From 510be94e3b0590ba73b2c56b13c30d5c7b6ed08b Mon Sep 17 00:00:00 2001 From: Serenibyss <10861407+serenibyss@users.noreply.github.com> Date: Sun, 17 Dec 2023 13:50:57 -0600 Subject: [PATCH 1/8] Port to MUI 2.4 (#2281) --- dependencies.gradle | 6 +- .../java/gregtech/api/cover/CoverWithUI.java | 14 +- .../gregtech/api/items/gui/ItemUIFactory.java | 9 +- .../api/metatileentity/MetaTileEntity.java | 13 +- .../java/gregtech/api/mui/GTGuiTextures.java | 30 ++-- .../java/gregtech/api/mui/GTGuiTheme.java | 72 ++++++--- src/main/java/gregtech/api/mui/GTGuis.java | 139 ++++++------------ .../api/mui/factory/CoverGuiFactory.java | 79 ++++++++++ .../api/mui/factory/MetaItemGuiFactory.java | 56 +++++++ .../mui/factory/MetaTileEntityGuiFactory.java | 63 ++++++++ .../mui/widget/GhostCircuitSlotWidget.java | 3 +- .../gregtech/common/covers/CoverStorage.java | 5 +- .../items/behaviors/IntCircuitBehaviour.java | 17 ++- .../multiblockpart/MetaTileEntityItemBus.java | 49 +++--- .../MetaTileEntitySteamItemBus.java | 5 +- .../storage/MetaTileEntityCrate.java | 5 +- src/main/java/gregtech/core/CoreModule.java | 2 + .../resources/assets/gregtech/lang/en_us.lang | 2 +- .../textures/gui/base/background_popup.png | Bin 0 -> 536 bytes 19 files changed, 373 insertions(+), 196 deletions(-) create mode 100644 src/main/java/gregtech/api/mui/factory/CoverGuiFactory.java create mode 100644 src/main/java/gregtech/api/mui/factory/MetaItemGuiFactory.java create mode 100644 src/main/java/gregtech/api/mui/factory/MetaTileEntityGuiFactory.java create mode 100644 src/main/resources/assets/gregtech/textures/gui/base/background_popup.png diff --git a/dependencies.gradle b/dependencies.gradle index db9bf2304c2..82ef07ce6a8 100644 --- a/dependencies.gradle +++ b/dependencies.gradle @@ -25,16 +25,14 @@ dependencies { // the CCL deobf jar uses very old MCP mappings, making it error at runtime in runClient/runServer // therefore we manually deobf the regular jar implementation rfg.deobf("curse.maven:codechicken-lib-1-8-242818:2779848") // CCL 3.2.3.358 - implementation "curse.maven:modularui-624243:4856895-deobf-4856896-sources-4856897" // MUI 2.3.1 + implementation("com.cleanroommc:modularui:2.4.1") { transitive = false } // Soft Dependencies // Can change any of these from compileOnlyApi -> implementation to test them in-game. implementation "CraftTweaker2:CraftTweaker2-MC1120-Main:1.12-4.1.20.684" implementation rfg.deobf("curse.maven:ctm-267602:2915363") // CTM 1.0.2.31 - implementation ("com.cleanroommc:groovyscript:0.7.1") { - transitive = false - } + implementation("com.cleanroommc:groovyscript:0.7.1") { transitive = false } implementation rfg.deobf("curse.maven:ae2-extended-life-570458:4402048") // AE2UEL 0.55.6 compileOnlyApi rfg.deobf("curse.maven:opencomputers-223008:4526246") // OpenComputers 1.8.0+9833087 diff --git a/src/main/java/gregtech/api/cover/CoverWithUI.java b/src/main/java/gregtech/api/cover/CoverWithUI.java index a504a7484d0..10ab6f243dd 100644 --- a/src/main/java/gregtech/api/cover/CoverWithUI.java +++ b/src/main/java/gregtech/api/cover/CoverWithUI.java @@ -3,8 +3,8 @@ import gregtech.api.gui.IUIHolder; import gregtech.api.gui.ModularUI; import gregtech.api.mui.GTGuiTheme; -import gregtech.api.mui.GTGuis; import gregtech.api.mui.GregTechGuiScreen; +import gregtech.api.mui.factory.CoverGuiFactory; import net.minecraft.entity.player.EntityPlayer; import net.minecraft.entity.player.EntityPlayerMP; @@ -12,13 +12,13 @@ import net.minecraftforge.fml.relauncher.SideOnly; import com.cleanroommc.modularui.api.IGuiHolder; -import com.cleanroommc.modularui.manager.GuiCreationContext; +import com.cleanroommc.modularui.factory.SidedPosGuiData; import com.cleanroommc.modularui.screen.ModularPanel; import com.cleanroommc.modularui.screen.ModularScreen; import com.cleanroommc.modularui.value.sync.GuiSyncManager; import org.jetbrains.annotations.ApiStatus; -public interface CoverWithUI extends Cover, IUIHolder, IGuiHolder { +public interface CoverWithUI extends Cover, IUIHolder, IGuiHolder { @ApiStatus.Experimental default boolean usesMui2() { @@ -27,8 +27,7 @@ default boolean usesMui2() { default void openUI(EntityPlayerMP player) { if (usesMui2()) { - GTGuis.getCoverUiInfo(getAttachedSide()) - .open(player, getCoverableView().getWorld(), getCoverableView().getPos()); + CoverGuiFactory.open(player, this); } else { CoverUIFactory.INSTANCE.openUI(this, player); } @@ -42,7 +41,7 @@ default ModularUI createUI(EntityPlayer player) { @ApiStatus.NonExtendable @SideOnly(Side.CLIENT) @Override - default ModularScreen createScreen(GuiCreationContext creationContext, ModularPanel mainPanel) { + default ModularScreen createScreen(SidedPosGuiData guiData, ModularPanel mainPanel) { return new GregTechGuiScreen(mainPanel, getUITheme()); } @@ -51,8 +50,7 @@ default GTGuiTheme getUITheme() { } @Override - default ModularPanel buildUI(GuiCreationContext guiCreationContext, GuiSyncManager guiSyncManager, - boolean isClient) { + default ModularPanel buildUI(SidedPosGuiData guiData, GuiSyncManager guiSyncManager) { return null; } diff --git a/src/main/java/gregtech/api/items/gui/ItemUIFactory.java b/src/main/java/gregtech/api/items/gui/ItemUIFactory.java index 998bca5dec7..abff0448370 100644 --- a/src/main/java/gregtech/api/items/gui/ItemUIFactory.java +++ b/src/main/java/gregtech/api/items/gui/ItemUIFactory.java @@ -10,13 +10,13 @@ import net.minecraftforge.fml.relauncher.SideOnly; import com.cleanroommc.modularui.api.IGuiHolder; -import com.cleanroommc.modularui.manager.GuiCreationContext; +import com.cleanroommc.modularui.factory.HandGuiData; import com.cleanroommc.modularui.screen.ModularPanel; import com.cleanroommc.modularui.screen.ModularScreen; import com.cleanroommc.modularui.value.sync.GuiSyncManager; import org.jetbrains.annotations.ApiStatus; -public interface ItemUIFactory extends IItemComponent, IGuiHolder { +public interface ItemUIFactory extends IItemComponent, IGuiHolder { /** * Creates new UI basing on given holder. Holder contains information @@ -30,7 +30,7 @@ default ModularUI createUI(PlayerInventoryHolder holder, EntityPlayer entityPlay @ApiStatus.NonExtendable @SideOnly(Side.CLIENT) @Override - default ModularScreen createScreen(GuiCreationContext creationContext, ModularPanel mainPanel) { + default ModularScreen createScreen(HandGuiData creationContext, ModularPanel mainPanel) { return new GregTechGuiScreen(mainPanel, getUITheme()); } @@ -39,8 +39,7 @@ default GTGuiTheme getUITheme() { } @Override - default ModularPanel buildUI(GuiCreationContext guiCreationContext, GuiSyncManager guiSyncManager, - boolean isClient) { + default ModularPanel buildUI(HandGuiData guiData, GuiSyncManager guiSyncManager) { return null; } } diff --git a/src/main/java/gregtech/api/metatileentity/MetaTileEntity.java b/src/main/java/gregtech/api/metatileentity/MetaTileEntity.java index aa223d66de7..659460902b0 100644 --- a/src/main/java/gregtech/api/metatileentity/MetaTileEntity.java +++ b/src/main/java/gregtech/api/metatileentity/MetaTileEntity.java @@ -16,8 +16,8 @@ import gregtech.api.metatileentity.interfaces.IGregTechTileEntity; import gregtech.api.metatileentity.interfaces.ISyncedTileEntity; import gregtech.api.mui.GTGuiTheme; -import gregtech.api.mui.GTGuis; import gregtech.api.mui.GregTechGuiScreen; +import gregtech.api.mui.factory.MetaTileEntityGuiFactory; import gregtech.api.recipes.RecipeMap; import gregtech.api.util.GTLog; import gregtech.api.util.GTTransferUtils; @@ -70,7 +70,7 @@ import codechicken.lib.vec.Cuboid6; import codechicken.lib.vec.Matrix4; import com.cleanroommc.modularui.api.IGuiHolder; -import com.cleanroommc.modularui.manager.GuiCreationContext; +import com.cleanroommc.modularui.factory.PosGuiData; import com.cleanroommc.modularui.screen.ModularPanel; import com.cleanroommc.modularui.screen.ModularScreen; import com.cleanroommc.modularui.value.sync.GuiSyncManager; @@ -90,7 +90,7 @@ import static gregtech.api.capability.GregtechDataCodes.*; -public abstract class MetaTileEntity implements ISyncedTileEntity, CoverHolder, IVoidable, IGuiHolder { +public abstract class MetaTileEntity implements ISyncedTileEntity, CoverHolder, IVoidable, IGuiHolder { public static final IndexedCuboid6 FULL_CUBE_COLLISION = new IndexedCuboid6(null, Cuboid6.full); @@ -437,7 +437,7 @@ public boolean usesMui2() { @SideOnly(Side.CLIENT) @Override - public final ModularScreen createScreen(GuiCreationContext creationContext, ModularPanel mainPanel) { + public final ModularScreen createScreen(PosGuiData posGuiData, ModularPanel mainPanel) { return new GregTechGuiScreen(mainPanel, getUITheme()); } @@ -446,8 +446,7 @@ public GTGuiTheme getUITheme() { } @Override - public ModularPanel buildUI(GuiCreationContext guiCreationContext, GuiSyncManager guiSyncManager, - boolean isClient) { + public ModularPanel buildUI(PosGuiData guiData, GuiSyncManager guiSyncManager) { return null; } @@ -469,7 +468,7 @@ public boolean onRightClick(EntityPlayer playerIn, EnumHand hand, EnumFacing fac if (!playerIn.isSneaking() && openGUIOnRightClick()) { if (getWorld() != null && !getWorld().isRemote) { if (usesMui2()) { - GTGuis.MTE.open(playerIn, getWorld(), getPos()); + MetaTileEntityGuiFactory.open(playerIn, this); } else { MetaTileEntityUIFactory.INSTANCE.openUI(getHolder(), (EntityPlayerMP) playerIn); } diff --git a/src/main/java/gregtech/api/mui/GTGuiTextures.java b/src/main/java/gregtech/api/mui/GTGuiTextures.java index 434c90e9ce3..d632bf3f8e6 100644 --- a/src/main/java/gregtech/api/mui/GTGuiTextures.java +++ b/src/main/java/gregtech/api/mui/GTGuiTextures.java @@ -52,7 +52,15 @@ public static class IDs { .location(GTValues.MODID, "textures/gui/base/background.png") .imageSize(176, 166) .adaptable(3) - .registerAsBackground(IDs.STANDARD_BACKGROUND, true) + .name(IDs.STANDARD_BACKGROUND) + .canApplyTheme() + .build(); + + public static final UITexture BACKGROUND_POPUP = UITexture.builder() + .location(GTValues.MODID, "textures/gui/base/background_popup.png") + .imageSize(195, 136) + .adaptable(4) + .canApplyTheme() .build(); // todo BORDERED/BOXED backgrounds will not be ported, if possible @@ -61,14 +69,14 @@ public static class IDs { .location(GTValues.MODID, "textures/gui/base/background_bronze.png") .imageSize(176, 166) .adaptable(3) - .registerAsBackground(IDs.BRONZE_BACKGROUND) + .name(IDs.BRONZE_BACKGROUND) .build(); public static final UITexture BACKGROUND_STEEL = UITexture.builder() .location(GTValues.MODID, "textures/gui/base/background_steel.png") .imageSize(176, 166) .adaptable(3) - .registerAsBackground(IDs.STEEL_BACKGROUND) + .name(IDs.STEEL_BACKGROUND) .build(); // todo move to textures/gui/base @@ -76,7 +84,7 @@ public static class IDs { .location(GTValues.MODID, "textures/gui/primitive/primitive_background.png") .imageSize(176, 166) .adaptable(3) - .registerAsBackground(IDs.PRIMITIVE_BACKGROUND) + .name(IDs.PRIMITIVE_BACKGROUND) .build(); // todo clipboard backgrounds, may deserve some redoing @@ -108,21 +116,22 @@ public static class IDs { .location(GTValues.MODID, "textures/gui/base/slot.png") .imageSize(18, 18) .adaptable(1) - .registerAsBackground(IDs.STANDARD_SLOT, true) + .name(IDs.STANDARD_SLOT) + .canApplyTheme() .build(); public static final UITexture SLOT_BRONZE = new UITexture.Builder() .location(GTValues.MODID, "textures/gui/base/slot_bronze.png") .imageSize(18, 18) .adaptable(1) - .registerAsBackground(IDs.BRONZE_SLOT) + .name(IDs.BRONZE_SLOT) .build(); public static final UITexture SLOT_STEEL = new UITexture.Builder() .location(GTValues.MODID, "textures/gui/base/slot_steel.png") .imageSize(18, 18) .adaptable(1) - .registerAsBackground(IDs.STEEL_SLOT) + .name(IDs.STEEL_SLOT) .build(); // todo move to textures/gui/base @@ -130,14 +139,15 @@ public static class IDs { .location(GTValues.MODID, "textures/gui/primitive/primitive_slot.png") .imageSize(18, 18) .adaptable(1) - .registerAsBackground(IDs.PRIMITIVE_SLOT) + .name(IDs.PRIMITIVE_SLOT) .build(); public static final UITexture FLUID_SLOT = new UITexture.Builder() .location(GTValues.MODID, "textures/gui/base/fluid_slot.png") .imageSize(18, 18) .adaptable(1) - .registerAsBackground(IDs.STANDARD_FLUID_SLOT, true) + .name(IDs.STANDARD_FLUID_SLOT) + .canApplyTheme() .build(); // todo bronze/steel/primitive fluid slots? @@ -253,7 +263,7 @@ public static class IDs { .location(GTValues.MODID, "textures/gui/widget/button.png") .imageSize(18, 18) .adaptable(1) - .registerAsIcon(IDs.STANDARD_BUTTON) + .name(IDs.STANDARD_BUTTON) .canApplyTheme() .build(); diff --git a/src/main/java/gregtech/api/mui/GTGuiTheme.java b/src/main/java/gregtech/api/mui/GTGuiTheme.java index c23754eea94..eb1c301aca2 100644 --- a/src/main/java/gregtech/api/mui/GTGuiTheme.java +++ b/src/main/java/gregtech/api/mui/GTGuiTheme.java @@ -6,6 +6,7 @@ import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import com.cleanroommc.modularui.api.IThemeApi; +import com.cleanroommc.modularui.screen.Tooltip; import com.cleanroommc.modularui.theme.ReloadThemeEvent; import com.cleanroommc.modularui.utils.JsonBuilder; @@ -17,27 +18,30 @@ public class GTGuiTheme { private static final List THEMES = new ArrayList<>(); - public static final GTGuiTheme STANDARD = new Builder("gregtech_standard") + public static final GTGuiTheme STANDARD = templateBuilder("gregtech_standard") .panel(GTGuiTextures.IDs.STANDARD_BACKGROUND) .itemSlot(GTGuiTextures.IDs.STANDARD_SLOT) .fluidSlot(GTGuiTextures.IDs.STANDARD_FLUID_SLOT) .color(ConfigHolder.client.defaultUIColor) + .button(GTGuiTextures.IDs.STANDARD_BUTTON) .toggleButton(GTGuiTextures.IDs.STANDARD_BUTTON, GTGuiTextures.IDs.STANDARD_SLOT, ConfigHolder.client.defaultUIColor) .build(); - public static final GTGuiTheme BRONZE = new Builder("gregtech_bronze") + // TODO Cover theme to utilize the GT5u-like button textures vs the standard ones + + public static final GTGuiTheme BRONZE = templateBuilder("gregtech_bronze") .panel(GTGuiTextures.IDs.BRONZE_BACKGROUND) .itemSlot(GTGuiTextures.IDs.BRONZE_SLOT) .build(); - public static final GTGuiTheme STEEL = new Builder("gregtech_steel") + public static final GTGuiTheme STEEL = templateBuilder("gregtech_steel") .panel(GTGuiTextures.IDs.STEEL_BACKGROUND) .itemSlot(GTGuiTextures.IDs.STEEL_SLOT) .build(); - public static final GTGuiTheme PRIMITIVE = new Builder("gregtech_primitive") + public static final GTGuiTheme PRIMITIVE = templateBuilder("gregtech_primitive") .panel(GTGuiTextures.IDs.PRIMITIVE_BACKGROUND) .itemSlot(GTGuiTextures.IDs.PRIMITIVE_SLOT) .build(); @@ -77,6 +81,14 @@ public static void onReloadThemes(ReloadThemeEvent.Pre event) { THEMES.forEach(GTGuiTheme::buildJson); } + public static Builder templateBuilder(String themeId) { + Builder builder = new Builder(themeId); + builder.openCloseAnimation(0); + builder.tooltipPos(Tooltip.Pos.NEXT_TO_MOUSE); + builder.smoothProgressBar(true); + return builder; + } + public static class Builder { private final GTGuiTheme theme; @@ -110,6 +122,28 @@ public Builder globalHoverBackground(String hoverBackgroundId) { return this; } + /** + * Set the window open/close animation speed. Overrides global cfg. + * + * @param rate the rate in frames to play the open/close animation over, or 0 for no animation + */ + public Builder openCloseAnimation(int rate) { + theme.elementBuilder.add(b -> b.add("openCloseAnimation", rate)); + return this; + } + + /** Set whether progress bars should animate smoothly. Overrides global cfg. */ + public Builder smoothProgressBar(boolean smoothBar) { + theme.elementBuilder.add(b -> b.add("smoothProgressBar", smoothBar)); + return this; + } + + /** Set the tooltip pos for this theme. Overrides global cfg. */ + public Builder tooltipPos(Tooltip.Pos tooltipPos) { + theme.elementBuilder.add(b -> b.add("tooltipPos", tooltipPos.name())); + return this; + } + /** Set a global UI coloration for this theme. */ public Builder color(int color) { theme.elementBuilder.add(b -> b.add("color", color)); @@ -130,8 +164,6 @@ public Builder textShadow() { /** * Set a custom panel (background texture) for UIs with this theme. - * This ID must correspond with a {@link com.cleanroommc.modularui.drawable.UITexture} that is - * registered using {@link com.cleanroommc.modularui.drawable.GuiTextures#registerBackground}! */ public Builder panel(String panelId) { theme.elementBuilder.add(b -> b @@ -144,28 +176,36 @@ public Builder panel(String panelId) { /** * Set a custom button texture for UIs with this theme. - * This ID must correspond with a {@link com.cleanroommc.modularui.drawable.UITexture} that is - * registered using {@link com.cleanroommc.modularui.drawable.GuiTextures#registerIcon}! */ public Builder button(String buttonId) { - return button(buttonId, 0xFFFFFFFF, false); + return button(buttonId, buttonId, 0xFFFFFFFF, false); + } + + /** + * Set a custom button texture for UIs with this theme. + * + * @param buttonId The ID of the button texture + * @param hoverId The ID of the button texture while hovering over the button with your mouse + */ + public Builder button(String buttonId, String hoverId) { + return button(buttonId, hoverId, 0xFFFFFFFF, false); } /** * Set a custom button texture for UIs with this theme. - * This ID must correspond with a {@link com.cleanroommc.modularui.drawable.UITexture} that is - * registered using {@link com.cleanroommc.modularui.drawable.GuiTextures#registerIcon}! * * @param buttonId The ID of the button texture + * @param hoverId The ID of the button texture while hovering over the button with your mouse * @param textColor The color of text overlaid on this button * @param textShadow If text overlaid on this button should have a text shadow */ - public Builder button(String buttonId, int textColor, boolean textShadow) { + public Builder button(String buttonId, String hoverId, int textColor, boolean textShadow) { theme.elementBuilder.add(b -> b .add("button", new JsonBuilder() .add("background", new JsonBuilder() .add("type", "texture") .add("id", buttonId)) + .add("hoverBackground", hoverId) .add("textColor", textColor) .add("textShadow", textShadow))); return this; @@ -173,8 +213,6 @@ public Builder button(String buttonId, int textColor, boolean textShadow) { /** * Set a custom item slot texture for UIs with this theme. - * This ID must correspond with a {@link com.cleanroommc.modularui.drawable.UITexture} that is - * registered using {@link com.cleanroommc.modularui.drawable.GuiTextures#registerIcon}! */ public Builder itemSlot(String itemSlotId) { return itemSlot(itemSlotId, 0x60FFFFFF); @@ -182,8 +220,6 @@ public Builder itemSlot(String itemSlotId) { /** * Set a custom item slot texture for UIs with this theme. - * This ID must correspond with a {@link com.cleanroommc.modularui.drawable.UITexture} that is - * registered using {@link com.cleanroommc.modularui.drawable.GuiTextures#registerIcon}! * * @param itemSlotId The ID of the item slot texture * @param hoverColor The color of the tooltip hover box for this widget @@ -200,8 +236,6 @@ public Builder itemSlot(String itemSlotId, int hoverColor) { /** * Set a custom fluid slot texture for UIs with this theme. - * This ID must correspond with a {@link com.cleanroommc.modularui.drawable.UITexture} that is - * registered using {@link com.cleanroommc.modularui.drawable.GuiTextures#registerIcon}! */ public Builder fluidSlot(String fluidSlotId) { return fluidSlot(fluidSlotId, 0x60FFFFFF); @@ -209,8 +243,6 @@ public Builder fluidSlot(String fluidSlotId) { /** * Set a custom fluid slot texture for UIs with this theme. - * This ID must correspond with a {@link com.cleanroommc.modularui.drawable.UITexture} that is - * registered using {@link com.cleanroommc.modularui.drawable.GuiTextures#registerIcon}! * * @param fluidSlotId The ID of the fluid slot texture * @param hoverColor The color of the tooltip hover box for this widget diff --git a/src/main/java/gregtech/api/mui/GTGuis.java b/src/main/java/gregtech/api/mui/GTGuis.java index 35893a3908e..d60b66088c7 100644 --- a/src/main/java/gregtech/api/mui/GTGuis.java +++ b/src/main/java/gregtech/api/mui/GTGuis.java @@ -1,77 +1,28 @@ package gregtech.api.mui; -import gregtech.api.capability.GregtechTileCapabilities; import gregtech.api.cover.Cover; -import gregtech.api.cover.CoverHolder; -import gregtech.api.cover.CoverWithUI; import gregtech.api.items.metaitem.MetaItem; import gregtech.api.metatileentity.MetaTileEntity; -import gregtech.api.util.GTUtility; +import gregtech.api.mui.factory.CoverGuiFactory; +import gregtech.api.mui.factory.MetaItemGuiFactory; +import gregtech.api.mui.factory.MetaTileEntityGuiFactory; import net.minecraft.item.ItemStack; -import net.minecraft.tileentity.TileEntity; -import net.minecraft.util.EnumFacing; -import net.minecraft.util.EnumHand; -import com.cleanroommc.modularui.api.IGuiHolder; -import com.cleanroommc.modularui.manager.GuiInfo; +import com.cleanroommc.modularui.factory.GuiManager; import com.cleanroommc.modularui.screen.ModularPanel; - -import java.util.EnumMap; +import com.cleanroommc.modularui.utils.Alignment; +import com.cleanroommc.modularui.widgets.ButtonWidget; +import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; public class GTGuis { - private static final EnumMap COVERS = new EnumMap<>(EnumFacing.class); - - public static final GuiInfo MTE = GuiInfo.builder() - .clientGui((context, mainPanel) -> { - MetaTileEntity mte = GTUtility.getMetaTileEntity(context.getWorld(), context.getBlockPos()); - if (mte != null) { - return mte.createScreen(context, mainPanel); - } - throw new UnsupportedOperationException(); - }) - .commonGui((context, syncHandler) -> { - MetaTileEntity mte = GTUtility.getMetaTileEntity(context.getWorld(), context.getBlockPos()); - if (mte != null) { - return mte.buildUI(context, syncHandler, context.getWorld().isRemote); - } - throw new UnsupportedOperationException(); - }) - .build(); - - public static final GuiInfo PLAYER_META_ITEM_MAIN_HAND = GuiInfo.builder() - .clientGui((context, mainPanel) -> { - ItemStack itemStack = context.getMainHandItem(); - return getGuiHolder(itemStack).createScreen(context.with(EnumHand.MAIN_HAND), mainPanel); - - }) - .commonGui((context, guiSyncHandler) -> { - ItemStack itemStack = context.getMainHandItem(); - return getGuiHolder(itemStack).buildUI(context.with(EnumHand.MAIN_HAND), guiSyncHandler, - context.getWorld().isRemote); - }) - .build(); - - public static final GuiInfo PLAYER_META_ITEM_OFF_HAND = GuiInfo.builder() - .clientGui((context, mainPanel) -> { - ItemStack itemStack = context.getOffHandItem(); - return getGuiHolder(itemStack).createScreen(context.with(EnumHand.OFF_HAND), mainPanel); - - }) - .commonGui((context, guiSyncHandler) -> { - ItemStack itemStack = context.getOffHandItem(); - return getGuiHolder(itemStack).buildUI(context.with(EnumHand.OFF_HAND), guiSyncHandler, - context.getWorld().isRemote); - }) - .build(); - - public static GuiInfo getMetaItemUiInfo(EnumHand hand) { - return hand == EnumHand.MAIN_HAND ? PLAYER_META_ITEM_MAIN_HAND : PLAYER_META_ITEM_OFF_HAND; - } - - public static GuiInfo getCoverUiInfo(EnumFacing facing) { - return COVERS.get(facing); + @ApiStatus.Internal + public static void registerFactories() { + GuiManager.registerFactory(MetaTileEntityGuiFactory.INSTANCE); + GuiManager.registerFactory(MetaItemGuiFactory.INSTANCE); + GuiManager.registerFactory(CoverGuiFactory.INSTANCE); } public static ModularPanel createPanel(String name, int width, int height) { @@ -92,44 +43,40 @@ public static ModularPanel createPanel(ItemStack stack, int width, int height) { return createPanel(valueItem.unlocalizedName, width, height); } - static { - for (EnumFacing facing : EnumFacing.values()) { - COVERS.put(facing, makeCoverUiInfo(facing)); - } + public static ModularPanel createPopupPanel(String name, int width, int height) { + return createPopupPanel(name, width, height, false, false); } - private static GuiInfo makeCoverUiInfo(EnumFacing facing) { - return GuiInfo.builder() - .clientGui((context, mainPanel) -> { - TileEntity te = context.getTileEntity(); - if (te == null) throw new IllegalStateException(); - CoverHolder coverHolder = te.getCapability(GregtechTileCapabilities.CAPABILITY_COVER_HOLDER, - facing); - if (coverHolder == null) throw new IllegalStateException(); - Cover cover = coverHolder.getCoverAtSide(facing); - if (!(cover instanceof CoverWithUI)) throw new IllegalStateException(); - return ((CoverWithUI) cover).createScreen(context, mainPanel); - }) - .commonGui((context, syncHandler) -> { - TileEntity te = context.getTileEntity(); - if (te == null) throw new IllegalStateException(); - CoverHolder coverHolder = te.getCapability(GregtechTileCapabilities.CAPABILITY_COVER_HOLDER, - facing); - if (coverHolder == null) throw new IllegalStateException(); - Cover cover = coverHolder.getCoverAtSide(facing); - if (!(cover instanceof CoverWithUI)) throw new IllegalStateException(); - return ((CoverWithUI) cover).buildUI(context, syncHandler, context.getWorld().isRemote); - }) - .build(); + public static ModularPanel createPopupPanel(String name, int width, int height, boolean disableBelow, + boolean closeOnOutsideClick) { + return new PopupPanel(name, width, height, disableBelow, closeOnOutsideClick); } - private static IGuiHolder getGuiHolder(ItemStack stack) { - if (stack.getItem() instanceof MetaItem) { - MetaItem.MetaValueItem valueItem = ((MetaItem) stack.getItem()).getItem(stack); - if (valueItem != null && valueItem.getUIManager() != null) { - return valueItem.getUIManager(); - } + private static class PopupPanel extends ModularPanel { + + private final boolean disableBelow; + private final boolean closeOnOutsideClick; + + public PopupPanel(@NotNull String name, int width, int height, boolean disableBelow, + boolean closeOnOutsideClick) { + super(name); + flex().startDefaultMode(); + flex().size(width, height).align(Alignment.Center); + flex().endDefaultMode(); + background(GTGuiTextures.BACKGROUND_POPUP); + child(ButtonWidget.panelCloseButton().top(5).right(5)); + this.disableBelow = disableBelow; + this.closeOnOutsideClick = closeOnOutsideClick; + } + + @Override + public boolean disablePanelsBelow() { + return disableBelow; + } + + @Override + public boolean closeOnOutOfBoundsClick() { + return closeOnOutsideClick; } - throw new IllegalStateException(); } } diff --git a/src/main/java/gregtech/api/mui/factory/CoverGuiFactory.java b/src/main/java/gregtech/api/mui/factory/CoverGuiFactory.java new file mode 100644 index 00000000000..918aad93833 --- /dev/null +++ b/src/main/java/gregtech/api/mui/factory/CoverGuiFactory.java @@ -0,0 +1,79 @@ +package gregtech.api.mui.factory; + +import gregtech.api.capability.GregtechTileCapabilities; +import gregtech.api.cover.Cover; +import gregtech.api.cover.CoverHolder; +import gregtech.api.cover.CoverWithUI; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.network.PacketBuffer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.EnumFacing; +import net.minecraft.util.math.BlockPos; + +import com.cleanroommc.modularui.api.IGuiHolder; +import com.cleanroommc.modularui.factory.AbstractUIFactory; +import com.cleanroommc.modularui.factory.GuiManager; +import com.cleanroommc.modularui.factory.SidedPosGuiData; +import org.jetbrains.annotations.NotNull; + +import java.util.Objects; + +public class CoverGuiFactory extends AbstractUIFactory { + + public static final CoverGuiFactory INSTANCE = new CoverGuiFactory(); + + private CoverGuiFactory() { + super("gregtech:cover"); + } + + public static > void open(EntityPlayer player, T cover) { + Objects.requireNonNull(player); + Objects.requireNonNull(cover); + if (!cover.getCoverableView().isValid()) { + throw new IllegalArgumentException("Can't open Cover GUI on invalid cover holder!"); + } + if (player.world != cover.getWorld()) { + throw new IllegalArgumentException("Cover must be in same dimension as the player!"); + } + BlockPos pos = cover.getPos(); + SidedPosGuiData data = new SidedPosGuiData(player, pos.getX(), pos.getY(), pos.getZ(), cover.getAttachedSide()); + GuiManager.open(INSTANCE, data, (EntityPlayerMP) player); + } + + @Override + public @NotNull IGuiHolder getGuiHolder(SidedPosGuiData data) { + TileEntity te = data.getTileEntity(); + if (te == null) { + throw new IllegalStateException("Could not get gui for null TileEntity!"); + } + CoverHolder coverHolder = te.getCapability(GregtechTileCapabilities.CAPABILITY_COVER_HOLDER, data.getSide()); + if (coverHolder == null) { + throw new IllegalStateException("Could not get CoverHolder for found TileEntity!"); + } + Cover cover = coverHolder.getCoverAtSide(data.getSide()); + if (cover == null) { + throw new IllegalStateException("Could not find cover at side " + data.getSide() + + " for found CoverHolder!"); + } + if (!(cover instanceof CoverWithUI coverWithUI)) { + throw new IllegalStateException("Cover at side " + data.getSide() + " is not a gui holder!"); + } + return coverWithUI; + } + + @Override + public void writeGuiData(SidedPosGuiData guiData, PacketBuffer buffer) { + buffer.writeVarInt(guiData.getX()); + buffer.writeVarInt(guiData.getY()); + buffer.writeVarInt(guiData.getZ()); + buffer.writeByte(guiData.getSide().getIndex()); + } + + @Override + public @NotNull SidedPosGuiData readGuiData(EntityPlayer player, PacketBuffer buffer) { + return new SidedPosGuiData(player, buffer.readVarInt(), buffer.readVarInt(), buffer.readVarInt(), + EnumFacing.VALUES[buffer.readByte()]); + } +} diff --git a/src/main/java/gregtech/api/mui/factory/MetaItemGuiFactory.java b/src/main/java/gregtech/api/mui/factory/MetaItemGuiFactory.java new file mode 100644 index 00000000000..7fea957a5a1 --- /dev/null +++ b/src/main/java/gregtech/api/mui/factory/MetaItemGuiFactory.java @@ -0,0 +1,56 @@ +package gregtech.api.mui.factory; + +import gregtech.api.items.metaitem.MetaItem; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.item.ItemStack; +import net.minecraft.network.PacketBuffer; +import net.minecraft.util.EnumHand; + +import com.cleanroommc.modularui.api.IGuiHolder; +import com.cleanroommc.modularui.factory.AbstractUIFactory; +import com.cleanroommc.modularui.factory.GuiManager; +import com.cleanroommc.modularui.factory.HandGuiData; +import org.jetbrains.annotations.NotNull; + +import java.util.Objects; + +public class MetaItemGuiFactory extends AbstractUIFactory { + + public static final MetaItemGuiFactory INSTANCE = new MetaItemGuiFactory(); + + private MetaItemGuiFactory() { + super("gregtech:meta_item"); + } + + public static void open(EntityPlayer player, EnumHand hand) { + Objects.requireNonNull(player); + Objects.requireNonNull(hand); + HandGuiData guiData = new HandGuiData(player, hand); + GuiManager.open(INSTANCE, guiData, (EntityPlayerMP) player); + } + + @Override + public @NotNull IGuiHolder getGuiHolder(HandGuiData data) { + ItemStack stack = data.getUsedItemStack(); + if (!(stack.getItem() instanceof MetaItemmetaItem)) { + throw new IllegalArgumentException("Found item is not a valid MetaItem!"); + } + MetaItem.MetaValueItem valueItem = metaItem.getItem(stack); + if (valueItem == null || valueItem.getUIManager() == null) { + throw new IllegalArgumentException("Found MetaItem is not a gui holder!"); + } + return valueItem.getUIManager(); + } + + @Override + public void writeGuiData(HandGuiData guiData, PacketBuffer buffer) { + buffer.writeByte(guiData.getHand().ordinal()); + } + + @Override + public @NotNull HandGuiData readGuiData(EntityPlayer player, PacketBuffer buffer) { + return new HandGuiData(player, EnumHand.values()[buffer.readByte()]); + } +} diff --git a/src/main/java/gregtech/api/mui/factory/MetaTileEntityGuiFactory.java b/src/main/java/gregtech/api/mui/factory/MetaTileEntityGuiFactory.java new file mode 100644 index 00000000000..0363476a987 --- /dev/null +++ b/src/main/java/gregtech/api/mui/factory/MetaTileEntityGuiFactory.java @@ -0,0 +1,63 @@ +package gregtech.api.mui.factory; + +import gregtech.api.metatileentity.MetaTileEntity; +import gregtech.api.metatileentity.interfaces.IGregTechTileEntity; + +import net.minecraft.entity.player.EntityPlayer; +import net.minecraft.entity.player.EntityPlayerMP; +import net.minecraft.network.PacketBuffer; +import net.minecraft.tileentity.TileEntity; +import net.minecraft.util.math.BlockPos; + +import com.cleanroommc.modularui.api.IGuiHolder; +import com.cleanroommc.modularui.factory.AbstractUIFactory; +import com.cleanroommc.modularui.factory.GuiManager; +import com.cleanroommc.modularui.factory.PosGuiData; +import org.jetbrains.annotations.NotNull; + +import java.util.Objects; + +public class MetaTileEntityGuiFactory extends AbstractUIFactory { + + public static final MetaTileEntityGuiFactory INSTANCE = new MetaTileEntityGuiFactory(); + + private MetaTileEntityGuiFactory() { + super("gregtech:mte"); + } + + public static > void open(EntityPlayer player, T mte) { + Objects.requireNonNull(player); + Objects.requireNonNull(mte); + if (!mte.isValid()) { + throw new IllegalArgumentException("Can't open invalid MetaTileEntity GUI!"); + } + if (player.world != mte.getWorld()) { + throw new IllegalArgumentException("MetaTileEntity must be in same dimension as the player!"); + } + BlockPos pos = mte.getPos(); + PosGuiData data = new PosGuiData(player, pos.getX(), pos.getY(), pos.getZ()); + GuiManager.open(INSTANCE, data, (EntityPlayerMP) player); + } + + @Override + public @NotNull IGuiHolder getGuiHolder(PosGuiData data) { + TileEntity te = data.getTileEntity(); + if (te instanceof IGregTechTileEntity gtte) { + MetaTileEntity mte = gtte.getMetaTileEntity(); + return Objects.requireNonNull(castGuiHolder(mte), "Found MetaTileEntity is not a gui holder!"); + } + throw new IllegalStateException("Found TileEntity is not a MetaTileEntity!"); + } + + @Override + public void writeGuiData(PosGuiData guiData, PacketBuffer buffer) { + buffer.writeVarInt(guiData.getX()); + buffer.writeVarInt(guiData.getY()); + buffer.writeVarInt(guiData.getZ()); + } + + @Override + public @NotNull PosGuiData readGuiData(EntityPlayer player, PacketBuffer buffer) { + return new PosGuiData(player, buffer.readVarInt(), buffer.readVarInt(), buffer.readVarInt()); + } +} diff --git a/src/main/java/gregtech/api/mui/widget/GhostCircuitSlotWidget.java b/src/main/java/gregtech/api/mui/widget/GhostCircuitSlotWidget.java index bab12d1013b..bd848099117 100644 --- a/src/main/java/gregtech/api/mui/widget/GhostCircuitSlotWidget.java +++ b/src/main/java/gregtech/api/mui/widget/GhostCircuitSlotWidget.java @@ -114,6 +114,7 @@ private void createSelectorPanel() { .size(18) .background(GTGuiTextures.SLOT, new ItemDrawable( IntCircuitIngredient.getIntegratedCircuit(index)).asIcon()) + .disableHoverBackground() .onMousePressed(mouseButton -> { getSyncHandler().syncToServer(SYNC_CIRCUIT_INDEX, buf -> buf.writeShort(index)); circuitPreview.setItem(IntCircuitIngredient.getIntegratedCircuit(index)); @@ -122,7 +123,7 @@ private void createSelectorPanel() { } } - getPanel().getScreen().openPanel(GTGuis.createPanel("circuit_selector", 176, 120) + getPanel().getScreen().openPanel(GTGuis.createPopupPanel("circuit_selector", 176, 120) .child(IKey.lang("metaitem.circuit.integrated.gui").asWidget().pos(5, 5)) .child(circuitPreview.asIcon().size(16).asWidget() .size(18) diff --git a/src/main/java/gregtech/common/covers/CoverStorage.java b/src/main/java/gregtech/common/covers/CoverStorage.java index a91caa74cb2..a63fe3cbd56 100644 --- a/src/main/java/gregtech/common/covers/CoverStorage.java +++ b/src/main/java/gregtech/common/covers/CoverStorage.java @@ -24,7 +24,7 @@ import codechicken.lib.vec.Matrix4; import com.cleanroommc.modularui.api.drawable.IKey; import com.cleanroommc.modularui.api.widget.IWidget; -import com.cleanroommc.modularui.manager.GuiCreationContext; +import com.cleanroommc.modularui.factory.SidedPosGuiData; import com.cleanroommc.modularui.screen.ModularPanel; import com.cleanroommc.modularui.value.sync.GuiSyncManager; import com.cleanroommc.modularui.value.sync.SyncHandlers; @@ -88,8 +88,7 @@ public boolean usesMui2() { } @Override - public ModularPanel buildUI(GuiCreationContext guiCreationContext, GuiSyncManager guiSyncManager, - boolean isClient) { + public ModularPanel buildUI(SidedPosGuiData guiData, GuiSyncManager guiSyncManager) { guiSyncManager.registerSlotGroup("item_inv", this.storageHandler.getSlots()); int rowSize = this.storageHandler.getSlots(); diff --git a/src/main/java/gregtech/common/items/behaviors/IntCircuitBehaviour.java b/src/main/java/gregtech/common/items/behaviors/IntCircuitBehaviour.java index 82a492eaa7b..2be3dcbc766 100644 --- a/src/main/java/gregtech/common/items/behaviors/IntCircuitBehaviour.java +++ b/src/main/java/gregtech/common/items/behaviors/IntCircuitBehaviour.java @@ -7,6 +7,7 @@ import gregtech.api.metatileentity.MetaTileEntity; import gregtech.api.mui.GTGuiTextures; import gregtech.api.mui.GTGuis; +import gregtech.api.mui.factory.MetaItemGuiFactory; import gregtech.api.recipes.ingredients.IntCircuitIngredient; import gregtech.api.util.GTUtility; @@ -21,7 +22,7 @@ import com.cleanroommc.modularui.api.drawable.IKey; import com.cleanroommc.modularui.api.widget.IWidget; import com.cleanroommc.modularui.drawable.ItemDrawable; -import com.cleanroommc.modularui.manager.GuiCreationContext; +import com.cleanroommc.modularui.factory.HandGuiData; import com.cleanroommc.modularui.screen.ModularPanel; import com.cleanroommc.modularui.value.sync.GuiSyncManager; import com.cleanroommc.modularui.value.sync.InteractionSyncHandler; @@ -57,23 +58,22 @@ public ActionResult onItemUse(EntityPlayer player, World world, Block public ActionResult onItemRightClick(World world, EntityPlayer player, EnumHand hand) { ItemStack heldItem = player.getHeldItem(hand); if (!world.isRemote) { - GTGuis.getMetaItemUiInfo(hand).open(player); + MetaItemGuiFactory.open(player, hand); } return ActionResult.newResult(EnumActionResult.SUCCESS, heldItem); } @Override - public ModularPanel buildUI(GuiCreationContext guiCreationContext, GuiSyncManager guiSyncManager, - boolean isClient) { - ItemDrawable circuitPreview = new ItemDrawable(guiCreationContext.getUsedItemStack()); + public ModularPanel buildUI(HandGuiData guiData, GuiSyncManager guiSyncManager) { + ItemDrawable circuitPreview = new ItemDrawable(guiData.getUsedItemStack()); for (int i = 0; i <= 32; i++) { int finalI = i; guiSyncManager.syncValue("config", i, new InteractionSyncHandler() .setOnMousePressed(b -> { ItemStack item = IntCircuitIngredient.getIntegratedCircuit(finalI); - item.setCount(guiCreationContext.getUsedItemStack().getCount()); + item.setCount(guiData.getUsedItemStack().getCount()); circuitPreview.setItem(item); - guiCreationContext.getPlayer().setHeldItem(guiCreationContext.getUsedHand(), item); + guiData.getPlayer().setHeldItem(guiData.getHand(), item); })); } @@ -87,10 +87,11 @@ public ModularPanel buildUI(GuiCreationContext guiCreationContext, GuiSyncManage .size(18) .background(GTGuiTextures.SLOT, new ItemDrawable(IntCircuitIngredient.getIntegratedCircuit(index)).asIcon().size(16)) + .disableHoverBackground() .syncHandler("config", index)); } } - return GTGuis.createPanel(guiCreationContext.getUsedItemStack(), 176, 120) + return GTGuis.createPanel(guiData.getUsedItemStack(), 176, 120) .child(IKey.lang("metaitem.circuit.integrated.gui").asWidget().pos(5, 5)) .child(circuitPreview.asIcon().size(16).asWidget() .size(18) diff --git a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/MetaTileEntityItemBus.java b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/MetaTileEntityItemBus.java index 2b5ffaddc4d..ce42375b680 100644 --- a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/MetaTileEntityItemBus.java +++ b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/MetaTileEntityItemBus.java @@ -37,7 +37,7 @@ import codechicken.lib.vec.Matrix4; import com.cleanroommc.modularui.api.drawable.IKey; import com.cleanroommc.modularui.api.widget.IWidget; -import com.cleanroommc.modularui.manager.GuiCreationContext; +import com.cleanroommc.modularui.factory.PosGuiData; import com.cleanroommc.modularui.screen.ModularPanel; import com.cleanroommc.modularui.value.BoolValue; import com.cleanroommc.modularui.value.sync.BooleanSyncValue; @@ -265,8 +265,7 @@ public boolean usesMui2() { } @Override - public ModularPanel buildUI(GuiCreationContext guiCreationContext, GuiSyncManager guiSyncManager, - boolean isClient) { + public ModularPanel buildUI(PosGuiData guiData, GuiSyncManager guiSyncManager) { int rowSize = (int) Math.sqrt(getInventorySize()); guiSyncManager.registerSlotGroup("item_inv", rowSize); @@ -294,28 +293,6 @@ public ModularPanel buildUI(GuiCreationContext guiCreationContext, GuiSyncManage boolean hasGhostCircuit = hasGhostCircuitInventory() && this.circuitInventory != null; - ToggleButton workingButton = new ToggleButton(); - workingButton.value( - new BoolValue.Dynamic(workingStateValue::getBoolValue, val -> { - workingStateValue.setBoolValue(val); - workingButton.markTooltipDirty(); - })) - .overlay(GTGuiTextures.BUTTON_ITEM_OUTPUT) - .tooltipBuilder(t -> t.addLine(workingStateValue.getBoolValue() ? - IKey.lang("gregtech.gui.item_auto_output.tooltip.enabled") : - IKey.lang("gregtech.gui.item_auto_output.tooltip.disabled"))); - - ToggleButton collapseButton = new ToggleButton(); - collapseButton.value( - new BoolValue.Dynamic(collapseStateValue::getBoolValue, val -> { - collapseStateValue.setBoolValue(val); - collapseButton.markTooltipDirty(); - })) - .overlay(GTGuiTextures.BUTTON_AUTO_COLLAPSE) - .tooltipBuilder(t -> t.addLine(collapseStateValue.getBoolValue() ? - IKey.lang("gregtech.gui.item_auto_collapse.tooltip.enabled") : - IKey.lang("gregtech.gui.item_auto_collapse.tooltip.disabled"))); - return GTGuis.createPanel(this, backgroundWidth, backgroundHeight) .child(IKey.lang(getMetaFullName()).asWidget().pos(5, 5)) .child(SlotGroupWidget.playerInventory().left(7).bottom(7)) @@ -329,8 +306,26 @@ public ModularPanel buildUI(GuiCreationContext guiCreationContext, GuiSyncManage .pos(backgroundWidth - 7 - 18, backgroundHeight - 18 * 4 - 7 - 5) .width(18).height(18 * 4 + 5) .child(GTGuiTextures.getLogo().asWidget().size(17).top(18 * 3 + 5)) - .child(workingButton.top(18 * 2)) - .child(collapseButton.top(18)) + .child(new ToggleButton() + .top(18 * 2) + .value(new BoolValue.Dynamic(workingStateValue::getBoolValue, + workingStateValue::setBoolValue)) + .overlay(GTGuiTextures.BUTTON_ITEM_OUTPUT) + .disableHoverBackground() + .tooltipBuilder(t -> t.setAutoUpdate(true) + .addLine(workingStateValue.getBoolValue() ? + IKey.lang("gregtech.gui.item_auto_output.tooltip.enabled") : + IKey.lang("gregtech.gui.item_auto_output.tooltip.disabled")))) + .child(new ToggleButton() + .top(18) + .value(new BoolValue.Dynamic(collapseStateValue::getBoolValue, + collapseStateValue::setBoolValue)) + .overlay(GTGuiTextures.BUTTON_AUTO_COLLAPSE) + .disableHoverBackground() + .tooltipBuilder(t -> t.setAutoUpdate(true) + .addLine(collapseStateValue.getBoolValue() ? + IKey.lang("gregtech.gui.item_auto_collapse.tooltip.enabled") : + IKey.lang("gregtech.gui.item_auto_collapse.tooltip.disabled")))) .childIf(hasGhostCircuit, new GhostCircuitSlotWidget() .slot(SyncHandlers.itemSlot(circuitInventory, 0)) .background(GTGuiTextures.SLOT, GTGuiTextures.INT_CIRCUIT_OVERLAY)) diff --git a/src/main/java/gregtech/common/metatileentities/steam/multiblockpart/MetaTileEntitySteamItemBus.java b/src/main/java/gregtech/common/metatileentities/steam/multiblockpart/MetaTileEntitySteamItemBus.java index acc41bc21c1..97f855406e2 100644 --- a/src/main/java/gregtech/common/metatileentities/steam/multiblockpart/MetaTileEntitySteamItemBus.java +++ b/src/main/java/gregtech/common/metatileentities/steam/multiblockpart/MetaTileEntitySteamItemBus.java @@ -24,7 +24,7 @@ import codechicken.lib.vec.Matrix4; import com.cleanroommc.modularui.api.drawable.IKey; import com.cleanroommc.modularui.api.widget.IWidget; -import com.cleanroommc.modularui.manager.GuiCreationContext; +import com.cleanroommc.modularui.factory.PosGuiData; import com.cleanroommc.modularui.screen.ModularPanel; import com.cleanroommc.modularui.value.sync.GuiSyncManager; import com.cleanroommc.modularui.value.sync.SyncHandlers; @@ -86,8 +86,7 @@ public void renderMetaTileEntity(CCRenderState renderState, Matrix4 translation, } @Override - public ModularPanel buildUI(GuiCreationContext guiCreationContext, GuiSyncManager guiSyncManager, - boolean isClient) { + public ModularPanel buildUI(PosGuiData guiData, GuiSyncManager guiSyncManager) { guiSyncManager.registerSlotGroup("item_inv", 2); List> widgets = new ArrayList<>(); diff --git a/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityCrate.java b/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityCrate.java index a3680aadfd1..44859246953 100644 --- a/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityCrate.java +++ b/src/main/java/gregtech/common/metatileentities/storage/MetaTileEntityCrate.java @@ -33,7 +33,7 @@ import codechicken.lib.vec.Matrix4; import com.cleanroommc.modularui.api.drawable.IKey; import com.cleanroommc.modularui.api.widget.IWidget; -import com.cleanroommc.modularui.manager.GuiCreationContext; +import com.cleanroommc.modularui.factory.PosGuiData; import com.cleanroommc.modularui.screen.ModularPanel; import com.cleanroommc.modularui.value.sync.GuiSyncManager; import com.cleanroommc.modularui.value.sync.SyncHandlers; @@ -146,8 +146,7 @@ public boolean usesMui2() { } @Override - public ModularPanel buildUI(GuiCreationContext guiCreationContext, GuiSyncManager guiSyncManager, - boolean isClient) { + public ModularPanel buildUI(PosGuiData guiData, GuiSyncManager guiSyncManager) { guiSyncManager.registerSlotGroup("item_inv", rowSize); int rows = inventorySize / rowSize; diff --git a/src/main/java/gregtech/core/CoreModule.java b/src/main/java/gregtech/core/CoreModule.java index 56c1196049e..1d2dc88a4ec 100644 --- a/src/main/java/gregtech/core/CoreModule.java +++ b/src/main/java/gregtech/core/CoreModule.java @@ -15,6 +15,7 @@ import gregtech.api.modules.IGregTechModule; import gregtech.api.mui.GTGuiTextures; import gregtech.api.mui.GTGuiTheme; +import gregtech.api.mui.GTGuis; import gregtech.api.recipes.ModHandler; import gregtech.api.recipes.RecipeMap; import gregtech.api.recipes.recipeproperties.TemperatureProperty; @@ -131,6 +132,7 @@ public void preInit(FMLPreInitializationEvent event) { GTSoundEvents.register(); /* MUI Initialization */ + GTGuis.registerFactories(); GTGuiTextures.init(); GTGuiTheme.registerThemes(); diff --git a/src/main/resources/assets/gregtech/lang/en_us.lang b/src/main/resources/assets/gregtech/lang/en_us.lang index 5ab44b85d32..b70165a7af4 100644 --- a/src/main/resources/assets/gregtech/lang/en_us.lang +++ b/src/main/resources/assets/gregtech/lang/en_us.lang @@ -531,7 +531,7 @@ metaitem.tool.datamodule.name=Data Module metaitem.tool.datamodule.tooltip=Storage for Incredibly Complex Data/n§cCan only be read by a Data Bank metaitem.circuit.integrated.name=Programmed Circuit metaitem.circuit.integrated.tooltip=Use to open configuration GUI/n/nShift-Right-Click on a machine/nwith a circuit slot to set it to/nthis circuit's value./n -metaitem.circuit.integrated.gui=Programmed Circuit Configuration +metaitem.circuit.integrated.gui=Circuit Configuration metaitem.circuit.integrated.jei_description=JEI is only showing recipes for the given configuration.\n\nYou can select a configuration in the Programmed Circuit configuration tab. item.glass.lens=Glass Lens (White) diff --git a/src/main/resources/assets/gregtech/textures/gui/base/background_popup.png b/src/main/resources/assets/gregtech/textures/gui/base/background_popup.png new file mode 100644 index 0000000000000000000000000000000000000000..f77849e8f7b08a50479030c9b5b5c28975f01da8 GIT binary patch literal 536 zcmeAS@N?(olHy`uVBq!ia0vp^hk>|*gAGVVJ&0!oQjEnx?oJHr&dIz4a#+$GeH|GX zHuiJ>Nd!r97I;J!GcfQ0b@3f$Jf6QI1t=&{;u=vBoS#-wo>-L1P>`6JSE84fTB2a0 zXQ*eI;vNCChOyJr#WAEJ?(OA+yv+s-ERM65q~7u>*fY_=leNNcR{z`O<-6aoa{sz{ zI_GHbetY2=uW#h+l|5d_z3B1ILeAAUzW+@wDd>K9Ke@ul(BTM!AhQdPz$gP-AQb#+ zE9gyp^IRy*NNR@WnZLCx{^tMw`8?S7o^{QWJKOd$_S}18X8EHL62JYD@<);T3K F0RT|Kk?Q~e literal 0 HcmV?d00001 From 5e73960b6814ed400fb975a2b86e4b169561d2b6 Mon Sep 17 00:00:00 2001 From: serenibyss <10861407+serenibyss@users.noreply.github.com> Date: Sun, 17 Dec 2023 17:20:01 -0600 Subject: [PATCH 2/8] UI theme cleanups --- .../java/gregtech/api/mui/GTGuiTextures.java | 7 +- .../java/gregtech/api/mui/GTGuiTheme.java | 110 +++++++++++++++--- .../multiblockpart/MetaTileEntityItemBus.java | 4 +- 3 files changed, 98 insertions(+), 23 deletions(-) diff --git a/src/main/java/gregtech/api/mui/GTGuiTextures.java b/src/main/java/gregtech/api/mui/GTGuiTextures.java index d632bf3f8e6..d1f432c6c07 100644 --- a/src/main/java/gregtech/api/mui/GTGuiTextures.java +++ b/src/main/java/gregtech/api/mui/GTGuiTextures.java @@ -4,6 +4,7 @@ import com.cleanroommc.modularui.drawable.UITexture; import org.jetbrains.annotations.ApiStatus; +import org.jetbrains.annotations.NotNull; /** * GT MUI textures.
@@ -454,7 +455,11 @@ private static UITexture progressBar(String path, int width, int height, boolean } // todo steam logos? multi indicator blinking logos? - public static UITexture getLogo() { + public static @NotNull UITexture getLogo(GTGuiTheme theme) { + if (theme != null) { + UITexture logo = theme.getLogo(); + if (logo != null) return logo; + } return GTValues.XMAS.get() ? GREGTECH_LOGO_XMAS : GREGTECH_LOGO; } } diff --git a/src/main/java/gregtech/api/mui/GTGuiTheme.java b/src/main/java/gregtech/api/mui/GTGuiTheme.java index eb1c301aca2..c3f80b09943 100644 --- a/src/main/java/gregtech/api/mui/GTGuiTheme.java +++ b/src/main/java/gregtech/api/mui/GTGuiTheme.java @@ -5,14 +5,18 @@ import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import com.cleanroommc.modularui.api.ITheme; import com.cleanroommc.modularui.api.IThemeApi; +import com.cleanroommc.modularui.drawable.UITexture; import com.cleanroommc.modularui.screen.Tooltip; import com.cleanroommc.modularui.theme.ReloadThemeEvent; import com.cleanroommc.modularui.utils.JsonBuilder; +import org.jetbrains.annotations.Nullable; import java.util.ArrayList; import java.util.List; import java.util.function.Consumer; +import java.util.function.Supplier; public class GTGuiTheme { @@ -24,7 +28,7 @@ public class GTGuiTheme { .fluidSlot(GTGuiTextures.IDs.STANDARD_FLUID_SLOT) .color(ConfigHolder.client.defaultUIColor) .button(GTGuiTextures.IDs.STANDARD_BUTTON) - .toggleButton(GTGuiTextures.IDs.STANDARD_BUTTON, + .simpleToggleButton(GTGuiTextures.IDs.STANDARD_BUTTON, GTGuiTextures.IDs.STANDARD_SLOT, ConfigHolder.client.defaultUIColor) .build(); @@ -51,6 +55,8 @@ public class GTGuiTheme { private final List> elementBuilder; private final JsonBuilder jsonBuilder; + private Supplier logo; + private GTGuiTheme(String themeId) { this.themeId = themeId; this.jsonBuilder = new JsonBuilder(); @@ -62,6 +68,15 @@ public String getId() { return themeId; } + public ITheme getMuiTheme() { + return IThemeApi.get().getTheme(themeId); + } + + public @Nullable UITexture getLogo() { + if (logo == null) return null; + return logo.get(); + } + private void register() { buildJson(); IThemeApi.get().registerTheme(themeId, jsonBuilder); @@ -278,33 +293,90 @@ public Builder textField(int textColor, int markedColor) { return this; } - public Builder toggleButton(String toggleButtonId, String selectedBackgroundId) { - return toggleButton(toggleButtonId, selectedBackgroundId, 0xFFFFFFFF, true); - } - - public Builder toggleButton(String toggleButtonId, String selectedBackgroundId, int selectedColor) { - return toggleButton(toggleButtonId, selectedBackgroundId, 0xFFFFFFFF, true, null, selectedColor); - } - - public Builder toggleButton(String toggleButtonId, String selectedBackgroundId, int textColor, - boolean textShadow) { - return toggleButton(toggleButtonId, selectedBackgroundId, textColor, textShadow, null, 0xFFBBBBBB); + /** + * Set the theme options for a ToggleButton widget. + * + * @param backgroundId The main background for the unpressed button + * @param hoverBackgroundId The on-hover background for the unpressed button + * @param selectedBackgroundId The main background for the pressed button + * @param selectedHoverBackgroundId The on-hover background for the pressed button + * @param selectedColor The color to apply to the pressed button + */ + public Builder toggleButton(String backgroundId, String hoverBackgroundId, + String selectedBackgroundId, String selectedHoverBackgroundId, int selectedColor) { + return toggleButton( + backgroundId, hoverBackgroundId, + selectedBackgroundId, selectedHoverBackgroundId, + selectedColor, 0xFFBBBBBB, false); } - public Builder toggleButton(String toggleButtonId, String selectedBackgroundId, int textColor, - boolean textShadow, String selectedHoverBackgroundId, int selectedColor) { + /** + * Set the theme options for a ToggleButton widget. + * + * @param backgroundId The main background for the unpressed button + * @param hoverBackgroundId The on-hover background for the unpressed button + * @param selectedBackgroundId The main background for the pressed button + * @param selectedHoverBackgroundId The on-hover background for the pressed button + * @param selectedColor The color to apply to the pressed button + * @param textColor The color for text overlaid on this button + * @param textShadow Whether to apply text shadow to text overlaid on this button + */ + public Builder toggleButton(String backgroundId, String hoverBackgroundId, + String selectedBackgroundId, String selectedHoverBackgroundId, + int selectedColor, int textColor, boolean textShadow) { theme.elementBuilder.add(b -> b .add("toggleButton", new JsonBuilder() .add("background", new JsonBuilder() .add("type", "texture") - .add("id", toggleButtonId)) - .add("textColor", textColor) - .add("textShadow", textShadow) + .add("id", backgroundId)) + .add("hoverBackground", new JsonBuilder() + .add("type", "texture") + .add("id", hoverBackgroundId)) .add("selectedBackground", new JsonBuilder() .add("type", "texture") .add("id", selectedBackgroundId)) - .add("selectedHoverBackground", selectedHoverBackgroundId) - .add("selectedColor", selectedColor))); + .add("selectedHoverBackground", new JsonBuilder() + .add("type", "texture") + .add("id", selectedHoverBackgroundId)) + .add("selectedColor", selectedColor) + .add("textColor", textColor) + .add("textShadow", textShadow))); + return this; + } + + /** + * Simple toggle button configuration for when you want a button with no texture changes on hover. + * + * @param backgroundId The unselected background texture + * @param selectedBackgroundId The selected background texture + * @param selectedColor The background color when the button is selected + */ + public Builder simpleToggleButton(String backgroundId, String selectedBackgroundId, int selectedColor) { + return simpleToggleButton(backgroundId, selectedBackgroundId, selectedColor, 0xFFBBBBBB, false); + } + + /** + * Simple toggle button configuration for when you want a button with no texture changes on hover. + * + * @param backgroundId The unselected background texture + * @param selectedBackgroundId The selected background texture + * @param selectedColor The background color when the button is selected + * @param textColor The color for text overlaid on this button + * @param textShadow Whether to apply text shadow to text overlaid on this button + */ + public Builder simpleToggleButton(String backgroundId, String selectedBackgroundId, int selectedColor, + int textColor, boolean textShadow) { + return toggleButton( + backgroundId, backgroundId, + selectedBackgroundId, selectedBackgroundId, + selectedColor, textColor, textShadow); + } + + /** + * Set a logo supplier for this theme. + */ + public Builder logo(Supplier logo) { + theme.logo = logo; return this; } diff --git a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/MetaTileEntityItemBus.java b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/MetaTileEntityItemBus.java index ce42375b680..949f47b77ca 100644 --- a/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/MetaTileEntityItemBus.java +++ b/src/main/java/gregtech/common/metatileentities/multi/multiblockpart/MetaTileEntityItemBus.java @@ -305,13 +305,12 @@ public ModularPanel buildUI(PosGuiData guiData, GuiSyncManager guiSyncManager) { .child(new Column() .pos(backgroundWidth - 7 - 18, backgroundHeight - 18 * 4 - 7 - 5) .width(18).height(18 * 4 + 5) - .child(GTGuiTextures.getLogo().asWidget().size(17).top(18 * 3 + 5)) + .child(GTGuiTextures.getLogo(getUITheme()).asWidget().size(17).top(18 * 3 + 5)) .child(new ToggleButton() .top(18 * 2) .value(new BoolValue.Dynamic(workingStateValue::getBoolValue, workingStateValue::setBoolValue)) .overlay(GTGuiTextures.BUTTON_ITEM_OUTPUT) - .disableHoverBackground() .tooltipBuilder(t -> t.setAutoUpdate(true) .addLine(workingStateValue.getBoolValue() ? IKey.lang("gregtech.gui.item_auto_output.tooltip.enabled") : @@ -321,7 +320,6 @@ public ModularPanel buildUI(PosGuiData guiData, GuiSyncManager guiSyncManager) { .value(new BoolValue.Dynamic(collapseStateValue::getBoolValue, collapseStateValue::setBoolValue)) .overlay(GTGuiTextures.BUTTON_AUTO_COLLAPSE) - .disableHoverBackground() .tooltipBuilder(t -> t.setAutoUpdate(true) .addLine(collapseStateValue.getBoolValue() ? IKey.lang("gregtech.gui.item_auto_collapse.tooltip.enabled") : From d87677651d874d224ebddfbda5c2e8cc0fc14c31 Mon Sep 17 00:00:00 2001 From: Tictim Date: Mon, 18 Dec 2023 09:42:38 +0900 Subject: [PATCH 3/8] Ore Dictionary Filter Update (#2296) --- src/main/java/gregtech/GregTechMod.java | 15 +- .../java/gregtech/api/gui/GuiTextures.java | 4 + .../gregtech/api/util/oreglob/OreGlob.java | 127 ++++++++++++--- .../api/util/oreglob/OreGlobCompiler.java | 10 ++ .../filter/OreDictionaryItemFilter.java | 146 ++++++++++++++---- .../filter/oreglob/impl/OreGlobMessages.java | 13 ++ .../filter/oreglob/impl/OreGlobParser.java | 44 +++--- .../widget/orefilter/OreFilterTestSlot.java | 63 ++++---- src/main/java/gregtech/core/CoreModule.java | 4 + .../resources/assets/gregtech/lang/en_us.lang | 6 +- .../ore_filter/button_case_sensitive.png | Bin 0 -> 339 bytes .../widget/ore_filter/button_match_all.png | Bin 0 -> 386 bytes .../java/gregtech/api/util/OreGlobTest.java | 17 +- 13 files changed, 322 insertions(+), 127 deletions(-) create mode 100644 src/main/java/gregtech/api/util/oreglob/OreGlobCompiler.java create mode 100644 src/main/resources/assets/gregtech/textures/gui/widget/ore_filter/button_case_sensitive.png create mode 100644 src/main/resources/assets/gregtech/textures/gui/widget/ore_filter/button_match_all.png diff --git a/src/main/java/gregtech/GregTechMod.java b/src/main/java/gregtech/GregTechMod.java index aa770c26ed6..f76989a97d5 100644 --- a/src/main/java/gregtech/GregTechMod.java +++ b/src/main/java/gregtech/GregTechMod.java @@ -3,9 +3,7 @@ import gregtech.api.GTValues; import gregtech.api.GregTechAPI; import gregtech.api.modules.ModuleContainerRegistryEvent; -import gregtech.api.util.oreglob.OreGlob; import gregtech.client.utils.BloomEffectUtil; -import gregtech.common.covers.filter.oreglob.impl.OreGlobParser; import gregtech.modules.GregTechModules; import gregtech.modules.ModuleManager; @@ -15,7 +13,17 @@ import net.minecraftforge.fml.common.Loader; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod.EventHandler; -import net.minecraftforge.fml.common.event.*; +import net.minecraftforge.fml.common.event.FMLConstructionEvent; +import net.minecraftforge.fml.common.event.FMLInitializationEvent; +import net.minecraftforge.fml.common.event.FMLInterModComms; +import net.minecraftforge.fml.common.event.FMLLoadCompleteEvent; +import net.minecraftforge.fml.common.event.FMLPostInitializationEvent; +import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; +import net.minecraftforge.fml.common.event.FMLServerAboutToStartEvent; +import net.minecraftforge.fml.common.event.FMLServerStartedEvent; +import net.minecraftforge.fml.common.event.FMLServerStartingEvent; +import net.minecraftforge.fml.common.event.FMLServerStoppedEvent; +import net.minecraftforge.fml.common.event.FMLServerStoppingEvent; @Mod(modid = GTValues.MODID, name = "GregTech", @@ -44,7 +52,6 @@ public GregTechMod() { public void onConstruction(FMLConstructionEvent event) { moduleManager = ModuleManager.getInstance(); GregTechAPI.moduleManager = moduleManager; - OreGlob.setCompiler(input -> new OreGlobParser(input).compile()); moduleManager.registerContainer(new GregTechModules()); MinecraftForge.EVENT_BUS.post(new ModuleContainerRegistryEvent()); moduleManager.setup(event.getASMHarvestedData(), Loader.instance().getConfigDir()); diff --git a/src/main/java/gregtech/api/gui/GuiTextures.java b/src/main/java/gregtech/api/gui/GuiTextures.java index fb073716142..e85bffcfe97 100644 --- a/src/main/java/gregtech/api/gui/GuiTextures.java +++ b/src/main/java/gregtech/api/gui/GuiTextures.java @@ -435,6 +435,10 @@ public class GuiTextures { .fullImage("textures/items/metaitems/cover.controller.png"); // Ore Filter + public static final TextureArea ORE_FILTER_BUTTON_CASE_SENSITIVE = TextureArea + .fullImage("textures/gui/widget/ore_filter/button_case_sensitive.png"); + public static final TextureArea ORE_FILTER_BUTTON_MATCH_ALL = TextureArea + .fullImage("textures/gui/widget/ore_filter/button_match_all.png"); public static final TextureArea ORE_FILTER_INFO = TextureArea.fullImage("textures/gui/widget/ore_filter/info.png"); public static final TextureArea ORE_FILTER_SUCCESS = TextureArea .fullImage("textures/gui/widget/ore_filter/success.png"); diff --git a/src/main/java/gregtech/api/util/oreglob/OreGlob.java b/src/main/java/gregtech/api/util/oreglob/OreGlob.java index 072e4959eeb..a560fcae1bf 100644 --- a/src/main/java/gregtech/api/util/oreglob/OreGlob.java +++ b/src/main/java/gregtech/api/util/oreglob/OreGlob.java @@ -7,21 +7,19 @@ import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; +import java.util.Collection; import java.util.List; -import java.util.Set; -import java.util.function.Function; /** * Glob-like string matcher language designed for ore dictionary matching. *

- * An OreGlob instance provides two functions: the ability to match strings, - * and the ability to translate expression structure into user-friendly text - * explanations. The text can be either a plaintext, or a text formatted by standard + * An OreGlob instance provides two functions: the ability to match strings, and the ability to translate expression + * structure into user-friendly text explanations. The text can be either a plaintext, or a text formatted by standard * Minecraft text format. */ public abstract class OreGlob { - private static Function compiler; + private static OreGlobCompiler compiler; /** * Tries to compile the string expression into OreGlob instance. @@ -29,15 +27,31 @@ public abstract class OreGlob { * @param expression OreGlob expression * @return Compilation result * @throws IllegalStateException If compiler is not provided yet + * @deprecated use {@link #compile(String, boolean)} */ @NotNull + @Deprecated + @ApiStatus.ScheduledForRemoval(inVersion = "2.9") public static OreGlobCompileResult compile(@NotNull String expression) { + return compile(expression, true); + } + + /** + * Tries to compile the string expression into OreGlob instance. + * + * @param expression OreGlob expression + * @param ignoreCase Whether the resulting OreGlob instance should do case-insensitive matches + * @return Compilation result + * @throws IllegalStateException If compiler is not provided yet + */ + @NotNull + public static OreGlobCompileResult compile(@NotNull String expression, boolean ignoreCase) { if (compiler == null) throw new IllegalStateException("Compiler unavailable"); - return compiler.apply(expression); + return compiler.compile(expression, ignoreCase); } @ApiStatus.Internal - public static void setCompiler(@NotNull Function compiler) { + public static void setCompiler(@NotNull OreGlobCompiler compiler) { OreGlob.compiler = compiler; } @@ -60,30 +74,97 @@ public static void setCompiler(@NotNull Function c public abstract boolean matches(@NotNull String input); /** - * Tries to match each ore dictionary entries associated with given item. - * If any of them matches, {@code true} is returned. *

- * For items not associated with any ore dictionary entries, this method returns - * {@code true} if this instance matches empty string instead. + * Tries to match each ore dictionary entries associated with given item. If any of them matches, {@code true} is + * returned. + *

+ *

+ * For items not associated with any ore dictionary entries, this method returns {@code true} if this instance + * matches empty string instead. + *

* * @param stack Item input * @return Whether this instance matches the input + * @deprecated use {@link #matchesAll(ItemStack)} or {@link #matchesAny(ItemStack)} */ + @Deprecated + @ApiStatus.ScheduledForRemoval(inVersion = "2.9") public final boolean matches(@NotNull ItemStack stack) { - Set oreDicts = OreDictUnifier.getOreDictionaryNames(stack); - if (oreDicts.isEmpty()) { - return matches(""); - } else { - for (String oreDict : oreDicts) { - if (matches(oreDict)) return true; - } - return false; - } + return matchesAny(stack); + } + + /** + *

+ * Tries to match each ore dictionary entries associated with given item. If any of them matches, {@code true} is + * returned. + *

+ *

+ * For items not associated with any ore dictionary entries, this method returns {@code true} if this instance + * matches empty string instead. + *

+ * + * @param stack Item input + * @return Whether this instance matches the input + */ + public final boolean matchesAny(@NotNull ItemStack stack) { + return matchesAny(OreDictUnifier.getOreDictionaryNames(stack), true); + } + + /** + *

+ * Tries to match each ore dictionary entries associated with given item. If all of them matches, {@code true} is + * returned. + *

+ *

+ * For items not associated with any ore dictionary entries, this method returns {@code true} if this instance + * matches empty string instead. + *

+ * + * @param stack Item input + * @return Whether this instance matches the input + */ + public final boolean matchesAll(@NotNull ItemStack stack) { + return matchesAll(OreDictUnifier.getOreDictionaryNames(stack), true); + } + + /** + *

+ * Tries to match each input. If any of them matches, {@code true} is returned. + *

+ * + * @param inputs Collection of input strings + * @param specialEmptyMatch If {@code true}, this method will match an empty string ({@code ""}) if the input + * collection is empty. If {@code true}, this method will return {@code false} in such + * scenario. + * @return Whether this instance matches the input + */ + public final boolean matchesAny(@NotNull Collection inputs, boolean specialEmptyMatch) { + if (specialEmptyMatch && inputs.isEmpty()) return matches(""); + for (String input : inputs) if (matches(input)) return true; + return false; + } + + /** + *

+ * Tries to match each input. If all of them matches, {@code true} is returned. Note that this method does not have + * special case for empty inputs. + *

+ * + * @param inputs Collection of input strings + * @param specialEmptyMatch If {@code true}, this method will match an empty string ({@code ""}) if the input + * collection is empty. If {@code true}, this method will return {@code true} in such + * scenario. + * @return Whether this instance matches the input + */ + public final boolean matchesAll(@NotNull Collection inputs, boolean specialEmptyMatch) { + if (specialEmptyMatch && inputs.isEmpty()) return matches(""); + for (String input : inputs) if (!matches(input)) return false; + return true; } /** - * Visualize this instance with standard Minecraft text formatting. Two spaces (' ') will - * be used as indentation. + * Visualize this instance with standard Minecraft text formatting. Two spaces ({@code ' '}) will be used as + * indentation. * * @return Formatted visualization * @see OreGlob#toFormattedString(String) diff --git a/src/main/java/gregtech/api/util/oreglob/OreGlobCompiler.java b/src/main/java/gregtech/api/util/oreglob/OreGlobCompiler.java new file mode 100644 index 00000000000..d66fb7785a0 --- /dev/null +++ b/src/main/java/gregtech/api/util/oreglob/OreGlobCompiler.java @@ -0,0 +1,10 @@ +package gregtech.api.util.oreglob; + +import org.jetbrains.annotations.NotNull; + +@FunctionalInterface +public interface OreGlobCompiler { + + @NotNull + OreGlobCompileResult compile(@NotNull String expression, boolean ignoreCase); +} diff --git a/src/main/java/gregtech/common/covers/filter/OreDictionaryItemFilter.java b/src/main/java/gregtech/common/covers/filter/OreDictionaryItemFilter.java index 95cc2f172e0..1db9a6087e3 100644 --- a/src/main/java/gregtech/common/covers/filter/OreDictionaryItemFilter.java +++ b/src/main/java/gregtech/common/covers/filter/OreDictionaryItemFilter.java @@ -2,12 +2,15 @@ import gregtech.api.gui.GuiTextures; import gregtech.api.gui.Widget; +import gregtech.api.gui.resources.TextureArea; import gregtech.api.gui.widgets.DrawableWidget; +import gregtech.api.gui.widgets.ImageCycleButtonWidget; import gregtech.api.gui.widgets.ImageWidget; import gregtech.api.unification.OreDictUnifier; import gregtech.api.unification.stack.ItemVariantMap; import gregtech.api.unification.stack.MultiItemVariantMap; import gregtech.api.unification.stack.SingleItemVariantMap; +import gregtech.api.util.function.BooleanConsumer; import gregtech.api.util.oreglob.OreGlob; import gregtech.api.util.oreglob.OreGlobCompileResult; import gregtech.common.covers.filter.oreglob.impl.ImpossibleOreGlob; @@ -18,55 +21,90 @@ import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.nbt.NBTTagCompound; +import net.minecraft.network.PacketBuffer; import net.minecraft.util.text.TextFormatting; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import java.util.Map; import java.util.Set; +import java.util.function.BooleanSupplier; import java.util.function.Consumer; public class OreDictionaryItemFilter extends ItemFilter { + private final Map> matchCache = new Object2ObjectOpenHashMap<>(); + private final SingleItemVariantMap noOreDictMatch = new SingleItemVariantMap<>(); + protected String expression = ""; + private OreGlob glob = ImpossibleOreGlob.getInstance(); private boolean error; - private final Map> matchCache = new Object2ObjectOpenHashMap<>(); - private final SingleItemVariantMap noOreDictMatch = new SingleItemVariantMap<>(); + private boolean caseSensitive; + /** + * {@code false} requires any of the entry to be match in order for the match to be success, {@code true} requires + * all entries to match + */ + private boolean matchAll; + @NotNull public String getExpression() { return expression; } + @NotNull + public OreGlob getGlob() { + return this.glob; + } + + protected void recompile(@Nullable Consumer<@Nullable OreGlobCompileResult> callback) { + clearCache(); + String expr = this.expression; + if (!expr.isEmpty()) { + OreGlobCompileResult result = OreGlob.compile(expr, !this.caseSensitive); + this.glob = result.getInstance(); + this.error = result.hasError(); + if (callback != null) callback.accept(result); + } else { + this.glob = ImpossibleOreGlob.getInstance(); + this.error = true; + if (callback != null) callback.accept(null); + } + } + + protected void clearCache() { + this.matchCache.clear(); + this.noOreDictMatch.clear(); + } + @Override public void initUI(Consumer widgetGroup) { ItemOreFilterTestSlot[] testSlot = new ItemOreFilterTestSlot[5]; for (int i = 0; i < testSlot.length; i++) { - testSlot[i] = new ItemOreFilterTestSlot(20 + 22 * i, 0); - widgetGroup.accept(testSlot[i]); + ItemOreFilterTestSlot slot = new ItemOreFilterTestSlot(20 + 22 * i, 0); + slot.setGlob(getGlob()); + slot.setMatchAll(this.matchAll); + widgetGroup.accept(slot); + testSlot[i] = slot; } OreGlobCompileStatusWidget compilationStatus = new OreGlobCompileStatusWidget(10, 10); + + Consumer<@Nullable OreGlobCompileResult> compileCallback = result -> { + compilationStatus.setCompileResult(result); + for (ItemOreFilterTestSlot slot : testSlot) { + slot.setGlob(getGlob()); + } + }; + HighlightedTextField textField = new HighlightedTextField(14, 26, 152, 14, () -> this.expression, s -> { if (s.equals(this.expression)) return; this.expression = s; - if (!s.isEmpty()) { - OreGlobCompileResult result = OreGlob.compile(s); - this.glob = result.getInstance(); - this.error = result.hasError(); - compilationStatus.setCompileResult(result); - } else { - this.glob = ImpossibleOreGlob.getInstance(); - this.error = true; - compilationStatus.setCompileResult(null); - } - this.matchCache.clear(); - this.noOreDictMatch.clear(); markDirty(); - for (ItemOreFilterTestSlot slot : testSlot) { - slot.setGlob(this.error ? null : this.glob); - } + recompile(compileCallback); }); compilationStatus.setTextField(textField); @@ -91,7 +129,7 @@ public void initUI(Consumer widgetGroup) { case '*', '?' -> h.format(i, TextFormatting.GREEN); case '!' -> h.format(i, TextFormatting.RED); case '\\' -> h.format(i++, TextFormatting.YELLOW); - case '$' -> { + case '$' -> { // TODO: remove this switch case in 2.9 h.format(i, TextFormatting.DARK_GREEN); for (; i < t.length(); i++) { switch (t.charAt(i)) { @@ -114,6 +152,25 @@ public void initUI(Consumer widgetGroup) { h.format(i + 1, TextFormatting.RESET); } }).setMaxLength(64)); + widgetGroup.accept(new ForcedInitialSyncImageCycleButtonWidget(130, 38, 18, 18, + GuiTextures.ORE_FILTER_BUTTON_CASE_SENSITIVE, () -> this.caseSensitive, caseSensitive -> { + if (this.caseSensitive == caseSensitive) return; + this.caseSensitive = caseSensitive; + markDirty(); + recompile(compileCallback); + }).setTooltipHoverString( + i -> "cover.ore_dictionary_filter.button.case_sensitive." + (i == 0 ? "disabled" : "enabled"))); + widgetGroup.accept(new ForcedInitialSyncImageCycleButtonWidget(148, 38, 18, 18, + GuiTextures.ORE_FILTER_BUTTON_MATCH_ALL, () -> this.matchAll, matchAll -> { + if (this.matchAll == matchAll) return; + this.matchAll = matchAll; + markDirty(); + clearCache(); + for (ItemOreFilterTestSlot slot : testSlot) { + slot.setMatchAll(matchAll); + } + }).setTooltipHoverString( + i -> "cover.ore_dictionary_filter.button.match_all." + (i == 0 ? "disabled" : "enabled"))); } @Override @@ -122,7 +179,7 @@ public Object matchItemStack(ItemStack itemStack) { "wtf is this system?? i can put any non null object here and it i will work??? $arch" : null; } - public boolean matchesItemStack(ItemStack itemStack) { + public boolean matchesItemStack(@NotNull ItemStack itemStack) { if (this.error) return false; Item item = itemStack.getItem(); ItemVariantMap> oreDictEntry = OreDictUnifier.getOreDictionaryEntry(item); @@ -160,7 +217,7 @@ public boolean matchesItemStack(ItemStack itemStack) { } this.matchCache.put(item, cacheEntry); } - boolean matches = this.glob.matches(itemStack); + boolean matches = this.matchAll ? this.glob.matchesAll(itemStack) : this.glob.matchesAny(itemStack); cacheEntry.put(itemStack, matches); return matches; } @@ -181,20 +238,43 @@ public int getTotalOccupiedHeight() { } @Override - public void writeToNBT(NBTTagCompound tagCompound) { - tagCompound.setString("OreDictionaryFilter", expression); + public void writeToNBT(NBTTagCompound tag) { + tag.setString("OreDictionaryFilter", expression); + if (this.caseSensitive) tag.setBoolean("caseSensitive", true); + if (this.matchAll) tag.setBoolean("matchAll", true); } @Override - public void readFromNBT(NBTTagCompound tagCompound) { - this.expression = tagCompound.getString("OreDictionaryFilter"); - if (!this.expression.isEmpty()) { - OreGlobCompileResult result = OreGlob.compile(this.expression); - this.glob = result.getInstance(); - this.error = result.hasError(); - } else { - this.glob = ImpossibleOreGlob.getInstance(); - this.error = true; + public void readFromNBT(NBTTagCompound tag) { + this.expression = tag.getString("OreDictionaryFilter"); + this.caseSensitive = tag.getBoolean("caseSensitive"); + this.matchAll = tag.getBoolean("matchAll"); + recompile(null); + } + + public static class ForcedInitialSyncImageCycleButtonWidget extends ImageCycleButtonWidget { + + private final BooleanConsumer updater; + + public ForcedInitialSyncImageCycleButtonWidget(int xPosition, int yPosition, int width, int height, + TextureArea buttonTexture, BooleanSupplier supplier, + BooleanConsumer updater) { + super(xPosition, yPosition, width, height, buttonTexture, supplier, updater); + this.currentOption = 0; + this.updater = updater; + } + + @Override + public void readUpdateInfo(int id, PacketBuffer buffer) { + if (id == 1) { + int currentOptionCache = this.currentOption; + super.readUpdateInfo(id, buffer); + if (this.currentOption != currentOptionCache) { + this.updater.apply(currentOption >= 1); // call updater to apply necessary state changes + } + } else { + super.readUpdateInfo(id, buffer); + } } } } diff --git a/src/main/java/gregtech/common/covers/filter/oreglob/impl/OreGlobMessages.java b/src/main/java/gregtech/common/covers/filter/oreglob/impl/OreGlobMessages.java index 6b3da3ca6fd..d0c2d44e7df 100644 --- a/src/main/java/gregtech/common/covers/filter/oreglob/impl/OreGlobMessages.java +++ b/src/main/java/gregtech/common/covers/filter/oreglob/impl/OreGlobMessages.java @@ -2,6 +2,8 @@ import gregtech.api.util.LocalizationUtils; +import org.jetbrains.annotations.ApiStatus; + import java.util.Locale; interface OreGlobMessages { @@ -102,21 +104,32 @@ static String compileErrorUnexpectedTokenAfterEOF(String token) { return LocalizationUtils.format(COMPILE_ERROR_PREFIX + "unexpected_token_after_eof", token); } + // compilation flags are expected to be removed in future release + + @Deprecated + @SuppressWarnings("DeprecatedIsStillUsed") + @ApiStatus.ScheduledForRemoval(inVersion = "2.9") static String compileErrorUnexpectedCompilationFlag() { // Compilation flags in the middle of expression return LocalizationUtils.format(COMPILE_ERROR_PREFIX + "unexpected_compilation_flag"); } + @Deprecated + @ApiStatus.ScheduledForRemoval(inVersion = "2.9") static String compileErrorEmptyCompilationFlag() { // No compilation flags given return LocalizationUtils.format(COMPILE_ERROR_PREFIX + "empty_compilation_flag"); } + @Deprecated + @ApiStatus.ScheduledForRemoval(inVersion = "2.9") static String compileErrorUnknownCompilationFlag(String flag) { // Unknown compilation flag '%s' return LocalizationUtils.format(COMPILE_ERROR_PREFIX + "unknown_compilation_flag", flag); } + @Deprecated + @ApiStatus.ScheduledForRemoval(inVersion = "2.9") static String compileErrorRedundantCompilationFlag(String flag) { // Compilation flag '%s' written twice return LocalizationUtils.format(COMPILE_ERROR_PREFIX + "redundant_compilation_flag", flag); diff --git a/src/main/java/gregtech/common/covers/filter/oreglob/impl/OreGlobParser.java b/src/main/java/gregtech/common/covers/filter/oreglob/impl/OreGlobParser.java index 0bc564d69db..b4cec035040 100644 --- a/src/main/java/gregtech/common/covers/filter/oreglob/impl/OreGlobParser.java +++ b/src/main/java/gregtech/common/covers/filter/oreglob/impl/OreGlobParser.java @@ -5,6 +5,7 @@ import gregtech.common.covers.filter.oreglob.node.OreGlobNode; import gregtech.common.covers.filter.oreglob.node.OreGlobNodes; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.Nullable; import java.util.ArrayList; @@ -14,7 +15,7 @@ /** * Top-down parser for oreGlob expression. - * + * *
  * oreGlob = [ FLAG ], [ or ], EOF
  *
@@ -47,8 +48,7 @@ public final class OreGlobParser {
 
     private boolean error;
 
-    private boolean caseSensitive;
-
+    private boolean ignoreCase;
     private int inputIndex;
 
     private TokenType tokenType;
@@ -56,8 +56,9 @@ public final class OreGlobParser {
     @Nullable
     private String tokenLiteralValue;
 
-    public OreGlobParser(String input) {
+    public OreGlobParser(String input, boolean ignoreCase) {
         this.input = input;
+        this.ignoreCase = ignoreCase;
     }
 
     // Get codepoint at current position and incr index
@@ -68,6 +69,7 @@ private int readNextChar() {
         return input.codePointAt(i);
     }
 
+    @SuppressWarnings("deprecation")
     private void advance() {
         boolean first = this.inputIndex == 0;
         while (true) {
@@ -84,7 +86,7 @@ private void advance() {
                 case '^' -> setCurrentToken(XOR, start, 1);
                 case '*' -> setCurrentToken(ANY, start, 1);
                 case '?' -> setCurrentToken(ANY_CHAR, start, 1);
-                case '$' -> {
+                case '$' -> { // TODO: remove this switch case in 2.9
                     if (!first) {
                         error(OreGlobMessages.compileErrorUnexpectedCompilationFlag(), start, 1);
                     }
@@ -145,8 +147,10 @@ private String gatherLiteralValue() {
         }
     }
 
+    @Deprecated
+    @SuppressWarnings("DeprecatedIsStillUsed")
+    @ApiStatus.ScheduledForRemoval(inVersion = "2.9")
     private void gatherFlags(boolean add) {
-        boolean flagsAdded = false;
         while (true) {
             int i = this.inputIndex;
             int c = readNextChar();
@@ -156,39 +160,27 @@ private void gatherFlags(boolean add) {
                     if (c == CHAR_EOF) {
                         error(OreGlobMessages.compileErrorEOFAfterEscape(), i, 1);
                     } else if (add) {
-                        addFlag(c, i);
-                        flagsAdded = true;
+                        addFlag(c);
                         continue;
                     }
                 }
                 case ' ', '\t', '\n', '\r', CHAR_EOF -> {}
                 default -> {
                     if (add) {
-                        addFlag(c, i);
-                        flagsAdded = true;
+                        addFlag(c);
                     }
                     continue;
                 }
             }
-            if (!flagsAdded && add) {
-                error(OreGlobMessages.compileErrorEmptyCompilationFlag(), i, 1);
-            }
+            warn("Compilation flags ('$') are scheduled to be removed in future releases.");
             return;
         }
     }
 
-    private void addFlag(int flag, int index) {
-        switch (flag) {
-            case 'c', 'C' -> {
-                if (this.caseSensitive) {
-                    warn(OreGlobMessages.compileErrorRedundantCompilationFlag("c"), index, 1);
-                } else {
-                    this.caseSensitive = true;
-                }
-            }
-            default -> warn(OreGlobMessages.compileErrorUnknownCompilationFlag(
-                    new StringBuilder().appendCodePoint(flag).toString()), index, 1);
-        }
+    @Deprecated
+    @ApiStatus.ScheduledForRemoval(inVersion = "2.9")
+    private void addFlag(int flag) {
+        if (flag == 'c' || flag == 'C') this.ignoreCase = false;
     }
 
     private boolean advanceIf(TokenType type) {
@@ -296,7 +288,7 @@ private OreGlobNode primary() {
         return switch (tokenType) {
             case LITERAL -> {
                 if (tokenLiteralValue != null) {
-                    OreGlobNode result = OreGlobNodes.match(tokenLiteralValue, !this.caseSensitive);
+                    OreGlobNode result = OreGlobNodes.match(tokenLiteralValue, this.ignoreCase);
                     advance();
                     yield result;
                 } else { // likely caused by program error, not user issue
diff --git a/src/main/java/gregtech/common/gui/widget/orefilter/OreFilterTestSlot.java b/src/main/java/gregtech/common/gui/widget/orefilter/OreFilterTestSlot.java
index 6bde8f6cb5b..fd81e80bcd7 100644
--- a/src/main/java/gregtech/common/gui/widget/orefilter/OreFilterTestSlot.java
+++ b/src/main/java/gregtech/common/gui/widget/orefilter/OreFilterTestSlot.java
@@ -23,7 +23,6 @@
 
 import java.util.Arrays;
 import java.util.Collections;
-import java.util.List;
 import java.util.Set;
 import java.util.stream.Collectors;
 
@@ -32,6 +31,9 @@
  */
 public abstract class OreFilterTestSlot extends WidgetGroup {
 
+    private final ImageWidget match;
+    private final ImageWidget noMatch;
+
     @Nullable
     private OreGlob glob;
     private boolean expectedResult = true;
@@ -48,8 +50,7 @@ public abstract class OreFilterTestSlot extends WidgetGroup {
 
     private boolean initialized = false;
 
-    private final ImageWidget match;
-    private final ImageWidget noMatch;
+    private boolean matchAll;
 
     public OreFilterTestSlot(int xPosition, int yPosition) {
         super(xPosition, yPosition, 18, 18);
@@ -86,30 +87,42 @@ public OreFilterTestSlot onMatchChange(@Nullable BooleanConsumer onMatchChange)
     }
 
     public void setGlob(@Nullable OreGlob glob) {
+        if (this.glob == glob) return;
         this.glob = glob;
         updatePreview();
     }
 
+    public void setMatchAll(boolean matchAll) {
+        if (this.matchAll == matchAll) return;
+        this.matchAll = matchAll;
+        updatePreview();
+    }
+
     protected void updatePreview() {
         if (!this.initialized) return;
         Set oreDicts = getTestCandidates();
         if (oreDicts != null) {
-            boolean success;
             OreGlob glob = this.glob;
             if (oreDicts.isEmpty()) {
                 // no oredict entries
-                this.testResult = Object2BooleanMaps.singleton("", success = glob != null && glob.matches(""));
+                this.testResult = Object2BooleanMaps.singleton("", glob != null && glob.matches(""));
                 this.matchType = MatchType.NO_ORE_DICT_MATCH;
             } else {
                 this.testResult = new Object2BooleanAVLTreeMap<>();
-                success = false;
                 for (String oreDict : oreDicts) {
                     boolean matches = glob != null && glob.matches(oreDict);
                     this.testResult.put(oreDict, matches);
-                    success |= matches;
                 }
                 this.matchType = MatchType.ORE_DICT_MATCH;
             }
+            boolean success = this.matchAll;
+            for (var e : testResult.object2BooleanEntrySet()) {
+                boolean result = e.getBooleanValue();
+                if (result == !this.matchAll) {
+                    success = !this.matchAll;
+                    break;
+                }
+            }
             updateAndNotifyMatchSuccess(this.expectedResult == success);
             this.match.setVisible(this.expectedResult == success);
             this.noMatch.setVisible(this.expectedResult != success);
@@ -131,9 +144,8 @@ private void updateAndNotifyMatchSuccess(boolean newValue) {
     }
 
     /**
-     * Get each test candidate for current state of test slot. An empty collection indicates that the
-     * match is for items without any ore dictionary entry. A {@code null} value indicates that the
-     * input state is invalid or empty.
+     * Get each test candidate for current state of test slot. An empty collection indicates that the match is for items
+     * without any ore dictionary entry. A {@code null} value indicates that the input state is invalid or empty.
      *
      * @return each test candidate for current state of test slot
      */
@@ -168,26 +180,17 @@ public void drawInBackground(int mouseX, int mouseY, float partialTicks, IRender
     @Override
     public void drawInForeground(int mouseX, int mouseY) {
         if (isActive() && isMouseOverElement(mouseX, mouseY)) {
-            List list;
-            switch (this.matchType) {
-                case NO_ORE_DICT_MATCH:
-                    list = Collections.singletonList(I18n.format(this.matchSuccess ?
-                            "cover.ore_dictionary_filter.test_slot.no_oredict.matches" :
-                            "cover.ore_dictionary_filter.test_slot.no_oredict.matches_not"));
-                    break;
-                case ORE_DICT_MATCH:
-                    list = this.testResult.object2BooleanEntrySet().stream().map(
-                            e -> I18n.format(e.getBooleanValue() ?
-                                    "cover.ore_dictionary_filter.test_slot.matches" :
-                                    "cover.ore_dictionary_filter.test_slot.matches_not", e.getKey()))
-                            .collect(Collectors.toList());
-                    break;
-                case INVALID:
-                default:
-                    list = Arrays.asList(LocalizationUtils.formatLines("cover.ore_dictionary_filter.test_slot.info"));
-                    break;
-            }
-            drawHoveringText(ItemStack.EMPTY, list, 300, mouseX, mouseY);
+            drawHoveringText(ItemStack.EMPTY, switch (this.matchType) {
+                case NO_ORE_DICT_MATCH -> Collections.singletonList(I18n.format(this.matchSuccess ?
+                        "cover.ore_dictionary_filter.test_slot.no_oredict.matches" :
+                        "cover.ore_dictionary_filter.test_slot.no_oredict.matches_not"));
+                case ORE_DICT_MATCH -> this.testResult.object2BooleanEntrySet().stream().map(
+                        e -> I18n.format(e.getBooleanValue() ?
+                                "cover.ore_dictionary_filter.test_slot.matches" :
+                                "cover.ore_dictionary_filter.test_slot.matches_not", e.getKey()))
+                        .collect(Collectors.toList());
+                default -> Arrays.asList(LocalizationUtils.formatLines("cover.ore_dictionary_filter.test_slot.info"));
+            }, 300, mouseX, mouseY);
         }
     }
 
diff --git a/src/main/java/gregtech/core/CoreModule.java b/src/main/java/gregtech/core/CoreModule.java
index 1d2dc88a4ec..46eeb3e8335 100644
--- a/src/main/java/gregtech/core/CoreModule.java
+++ b/src/main/java/gregtech/core/CoreModule.java
@@ -28,6 +28,7 @@
 import gregtech.api.util.CapesRegistry;
 import gregtech.api.util.VirtualTankRegistry;
 import gregtech.api.util.input.KeyBind;
+import gregtech.api.util.oreglob.OreGlob;
 import gregtech.api.worldgen.bedrockFluids.BedrockFluidVeinHandler;
 import gregtech.api.worldgen.bedrockFluids.BedrockFluidVeinSaveData;
 import gregtech.api.worldgen.config.WorldGenRegistry;
@@ -43,6 +44,7 @@
 import gregtech.common.command.worldgen.CommandWorldgen;
 import gregtech.common.covers.CoverBehaviors;
 import gregtech.common.covers.filter.FilterTypeRegistry;
+import gregtech.common.covers.filter.oreglob.impl.OreGlobParser;
 import gregtech.common.items.MetaItems;
 import gregtech.common.items.ToolItems;
 import gregtech.common.metatileentities.MetaTileEntities;
@@ -114,6 +116,8 @@ public CoreModule() {
         // must be set here because of GroovyScript compat
         // trying to read this before the pre-init stage
         GregTechAPI.materialManager = MaterialRegistryManager.getInstance();
+
+        OreGlob.setCompiler((expr, ignoreCase) -> new OreGlobParser(expr, ignoreCase).compile());
     }
 
     @NotNull
diff --git a/src/main/resources/assets/gregtech/lang/en_us.lang b/src/main/resources/assets/gregtech/lang/en_us.lang
index b70165a7af4..f4525a2dc5c 100644
--- a/src/main/resources/assets/gregtech/lang/en_us.lang
+++ b/src/main/resources/assets/gregtech/lang/en_us.lang
@@ -1175,7 +1175,7 @@ cover.filter.blacklist.disabled=Whitelist
 cover.filter.blacklist.enabled=Blacklist
 
 cover.ore_dictionary_filter.title=Ore Dictionary Filter
-cover.ore_dictionary_filter.info=§bAccepts complex expressions/n§6a & b§r = AND/n§6a | b§r = OR/n§6a ^ b§r = XOR/n§6! abc§r = NOT/n§6( abc )§r for grouping/n§6*§r for wildcard (i.e. 0 or more characters)/n§6?§r for any 1 character/n§6()§r for matching empty entry (including items with no ore dictionary)/n§6$c§r at the start of expression for case-sensitive match/n§bExample:/n§6dust*Gold | (plate* & !*Double*)/nWill match all gold dusts of all sizes or all plates, but not double plates
+cover.ore_dictionary_filter.info=§bAccepts complex expressions/n§6a & b§r = AND/n§6a | b§r = OR/n§6a ^ b§r = XOR/n§6! abc§r = NOT/n§6( abc )§r for grouping/n§6*§r for wildcard (i.e. 0 or more characters)/n§6?§r for any 1 character/n§6()§r for matching empty entry (including items with no ore dictionary)/n§bExample:/n§6dust*Gold | (plate* & !*Double*)/nWill match all gold dusts of all sizes or all plates, but not double plates
 cover.ore_dictionary_filter.test_slot.info=Insert a item to test if it matches the filter expression
 cover.ore_dictionary_filter.test_slot.matches=§a* %s
 cover.ore_dictionary_filter.test_slot.matches_not=§c* %s
@@ -1186,6 +1186,10 @@ cover.ore_dictionary_filter.status.err_warn=§c%s error(s) and %s warning(s)
 cover.ore_dictionary_filter.status.warn=§7%s warning(s)
 cover.ore_dictionary_filter.status.no_issues=§aNo issues
 cover.ore_dictionary_filter.status.explain=Ore filter explanation:
+cover.ore_dictionary_filter.button.case_sensitive.disabled=Case insensitive match
+cover.ore_dictionary_filter.button.case_sensitive.enabled=Case sensitive match
+cover.ore_dictionary_filter.button.match_all.disabled=Match any one of ore dictionary entries
+cover.ore_dictionary_filter.button.match_all.enabled=Match all ore dictionary entries
 
 cover.ore_dictionary_filter.preview.next=... followed by 
 cover.ore_dictionary_filter.preview.match='%s'
diff --git a/src/main/resources/assets/gregtech/textures/gui/widget/ore_filter/button_case_sensitive.png b/src/main/resources/assets/gregtech/textures/gui/widget/ore_filter/button_case_sensitive.png
new file mode 100644
index 0000000000000000000000000000000000000000..6615e156d4f5b3426199403f095230d8d89c9eb0
GIT binary patch
literal 339
zcmV-Z0j&OsP)Px$4M{{nR7i>KmB9_eAPhx6Rc@W5t27HRKo-c=Lm;FcvOos#0-Ysu;)8WBqE$I^{%>fVz?ebJz=;W
zG50H+bM20tbC~L?DZIciY#9hIQF<<}~dTko`mR%qwFZ@LRj=C?a!+SqEl
zBao@uVho4~Q=_X*V>^jpF$N>_c2WcdCnph1kMUa|08b}lHR3KKB2rs5?L#j9*GiCB
l{|>1qP#yg{Px$JV``BR7i>Kls!(vKoEt$l|q4X19~@{0}&43jwTmKK{JOKS)#}VIKUhrL7anz
zJ~xO`Pz;5=mjAsZLZZm4tljbR`@HrG?(STuq9|Czi%Vo?r4hib2u~sOhIUoplWIM)
zbLXVmnhWmkF_D=~J~_|x)=Zw~{Y1@;IkO?vMjtoA-Tkt)dH6g6@bImzneICL0__(10Wq5dlD}ncC>2%5(SB%<4qV8%2c2S9pIJ
zNR)!H-Y=1ru--3uTOI2(qi9i0L{%L%fipfx5$TzjS=;DbnHh_sC}#iq6oqR;0@sF|
zik&iZZOBsHa*Nk3qq&BR`U-(ege|ZcN|b`3s$?RinfrMS8PT>t=3XXhl-xAh0OF=f
gwyEAx)c(OreGlobCompileResult.class) {
 
             @Override

From 3fb84d6cdcbfed053de43cb7179f4207e9a49a3f Mon Sep 17 00:00:00 2001
From: TechLord22 <37029404+TechLord22@users.noreply.github.com>
Date: Sun, 17 Dec 2023 19:42:55 -0500
Subject: [PATCH 4/8] invalidate pipenet routepaths on chunk unload (#2303)

---
 .../metatileentity/NeighborCacheTileEntityBase.java  | 11 +++++++++++
 src/main/java/gregtech/api/pipenet/PipeNet.java      | 12 +++++++++++-
 .../api/pipenet/tile/TileEntityPipeBase.java         | 12 ++++++++++++
 .../common/pipelike/cable/net/EnergyNet.java         | 10 +++++++++-
 .../common/pipelike/cable/tile/TileEntityCable.java  |  8 +++++++-
 .../common/pipelike/itempipe/net/ItemPipeNet.java    | 11 ++++++++++-
 .../pipelike/itempipe/tile/TileEntityItemPipe.java   |  6 ++++++
 .../common/pipelike/laser/net/LaserPipeNet.java      |  5 +++++
 .../pipelike/laser/tile/TileEntityLaserPipe.java     |  6 ++++++
 .../common/pipelike/optical/net/OpticalPipeNet.java  |  5 +++++
 .../pipelike/optical/tile/TileEntityOpticalPipe.java |  6 ++++++
 11 files changed, 88 insertions(+), 4 deletions(-)

diff --git a/src/main/java/gregtech/api/metatileentity/NeighborCacheTileEntityBase.java b/src/main/java/gregtech/api/metatileentity/NeighborCacheTileEntityBase.java
index 473b950d63c..97200ab8518 100644
--- a/src/main/java/gregtech/api/metatileentity/NeighborCacheTileEntityBase.java
+++ b/src/main/java/gregtech/api/metatileentity/NeighborCacheTileEntityBase.java
@@ -7,6 +7,7 @@
 import net.minecraft.util.math.BlockPos;
 import net.minecraft.world.World;
 
+import org.jetbrains.annotations.MustBeInvokedByOverriders;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -28,24 +29,34 @@ protected void invalidateNeighbors() {
         }
     }
 
+    @MustBeInvokedByOverriders
     @Override
     public void setWorld(@NotNull World worldIn) {
         super.setWorld(worldIn);
         invalidateNeighbors();
     }
 
+    @MustBeInvokedByOverriders
     @Override
     public void setPos(@NotNull BlockPos posIn) {
         super.setPos(posIn);
         invalidateNeighbors();
     }
 
+    @MustBeInvokedByOverriders
     @Override
     public void invalidate() {
         super.invalidate();
         invalidateNeighbors();
     }
 
+    @MustBeInvokedByOverriders
+    @Override
+    public void onChunkUnload() {
+        super.onChunkUnload();
+        invalidateNeighbors();
+    }
+
     @Override
     public @Nullable TileEntity getNeighbor(@NotNull EnumFacing facing) {
         if (world == null || pos == null) return null;
diff --git a/src/main/java/gregtech/api/pipenet/PipeNet.java b/src/main/java/gregtech/api/pipenet/PipeNet.java
index 384d15134a1..536b2a23b81 100644
--- a/src/main/java/gregtech/api/pipenet/PipeNet.java
+++ b/src/main/java/gregtech/api/pipenet/PipeNet.java
@@ -15,8 +15,13 @@
 import it.unimi.dsi.fastutil.objects.Object2IntMap;
 import it.unimi.dsi.fastutil.objects.Object2IntOpenHashMap;
 
-import java.util.*;
+import java.util.ArrayDeque;
+import java.util.Collections;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.Map;
 import java.util.Map.Entry;
+import java.util.Set;
 
 public abstract class PipeNet implements INBTSerializable {
 
@@ -63,6 +68,11 @@ public void onPipeConnectionsUpdate() {}
 
     public void onNeighbourUpdate(BlockPos fromPos) {}
 
+    /**
+     * Is called when any Pipe TE in the PipeNet is unloaded
+     */
+    public void onChunkUnload() {}
+
     public Map> getAllNodes() {
         return unmodifiableNodeByBlockPos;
     }
diff --git a/src/main/java/gregtech/api/pipenet/tile/TileEntityPipeBase.java b/src/main/java/gregtech/api/pipenet/tile/TileEntityPipeBase.java
index a2d593bb206..b1ec074d9d6 100644
--- a/src/main/java/gregtech/api/pipenet/tile/TileEntityPipeBase.java
+++ b/src/main/java/gregtech/api/pipenet/tile/TileEntityPipeBase.java
@@ -26,6 +26,7 @@
 import net.minecraftforge.common.capabilities.Capability;
 import net.minecraftforge.common.util.Constants.NBT;
 
+import org.jetbrains.annotations.MustBeInvokedByOverriders;
 import org.jetbrains.annotations.NotNull;
 import org.jetbrains.annotations.Nullable;
 
@@ -539,6 +540,17 @@ public boolean shouldRefresh(@NotNull World world, @NotNull BlockPos pos, IBlock
         return oldState.getBlock() != newSate.getBlock();
     }
 
+    @MustBeInvokedByOverriders
+    @Override
+    public void onChunkUnload() {
+        super.onChunkUnload();
+        WorldPipeNet worldPipeNet = getPipeBlock().getWorldPipeNet(getWorld());
+        PipeNet net = worldPipeNet.getNetFromPos(pos);
+        if (net != null) {
+            net.onChunkUnload();
+        }
+    }
+
     public void doExplosion(float explosionPower) {
         getWorld().setBlockToAir(getPos());
         if (!getWorld().isRemote) {
diff --git a/src/main/java/gregtech/common/pipelike/cable/net/EnergyNet.java b/src/main/java/gregtech/common/pipelike/cable/net/EnergyNet.java
index 8d6f7110cb1..a56fb565600 100644
--- a/src/main/java/gregtech/common/pipelike/cable/net/EnergyNet.java
+++ b/src/main/java/gregtech/common/pipelike/cable/net/EnergyNet.java
@@ -11,7 +11,10 @@
 
 import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
 
-import java.util.*;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.List;
+import java.util.Map;
 
 public class EnergyNet extends PipeNet {
 
@@ -67,6 +70,11 @@ public void onPipeConnectionsUpdate() {
         NET_DATA.clear();
     }
 
+    @Override
+    public void onChunkUnload() {
+        NET_DATA.clear();
+    }
+
     @Override
     protected void transferNodeData(Map> transferredNodes,
                                     PipeNet parentNet) {
diff --git a/src/main/java/gregtech/common/pipelike/cable/tile/TileEntityCable.java b/src/main/java/gregtech/common/pipelike/cable/tile/TileEntityCable.java
index d54d160e525..befdf615466 100644
--- a/src/main/java/gregtech/common/pipelike/cable/tile/TileEntityCable.java
+++ b/src/main/java/gregtech/common/pipelike/cable/tile/TileEntityCable.java
@@ -258,7 +258,7 @@ public  T getCapabilityInternal(Capability capability, @Nullable EnumFacin
         if (capability == GregtechCapabilities.CAPABILITY_ENERGY_CONTAINER) {
             if (world.isRemote)
                 return GregtechCapabilities.CAPABILITY_ENERGY_CONTAINER.cast(clientCapability);
-            if (handlers.size() == 0)
+            if (handlers.isEmpty())
                 initHandlers();
             checkNetwork();
             return GregtechCapabilities.CAPABILITY_ENERGY_CONTAINER.cast(handlers.getOrDefault(facing, defaultHandler));
@@ -293,6 +293,12 @@ private EnergyNet getEnergyNet() {
         return currentEnergyNet;
     }
 
+    @Override
+    public void onChunkUnload() {
+        super.onChunkUnload();
+        this.handlers.clear();
+    }
+
     @Override
     public int getDefaultPaintingColor() {
         return 0x404040;
diff --git a/src/main/java/gregtech/common/pipelike/itempipe/net/ItemPipeNet.java b/src/main/java/gregtech/common/pipelike/itempipe/net/ItemPipeNet.java
index 25e6534b0f4..c836119c344 100644
--- a/src/main/java/gregtech/common/pipelike/itempipe/net/ItemPipeNet.java
+++ b/src/main/java/gregtech/common/pipelike/itempipe/net/ItemPipeNet.java
@@ -9,7 +9,11 @@
 import net.minecraft.util.EnumFacing;
 import net.minecraft.util.math.BlockPos;
 
-import java.util.*;
+import java.util.Collections;
+import java.util.Comparator;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 public class ItemPipeNet extends PipeNet {
 
@@ -43,6 +47,11 @@ public void onPipeConnectionsUpdate() {
         NET_DATA.clear();
     }
 
+    @Override
+    public void onChunkUnload() {
+        NET_DATA.clear();
+    }
+
     @Override
     protected void transferNodeData(Map> transferredNodes,
                                     PipeNet parentNet) {
diff --git a/src/main/java/gregtech/common/pipelike/itempipe/tile/TileEntityItemPipe.java b/src/main/java/gregtech/common/pipelike/itempipe/tile/TileEntityItemPipe.java
index 5880f375964..80b5e233b92 100644
--- a/src/main/java/gregtech/common/pipelike/itempipe/tile/TileEntityItemPipe.java
+++ b/src/main/java/gregtech/common/pipelike/itempipe/tile/TileEntityItemPipe.java
@@ -153,4 +153,10 @@ public int getTransferredItems() {
         updateTransferredState();
         return this.transferredItems;
     }
+
+    @Override
+    public void onChunkUnload() {
+        super.onChunkUnload();
+        this.handlers.clear();
+    }
 }
diff --git a/src/main/java/gregtech/common/pipelike/laser/net/LaserPipeNet.java b/src/main/java/gregtech/common/pipelike/laser/net/LaserPipeNet.java
index 02781ae8ce8..67aef2810ac 100644
--- a/src/main/java/gregtech/common/pipelike/laser/net/LaserPipeNet.java
+++ b/src/main/java/gregtech/common/pipelike/laser/net/LaserPipeNet.java
@@ -46,6 +46,11 @@ public void onPipeConnectionsUpdate() {
         netData.clear();
     }
 
+    @Override
+    public void onChunkUnload() {
+        netData.clear();
+    }
+
     @Override
     protected void transferNodeData(Map> transferredNodes,
                                     PipeNet parentNet) {
diff --git a/src/main/java/gregtech/common/pipelike/laser/tile/TileEntityLaserPipe.java b/src/main/java/gregtech/common/pipelike/laser/tile/TileEntityLaserPipe.java
index 6a11c0503a4..759fa494152 100644
--- a/src/main/java/gregtech/common/pipelike/laser/tile/TileEntityLaserPipe.java
+++ b/src/main/java/gregtech/common/pipelike/laser/tile/TileEntityLaserPipe.java
@@ -224,6 +224,12 @@ public void readFromNBT(@NotNull NBTTagCompound compound) {
         }
     }
 
+    @Override
+    public void onChunkUnload() {
+        super.onChunkUnload();
+        this.handlers.clear();
+    }
+
     private static class DefaultLaserContainer implements ILaserContainer {
 
         @Override
diff --git a/src/main/java/gregtech/common/pipelike/optical/net/OpticalPipeNet.java b/src/main/java/gregtech/common/pipelike/optical/net/OpticalPipeNet.java
index 18f2edd36ca..fceabc6aae6 100644
--- a/src/main/java/gregtech/common/pipelike/optical/net/OpticalPipeNet.java
+++ b/src/main/java/gregtech/common/pipelike/optical/net/OpticalPipeNet.java
@@ -47,6 +47,11 @@ public void onPipeConnectionsUpdate() {
         NET_DATA.clear();
     }
 
+    @Override
+    public void onChunkUnload() {
+        NET_DATA.clear();
+    }
+
     @Override
     protected void transferNodeData(Map> transferredNodes,
                                     PipeNet parentNet) {
diff --git a/src/main/java/gregtech/common/pipelike/optical/tile/TileEntityOpticalPipe.java b/src/main/java/gregtech/common/pipelike/optical/tile/TileEntityOpticalPipe.java
index adf7f995ae1..43efe04cb56 100644
--- a/src/main/java/gregtech/common/pipelike/optical/tile/TileEntityOpticalPipe.java
+++ b/src/main/java/gregtech/common/pipelike/optical/tile/TileEntityOpticalPipe.java
@@ -194,6 +194,12 @@ public void receiveCustomData(int discriminator, PacketBuffer buf) {
         }
     }
 
+    @Override
+    public void onChunkUnload() {
+        super.onChunkUnload();
+        this.handlers.clear();
+    }
+
     private static class DefaultDataHandler implements IDataAccessHatch {
 
         @Override

From a51c424037ee062edc693ffb30bd140287fccd54 Mon Sep 17 00:00:00 2001
From: Serenibyss <10861407+serenibyss@users.noreply.github.com>
Date: Sun, 17 Dec 2023 18:43:12 -0600
Subject: [PATCH 5/8] Allow electrolyzing more hydrocarbons (#2258)

---
 .../materials/OrganicChemistryMaterials.java  |   6 +-
 .../recipe/chemistry/SeparationRecipes.java   | 124 ++++++++++++------
 2 files changed, 88 insertions(+), 42 deletions(-)

diff --git a/src/main/java/gregtech/api/unification/material/materials/OrganicChemistryMaterials.java b/src/main/java/gregtech/api/unification/material/materials/OrganicChemistryMaterials.java
index f47c7cc0a42..de2bdf4a703 100644
--- a/src/main/java/gregtech/api/unification/material/materials/OrganicChemistryMaterials.java
+++ b/src/main/java/gregtech/api/unification/material/materials/OrganicChemistryMaterials.java
@@ -194,7 +194,6 @@ public static void register() {
         Chloromethane = new Material.Builder(1024, gregtechId("chloromethane"))
                 .gas()
                 .color(0xC82CA0)
-                .flags(DISABLE_DECOMPOSITION)
                 .components(Carbon, 1, Hydrogen, 3, Chlorine, 1)
                 .build();
 
@@ -221,12 +220,14 @@ public static void register() {
         Propene = new Material.Builder(1028, gregtechId("propene"))
                 .gas()
                 .color(0xFFDD55)
+                .flags(DISABLE_DECOMPOSITION)
                 .components(Carbon, 3, Hydrogen, 6)
                 .build();
 
         Ethane = new Material.Builder(1029, gregtechId("ethane"))
                 .gas()
                 .color(0xC8C8FF)
+                .flags(DISABLE_DECOMPOSITION)
                 .components(Carbon, 2, Hydrogen, 6)
                 .build();
 
@@ -268,7 +269,6 @@ public static void register() {
         Ethenone = new Material.Builder(1035, gregtechId("ethenone"))
                 .fluid()
                 .color(0x141446)
-                .flags(DISABLE_DECOMPOSITION)
                 .components(Carbon, 2, Hydrogen, 2, Oxygen, 1)
                 .build();
 
@@ -331,7 +331,6 @@ public static void register() {
         AceticAcid = new Material.Builder(1044, gregtechId("acetic_acid"))
                 .liquid(new FluidBuilder().attribute(FluidAttributes.ACID))
                 .color(0xC8B4A0)
-                .flags(DISABLE_DECOMPOSITION)
                 .components(Carbon, 2, Hydrogen, 4, Oxygen, 2)
                 .build();
 
@@ -373,7 +372,6 @@ public static void register() {
         Acetone = new Material.Builder(1050, gregtechId("acetone"))
                 .fluid()
                 .color(0xAFAFAF)
-                .flags(DISABLE_DECOMPOSITION)
                 .components(Carbon, 3, Hydrogen, 6, Oxygen, 1)
                 .build();
 
diff --git a/src/main/java/gregtech/loaders/recipe/chemistry/SeparationRecipes.java b/src/main/java/gregtech/loaders/recipe/chemistry/SeparationRecipes.java
index 3d51fc11124..fc433308a0d 100644
--- a/src/main/java/gregtech/loaders/recipe/chemistry/SeparationRecipes.java
+++ b/src/main/java/gregtech/loaders/recipe/chemistry/SeparationRecipes.java
@@ -369,44 +369,6 @@ public static void init() {
                 .output(dust, Carbon, 4)
                 .duration(100).EUt(60).buildAndRegister();
 
-        ELECTROLYZER_RECIPES.recipeBuilder()
-                .fluidInputs(AceticAcid.getFluid(2000))
-                .fluidOutputs(Ethane.getFluid(1000))
-                .fluidOutputs(CarbonDioxide.getFluid(2000))
-                .fluidOutputs(Hydrogen.getFluid(2000))
-                .duration(512).EUt(60).buildAndRegister();
-
-        ELECTROLYZER_RECIPES.recipeBuilder()
-                .fluidInputs(Chloromethane.getFluid(2000))
-                .fluidOutputs(Ethane.getFluid(1000))
-                .fluidOutputs(Chlorine.getFluid(2000))
-                .duration(400).EUt(60).buildAndRegister();
-
-        ELECTROLYZER_RECIPES.recipeBuilder()
-                .fluidInputs(Acetone.getFluid(2000))
-                .output(dust, Carbon, 3)
-                .fluidOutputs(Propane.getFluid(1000))
-                .fluidOutputs(Water.getFluid(2000))
-                .duration(480).EUt(60).buildAndRegister();
-
-        ELECTROLYZER_RECIPES.recipeBuilder()
-                .fluidInputs(Butane.getFluid(1000))
-                .fluidOutputs(Butene.getFluid(1000))
-                .fluidOutputs(Hydrogen.getFluid(2000))
-                .duration(240).EUt(VA[MV]).buildAndRegister();
-
-        ELECTROLYZER_RECIPES.recipeBuilder()
-                .fluidInputs(Butene.getFluid(1000))
-                .fluidOutputs(Butadiene.getFluid(1000))
-                .fluidOutputs(Hydrogen.getFluid(2000))
-                .duration(240).EUt(VA[MV]).buildAndRegister();
-
-        ELECTROLYZER_RECIPES.recipeBuilder()
-                .fluidInputs(Propane.getFluid(1000))
-                .fluidOutputs(Propene.getFluid(1000))
-                .fluidOutputs(Hydrogen.getFluid(2000))
-                .duration(640).EUt(VA[MV]).buildAndRegister();
-
         ELECTROLYZER_RECIPES.recipeBuilder()
                 .input(dust, Diamond)
                 .output(dust, Carbon, 64)
@@ -470,6 +432,92 @@ public static void init() {
                 .fluidOutputs(Chlorine.getFluid(1000))
                 .duration(288).EUt(60).buildAndRegister();
 
+        ELECTROLYZER_RECIPES.recipeBuilder()
+                .fluidInputs(Propane.getFluid(1000))
+                .output(dust, Carbon, 3)
+                .fluidOutputs(Hydrogen.getFluid(8000))
+                .duration(176).EUt(60).buildAndRegister();
+
+        ELECTROLYZER_RECIPES.recipeBuilder()
+                .fluidInputs(Butene.getFluid(1000))
+                .output(dust, Carbon, 4)
+                .fluidOutputs(Hydrogen.getFluid(8000))
+                .duration(192).EUt(60).buildAndRegister();
+
+        ELECTROLYZER_RECIPES.recipeBuilder()
+                .fluidInputs(Butane.getFluid(1000))
+                .output(dust, Carbon, 4)
+                .fluidOutputs(Hydrogen.getFluid(10000))
+                .duration(224).EUt(60).buildAndRegister();
+
+        ELECTROLYZER_RECIPES.recipeBuilder()
+                .fluidInputs(Styrene.getFluid(1000))
+                .output(dust, Carbon, 8)
+                .fluidOutputs(Hydrogen.getFluid(8000))
+                .duration(384).EUt(60).buildAndRegister();
+
+        ELECTROLYZER_RECIPES.recipeBuilder()
+                .fluidInputs(Butadiene.getFluid(1000))
+                .output(dust, Carbon, 4)
+                .fluidOutputs(Hydrogen.getFluid(6000))
+                .duration(240).EUt(60).buildAndRegister();
+
+        ELECTROLYZER_RECIPES.recipeBuilder()
+                .fluidInputs(Phenol.getFluid(1000))
+                .output(dust, Carbon, 6)
+                .fluidOutputs(Hydrogen.getFluid(6000))
+                .fluidOutputs(Oxygen.getFluid(1000))
+                .duration(312).EUt(90).buildAndRegister();
+
+        ELECTROLYZER_RECIPES.recipeBuilder()
+                .fluidInputs(Ethylene.getFluid(1000))
+                .output(dust, Carbon, 2)
+                .fluidOutputs(Hydrogen.getFluid(4000))
+                .duration(96).EUt(60).buildAndRegister();
+
+        ELECTROLYZER_RECIPES.recipeBuilder()
+                .fluidInputs(Benzene.getFluid(1000))
+                .output(dust, Carbon, 6)
+                .fluidOutputs(Hydrogen.getFluid(6000))
+                .duration(288).EUt(60).buildAndRegister();
+
+        ELECTROLYZER_RECIPES.recipeBuilder()
+                .fluidInputs(Ethanol.getFluid(1000))
+                .output(dust, Carbon, 2)
+                .fluidOutputs(Hydrogen.getFluid(6000))
+                .fluidOutputs(Oxygen.getFluid(1000))
+                .duration(144).EUt(90).buildAndRegister();
+
+        ELECTROLYZER_RECIPES.recipeBuilder()
+                .fluidInputs(Toluene.getFluid(1000))
+                .output(dust, Carbon, 7)
+                .fluidOutputs(Hydrogen.getFluid(8000))
+                .duration(360).EUt(60).buildAndRegister();
+
+        ELECTROLYZER_RECIPES.recipeBuilder()
+                .fluidInputs(Dimethylbenzene.getFluid(1000))
+                .output(dust, Carbon, 8)
+                .fluidOutputs(Hydrogen.getFluid(10000))
+                .duration(432).EUt(60).buildAndRegister();
+
+        ELECTROLYZER_RECIPES.recipeBuilder()
+                .fluidInputs(Octane.getFluid(1000))
+                .output(dust, Carbon, 8)
+                .fluidOutputs(Hydrogen.getFluid(18000))
+                .duration(624).EUt(60).buildAndRegister();
+
+        ELECTROLYZER_RECIPES.recipeBuilder()
+                .fluidInputs(Propene.getFluid(1000))
+                .output(dust, Carbon, 3)
+                .fluidOutputs(Hydrogen.getFluid(6000))
+                .duration(144).EUt(60).buildAndRegister();
+
+        ELECTROLYZER_RECIPES.recipeBuilder()
+                .fluidInputs(Ethane.getFluid(1000))
+                .output(dust, Carbon, 2)
+                .fluidOutputs(Hydrogen.getFluid(6000))
+                .duration(128).EUt(60).buildAndRegister();
+
         // Thermal Centrifuge
         THERMAL_CENTRIFUGE_RECIPES.recipeBuilder()
                 .inputs(new ItemStack(Blocks.COBBLESTONE, 1, GTValues.W))

From e54bb80402211e073bcac50dcd6d42bc6b42a30e Mon Sep 17 00:00:00 2001
From: serenibyss <10861407+serenibyss@users.noreply.github.com>
Date: Sun, 17 Dec 2023 18:44:43 -0600
Subject: [PATCH 6/8] 2.8.4

---
 gradle.properties | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gradle.properties b/gradle.properties
index e213ae3b547..cc4a87789c5 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -7,7 +7,7 @@ modGroup = gregtech
 
 # Version of your mod.
 # This field can be left empty if you want your mod's version to be determined by the latest git tag instead.
-modVersion = 2.8.3-beta
+modVersion = 2.8.4-beta
 
 # Whether to use the old jar naming structure (modid-mcversion-version) instead of the new version (modid-version)
 includeMCVersionJar = true

From 0bd52347f97a60fa2eb434ca3613093cc11e20a4 Mon Sep 17 00:00:00 2001
From: TechLord22 <37029404+TechLord22@users.noreply.github.com>
Date: Sun, 17 Dec 2023 21:46:25 -0500
Subject: [PATCH 7/8] only access worldpipenet on server (#2310)

---
 .../gregtech/api/pipenet/WorldPipeNet.java    | 21 +++++++++++++++----
 .../api/pipenet/tile/TileEntityPipeBase.java  | 10 +++++----
 2 files changed, 23 insertions(+), 8 deletions(-)

diff --git a/src/main/java/gregtech/api/pipenet/WorldPipeNet.java b/src/main/java/gregtech/api/pipenet/WorldPipeNet.java
index 23860461888..03211cc377c 100644
--- a/src/main/java/gregtech/api/pipenet/WorldPipeNet.java
+++ b/src/main/java/gregtech/api/pipenet/WorldPipeNet.java
@@ -1,5 +1,7 @@
 package gregtech.api.pipenet;
 
+import gregtech.api.util.GTLog;
+
 import net.minecraft.nbt.NBTTagCompound;
 import net.minecraft.nbt.NBTTagList;
 import net.minecraft.util.EnumFacing;
@@ -12,7 +14,11 @@
 import org.jetbrains.annotations.NotNull;
 
 import java.lang.ref.WeakReference;
-import java.util.*;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
 
 public abstract class WorldPipeNet> extends WorldSavedData {
 
@@ -35,9 +41,16 @@ protected void setWorldAndInit(World world) {
         }
     }
 
-    public static String getDataID(final String baseID, final World world) {
-        if (world == null || world.isRemote)
-            throw new RuntimeException("WorldPipeNet should only be created on the server!");
+    public static @NotNull String getDataID(@NotNull final String baseID, @NotNull final World world) {
+        // noinspection ConstantValue
+        if (world == null || world.isRemote) {
+            GTLog.logger.error("WorldPipeNet should only be created on the server!", new Throwable());
+            // noinspection ConstantValue
+            if (world == null) {
+                return baseID;
+            }
+        }
+
         int dimension = world.provider.getDimension();
         return dimension == 0 ? baseID : baseID + '.' + dimension;
     }
diff --git a/src/main/java/gregtech/api/pipenet/tile/TileEntityPipeBase.java b/src/main/java/gregtech/api/pipenet/tile/TileEntityPipeBase.java
index b1ec074d9d6..84897a022e8 100644
--- a/src/main/java/gregtech/api/pipenet/tile/TileEntityPipeBase.java
+++ b/src/main/java/gregtech/api/pipenet/tile/TileEntityPipeBase.java
@@ -544,10 +544,12 @@ public boolean shouldRefresh(@NotNull World world, @NotNull BlockPos pos, IBlock
     @Override
     public void onChunkUnload() {
         super.onChunkUnload();
-        WorldPipeNet worldPipeNet = getPipeBlock().getWorldPipeNet(getWorld());
-        PipeNet net = worldPipeNet.getNetFromPos(pos);
-        if (net != null) {
-            net.onChunkUnload();
+        if (!world.isRemote) {
+            WorldPipeNet worldPipeNet = getPipeBlock().getWorldPipeNet(getWorld());
+            PipeNet net = worldPipeNet.getNetFromPos(pos);
+            if (net != null) {
+                net.onChunkUnload();
+            }
         }
     }
 

From c4060fa6d3ea8c0d6b8ed9f9719cfbd841261312 Mon Sep 17 00:00:00 2001
From: serenibyss <10861407+serenibyss@users.noreply.github.com>
Date: Sun, 17 Dec 2023 20:46:51 -0600
Subject: [PATCH 8/8] 2.8.5

---
 gradle.properties | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/gradle.properties b/gradle.properties
index cc4a87789c5..8cc69185de4 100644
--- a/gradle.properties
+++ b/gradle.properties
@@ -7,7 +7,7 @@ modGroup = gregtech
 
 # Version of your mod.
 # This field can be left empty if you want your mod's version to be determined by the latest git tag instead.
-modVersion = 2.8.4-beta
+modVersion = 2.8.5-beta
 
 # Whether to use the old jar naming structure (modid-mcversion-version) instead of the new version (modid-version)
 includeMCVersionJar = true