diff --git a/src/generated/resources/assets/gtceu/models/item/gui_module.json b/src/generated/resources/assets/gtceu/models/item/gui_module.json new file mode 100644 index 00000000000..5c1152837c4 --- /dev/null +++ b/src/generated/resources/assets/gtceu/models/item/gui_module.json @@ -0,0 +1,6 @@ +{ + "parent": "minecraft:item/generated", + "textures": { + "layer0": "gtceu:item/gui_module" + } +} \ No newline at end of file diff --git a/src/main/java/com/gregtechceu/gtceu/api/item/component/IMonitorModuleItem.java b/src/main/java/com/gregtechceu/gtceu/api/item/component/IMonitorModuleItem.java index 6bfa55da341..38b1464a62b 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/item/component/IMonitorModuleItem.java +++ b/src/main/java/com/gregtechceu/gtceu/api/item/component/IMonitorModuleItem.java @@ -1,11 +1,12 @@ package com.gregtechceu.gtceu.api.item.component; +import com.gregtechceu.gtceu.api.mui.base.IPanelHandler; +import com.gregtechceu.gtceu.api.mui.value.sync.PanelSyncManager; +import com.gregtechceu.gtceu.client.mui.screen.ModularPanel; import com.gregtechceu.gtceu.client.renderer.monitor.IMonitorRenderer; import com.gregtechceu.gtceu.common.machine.multiblock.electric.CentralMonitorMachine; import com.gregtechceu.gtceu.common.machine.multiblock.electric.monitor.MonitorGroup; -import com.lowdragmc.lowdraglib.gui.widget.Widget; - import net.minecraft.world.item.ItemStack; public interface IMonitorModuleItem extends IItemComponent { @@ -14,7 +15,8 @@ default void tick(ItemStack stack, CentralMonitorMachine machine, MonitorGroup g IMonitorRenderer getRenderer(ItemStack stack, CentralMonitorMachine machine, MonitorGroup group); - Widget createUIWidget(ItemStack stack, CentralMonitorMachine machine, MonitorGroup group); + ModularPanel createModularPanel(ItemStack stack, CentralMonitorMachine machine, MonitorGroup group, + PanelSyncManager syncManager, IPanelHandler panelHandler); default String getType() { return "unknown"; diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/InWorldMUIOpenEvent.java b/src/main/java/com/gregtechceu/gtceu/api/mui/InWorldMUIOpenEvent.java new file mode 100644 index 00000000000..4817595ef30 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/InWorldMUIOpenEvent.java @@ -0,0 +1,27 @@ +package com.gregtechceu.gtceu.api.mui; + +import com.gregtechceu.gtceu.api.mui.factory.GuiData; +import com.gregtechceu.gtceu.client.mui.screen.ModularContainerMenu; +import com.gregtechceu.gtceu.client.mui.screen.ModularScreen; + +import net.minecraft.client.gui.screens.Screen; +import net.minecraftforge.eventbus.api.Event; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +public class InWorldMUIOpenEvent extends Event { + + @Getter + private final GuiData guiData; + + @Getter + private final Screen vanillaScreen; + + @Getter + private final ModularScreen screen; + + @Getter + private final ModularContainerMenu menu; +} diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/InWorldMUIRenderEvent.java b/src/main/java/com/gregtechceu/gtceu/api/mui/InWorldMUIRenderEvent.java new file mode 100644 index 00000000000..8a965ac5e63 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/InWorldMUIRenderEvent.java @@ -0,0 +1,15 @@ +package com.gregtechceu.gtceu.api.mui; + +import net.minecraft.client.gui.GuiGraphics; +import net.minecraftforge.eventbus.api.Event; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +@AllArgsConstructor +@Getter +public class InWorldMUIRenderEvent extends Event { + + private final GuiGraphics graphics; + private final float partialTick; +} diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/animation/AnimatorManager.java b/src/main/java/com/gregtechceu/gtceu/api/mui/animation/AnimatorManager.java index 86f8202afcf..6398d9c85c7 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/animation/AnimatorManager.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/animation/AnimatorManager.java @@ -11,6 +11,8 @@ public class AnimatorManager { + public static final AnimatorManager INSTANCE = new AnimatorManager(); + private static final List animators = new ArrayList<>(16); private static final List queuedAnimators = new ArrayList<>(8); private static long lastTime = 0; @@ -25,7 +27,7 @@ static void startAnimation(IAnimator animator) { private AnimatorManager() {} public static void init() { - MinecraftForge.EVENT_BUS.register(new AnimatorManager()); + MinecraftForge.EVENT_BUS.register(INSTANCE); } @SubscribeEvent(priority = EventPriority.HIGHEST) diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/factory/GuiManager.java b/src/main/java/com/gregtechceu/gtceu/api/mui/factory/GuiManager.java index b556deee40c..8263103de5e 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/factory/GuiManager.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/factory/GuiManager.java @@ -1,6 +1,7 @@ package com.gregtechceu.gtceu.api.mui.factory; import com.gregtechceu.gtceu.GTCEu; +import com.gregtechceu.gtceu.api.mui.InWorldMUIOpenEvent; import com.gregtechceu.gtceu.api.mui.base.IMuiScreen; import com.gregtechceu.gtceu.api.mui.base.MCHelper; import com.gregtechceu.gtceu.api.mui.base.UIFactory; @@ -10,6 +11,7 @@ import com.gregtechceu.gtceu.api.mui.widget.WidgetTree; import com.gregtechceu.gtceu.client.mui.screen.*; import com.gregtechceu.gtceu.common.network.GTNetwork; +import com.gregtechceu.gtceu.common.network.InWorldContainerSynchronizer; import com.gregtechceu.gtceu.common.network.ModularNetwork; import com.gregtechceu.gtceu.common.network.packets.ui.OpenGuiPacket; @@ -47,6 +49,8 @@ public class GuiManager { 16); private static final List openedContainers = new ArrayList<>(4); + private static final Object2ObjectMap> openedInWorldContainers = new Object2ObjectOpenHashMap<>(); + private static final List clientInWorldContainers = new ArrayList<>(); public static void registerFactory(UIFactory factory) { Objects.requireNonNull(factory); @@ -69,8 +73,13 @@ public static boolean hasFactory(ResourceLocation name) { public static void open(@NotNull UIFactory factory, @NotNull T guiData, ServerPlayer player) { + open(factory, false, guiData, player); + } + + public static void open(@NotNull UIFactory factory, boolean inWorldUI, @NotNull T guiData, + ServerPlayer player) { if (player instanceof FakePlayer || openedContainers.contains(player)) return; - openedContainers.add(player); + if (!inWorldUI) openedContainers.add(player); // create panel, collect sync handlers and create menu UISettings settings = new UISettings(XeiSettings.DUMMY); settings.defaultCanInteractWith(factory, guiData); @@ -81,7 +90,7 @@ public static void open(@NotNull UIFactory factory, @NotN // create the menu player.nextContainerCounter(); - if (player.containerMenu != player.inventoryMenu) { + if (player.containerMenu != player.inventoryMenu && !inWorldUI) { player.closeContainer(); } int windowId = player.containerCounter; @@ -93,11 +102,17 @@ public static void open(@NotNull UIFactory factory, @NotN FriendlyByteBuf buffer = new FriendlyByteBuf(Unpooled.buffer()); factory.writeGuiData(guiData, buffer); int nid = ModularNetwork.SERVER.activate(msm); - GTNetwork.sendToPlayer(player, new OpenGuiPacket<>(windowId, nid, factory, buffer)); + GTNetwork.sendToPlayer(player, new OpenGuiPacket<>(windowId, nid, factory, buffer, inWorldUI)); // open the menu // this mimics forge behaviour - player.initMenu(menu); - player.containerMenu = menu; - // init mui syncer + if (!inWorldUI) { + player.initMenu(menu); + player.containerMenu = menu; + } else { + List tmp = openedInWorldContainers.computeIfAbsent(player, p -> new ArrayList<>()); + menu.inWorldID = tmp.size(); + tmp.add(menu); + menu.setSynchronizer(new InWorldContainerSynchronizer(player)); + } msm.onOpen(); // finally invoke event MinecraftForge.EVENT_BUS.post(new PlayerContainerEvent.Open(player, menu)); @@ -105,10 +120,12 @@ public static void open(@NotNull UIFactory factory, @NotN @ApiStatus.Internal @OnlyIn(Dist.CLIENT) - public static void openFromClient(int windowId, int networkId, @NotNull UIFactory factory, + public static void openFromClient(int windowId, int networkId, boolean inWorldUI, + @NotNull UIFactory factory, @NotNull FriendlyByteBuf data, @NotNull LocalPlayer player) { T guiData = factory.readGuiData(player, data); UISettings settings = new UISettings(); + if (inWorldUI) settings.getXeiSettings().forceDisabled(); settings.defaultCanInteractWith(factory, guiData); ModularSyncManager msm = new ModularSyncManager(true); PanelSyncManager syncManager = new PanelSyncManager(msm, true); @@ -127,18 +144,31 @@ public static void openFromClient(int windowId, int networkI if (guiContainer.getMenu() != container) throw new IllegalStateException("Custom Containers are not yet allowed!"); ModularNetwork.CLIENT.activate(networkId, msm); - MCHelper.setScreen(wrapper.getWrappedScreen()); - player.containerMenu = guiContainer.getMenu(); + if (inWorldUI) { + container.inWorldID = clientInWorldContainers.size(); + clientInWorldContainers.add(container); + MinecraftForge.EVENT_BUS + .post(new InWorldMUIOpenEvent(guiData, wrapper.getWrappedScreen(), screen, container)); + } else { + MCHelper.setScreen(wrapper.getWrappedScreen()); + player.containerMenu = guiContainer.getMenu(); + } msm.onOpen(); } @OnlyIn(Dist.CLIENT) public static void openFromClient(@NotNull UIFactory factory, @NotNull T guiData) { + openFromClient(factory, guiData, false); + } + + @OnlyIn(Dist.CLIENT) + public static void openFromClient(@NotNull UIFactory factory, @NotNull T guiData, + boolean inWorldUI) { // notify server to open the gui // server will send packet back to actually open the gui FriendlyByteBuf buffer = new FriendlyByteBuf(Unpooled.buffer()); factory.writeGuiData(guiData, buffer); - GTNetwork.sendToServer(new OpenGuiPacket<>(0, 0, factory, buffer)); + GTNetwork.sendToServer(new OpenGuiPacket<>(0, 0, factory, buffer, inWorldUI)); } @OnlyIn(Dist.CLIENT) @@ -164,6 +194,38 @@ static void openScreen(ModularScreen screen, UISettings settings) { public static void onTick(TickEvent.ServerTickEvent event) { if (event.phase == TickEvent.Phase.END) { openedContainers.clear(); + openedInWorldContainers.values().forEach(arr -> arr.forEach(ModularContainerMenu::onUpdate)); + openedInWorldContainers.values().forEach(arr -> arr.forEach(ModularContainerMenu::broadcastChanges)); } } + + @SubscribeEvent + public static void onClientTick(TickEvent.ClientTickEvent event) { + if (event.phase == TickEvent.Phase.END) { + clientInWorldContainers.forEach(ModularContainerMenu::onUpdate); + clientInWorldContainers.forEach(ModularContainerMenu::broadcastChanges); + } + } + + @SubscribeEvent + public static void onOpenContainer(PlayerContainerEvent.Open event) { + if (event.getContainer() instanceof ModularContainerMenu modularContainer) { + modularContainer.opened(); + } + } + + @SubscribeEvent + public static void onCloseContainer(PlayerContainerEvent.Close event) { + if (event.getContainer() instanceof ModularContainerMenu modularContainer) { + modularContainer.removed(event.getEntity()); + } + } + + public static ModularContainerMenu getClientInWorldMenu(int inWorldID) { + return clientInWorldContainers.get(inWorldID); + } + + public static ModularContainerMenu getServerInWorldMenu(ServerPlayer player, int inWorldID) { + return openedInWorldContainers.get(player).get(inWorldID); + } } diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/PanelSyncManager.java b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/PanelSyncManager.java index ca3d2c724e1..dcf82c971d9 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/PanelSyncManager.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/value/sync/PanelSyncManager.java @@ -190,7 +190,9 @@ private void putSyncValue(String name, int id, SyncHandler syncHandler) { if (!currentKey.equals(key)) { boolean auto = name.startsWith(ModularSyncManager.AUTO_SYNC_PREFIX); if (auto != currentKey.startsWith(ModularSyncManager.AUTO_SYNC_PREFIX)) { - throw new IllegalStateException("Old and new sync handler must both be either not auto or auto!"); + throw new IllegalStateException( + "Old and new sync handler must both be either not auto or auto! (old key = \"%s\", new key = \"%s\"" + .formatted(currentKey, key)); } if (auto && !currentKey.startsWith(name)) { throw new IllegalStateException("Sync Handler was previously added with a different panel!"); diff --git a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/SlotGroupWidget.java b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/SlotGroupWidget.java index 286fec1596d..cad7e2782ad 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/SlotGroupWidget.java +++ b/src/main/java/com/gregtechceu/gtceu/api/mui/widgets/SlotGroupWidget.java @@ -10,6 +10,7 @@ import it.unimi.dsi.fastutil.chars.Char2IntOpenHashMap; import it.unimi.dsi.fastutil.chars.Char2ObjectMap; import it.unimi.dsi.fastutil.chars.Char2ObjectOpenHashMap; +import lombok.Getter; import java.util.ArrayList; import java.util.Collections; @@ -19,6 +20,9 @@ public class SlotGroupWidget extends ParentWidget { + @Getter + private boolean playerInventory = false; + public static SlotGroupWidget playerInventory(boolean positioned) { return positioned ? playerInventory(7, true) : playerInventory((index, slot) -> slot); } @@ -45,6 +49,7 @@ public static SlotGroupWidget playerInventory(int bottom, boolean horizontalCent */ public static SlotGroupWidget playerInventory(SlotConsumer slotConsumer) { SlotGroupWidget slotGroupWidget = new SlotGroupWidget(); + slotGroupWidget.playerInventory = true; slotGroupWidget.coverChildren(); slotGroupWidget.name("player_inventory"); String key = "player"; diff --git a/src/main/java/com/gregtechceu/gtceu/api/placeholder/PlaceholderHandler.java b/src/main/java/com/gregtechceu/gtceu/api/placeholder/PlaceholderHandler.java index c496615442a..86edbd0bd77 100644 --- a/src/main/java/com/gregtechceu/gtceu/api/placeholder/PlaceholderHandler.java +++ b/src/main/java/com/gregtechceu/gtceu/api/placeholder/PlaceholderHandler.java @@ -84,31 +84,31 @@ public static MultiLineComponent processPlaceholders(String s, PlaceholderContex int symbol = 1; Stack> stack = new Stack<>(); stack.push(GTUtil.list(MultiLineComponent.empty())); - for (char c : s.toCharArray()) { - if (escape || (literalEscape && c != LITERAL_ESCAPE)) { - if (c == ESCAPED_NEWLINE && !literalEscape) { - GTUtil.getLast(stack.peek()).appendNewline(); - line++; - symbol = 0; - } else if (c == NEWLINE) continue; - else GTUtil.getLast(stack.peek()).append(c); - } else { - switch (c) { - case ESCAPE -> escapeNext = true; - case LITERAL_ESCAPE -> literalEscape = !literalEscape; - case NEWLINE -> { + try { + for (char c : s.toCharArray()) { + if (escape || (literalEscape && c != LITERAL_ESCAPE)) { + if (c == ESCAPED_NEWLINE && !literalEscape) { GTUtil.getLast(stack.peek()).appendNewline(); line++; symbol = 0; - } - case ARG_SEPARATOR -> { - if (stack.size() == 1) GTUtil.getLast(stack.peek()).append(c); - else stack.peek().add(MultiLineComponent.empty()); - } - case PLACEHOLDER_BEGIN -> stack.push(GTUtil.list(MultiLineComponent.empty())); - case PLACEHOLDER_END -> { - List placeholder = stack.pop(); - try { + } else if (c == NEWLINE) continue; + else GTUtil.getLast(stack.peek()).append(c); + } else { + switch (c) { + case ESCAPE -> escapeNext = true; + case LITERAL_ESCAPE -> literalEscape = !literalEscape; + case NEWLINE -> { + GTUtil.getLast(stack.peek()).appendNewline(); + line++; + symbol = 0; + } + case ARG_SEPARATOR -> { + if (stack.size() == 1) GTUtil.getLast(stack.peek()).append(c); + else stack.peek().add(MultiLineComponent.empty()); + } + case PLACEHOLDER_BEGIN -> stack.push(GTUtil.list(MultiLineComponent.empty())); + case PLACEHOLDER_END -> { + List placeholder = stack.pop(); if (stack.isEmpty()) throw new UnexpectedBracketException(); MultiLineComponent result = processPlaceholder(placeholder, ctx); if (result.isIgnoreSpaces() || stack.size() == 1) { @@ -134,19 +134,19 @@ public static MultiLineComponent processPlaceholders(String s, PlaceholderContex if (i != result.size() - 1) GTUtil.getLast(stack.peek()).appendNewline(); } } - } catch (PlaceholderException e) { - e.setLineInfo(line, symbol); - exceptions.add(e); - } catch (RuntimeException e) { - exceptions.add(e); } + default -> GTUtil.getLast(stack.peek()).append(c); } - default -> GTUtil.getLast(stack.peek()).append(c); } + escape = escapeNext; + escapeNext = false; + symbol++; } - escape = escapeNext; - escapeNext = false; - symbol++; + } catch (PlaceholderException e) { + e.setLineInfo(line, symbol); + exceptions.add(e); + } catch (RuntimeException e) { + exceptions.add(e); } if (stack.size() > 1) { PlaceholderException exception = new UnclosedBracketException(); diff --git a/src/main/java/com/gregtechceu/gtceu/client/CharTypedEvent.java b/src/main/java/com/gregtechceu/gtceu/client/CharTypedEvent.java new file mode 100644 index 00000000000..77935f7f852 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/CharTypedEvent.java @@ -0,0 +1,21 @@ +package com.gregtechceu.gtceu.client; + +import net.minecraftforge.eventbus.api.Cancelable; +import net.minecraftforge.eventbus.api.Event; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * Fired when the corresponding GLFW event is triggered, before Minecraft's handling. + * Cancelling this event will also cancel further handling by Minecraft, like firing the + * {@link net.minecraftforge.client.event.ScreenEvent.CharacterTyped} event. + */ +@AllArgsConstructor +@Getter +@Cancelable +public class CharTypedEvent extends Event { + + private final char codepoint; + private final int modifiers; +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/EarlyKeyPressEvent.java b/src/main/java/com/gregtechceu/gtceu/client/EarlyKeyPressEvent.java new file mode 100644 index 00000000000..222a9536cb3 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/EarlyKeyPressEvent.java @@ -0,0 +1,26 @@ +package com.gregtechceu.gtceu.client; + +import net.minecraftforge.client.event.InputEvent.Key; +import net.minecraftforge.client.event.ScreenEvent.KeyPressed; +import net.minecraftforge.eventbus.api.Cancelable; +import net.minecraftforge.eventbus.api.Event; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * Fired when the corresponding GLFW event is triggered, before Minecraft's handling. + * Cancelling this event will also cancel further handling by Minecraft, like detecting + * ESC to pause the game, other controls, and firing the {@link Key} and {@link KeyPressed} + * events. + */ +@AllArgsConstructor +@Getter +@Cancelable +public class EarlyKeyPressEvent extends Event { + + private final int key; + private final int scanCode; + private final int action; + private final int modifiers; +} diff --git a/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ClientScreenHandler.java b/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ClientScreenHandler.java index ffbe8af15ca..2b973ab1144 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ClientScreenHandler.java +++ b/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ClientScreenHandler.java @@ -311,9 +311,9 @@ private static boolean doAction(@Nullable ModularScreen muiScreen, Predicate ms.keyPressed(keyCode, scanCode, modifiers)) : @@ -680,7 +680,7 @@ public static GuiContext getBestContext() { return defaultContext; } - private enum InputPhase { + public enum InputPhase { // for mui interactions EARLY, diff --git a/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ModularContainerMenu.java b/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ModularContainerMenu.java index 3f0ff42da25..8991a3686c2 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ModularContainerMenu.java +++ b/src/main/java/com/gregtechceu/gtceu/client/mui/screen/ModularContainerMenu.java @@ -58,6 +58,8 @@ public static ModularContainerMenu getCurrent(Player player) { @OnlyIn(Dist.CLIENT) private ModularScreen optionalScreen; + public int inWorldID = -1; + public ModularContainerMenu(int containerId) { super(GTMenuTypes.MODULAR_CONTAINER.get(), containerId); } diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/GTRenderTypes.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/GTRenderTypes.java index 60e78463372..fb40dfdcdb2 100644 --- a/src/main/java/com/gregtechceu/gtceu/client/renderer/GTRenderTypes.java +++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/GTRenderTypes.java @@ -34,6 +34,15 @@ public class GTRenderTypes extends RenderType { .createCompositeState(false)); }); + private static final RenderType INWORLD_GUI = create("inworld_gui", DefaultVertexFormat.POSITION_COLOR_TEX_LIGHTMAP, + VertexFormat.Mode.QUADS, + RenderType.TRANSIENT_BUFFER_SIZE, false, true, + RenderType.CompositeState.builder() + .setShaderState(RENDERTYPE_TRANSLUCENT_SHADER) + .setTextureState(RenderStateShard.NO_TEXTURE) + .setTransparencyState(TRANSLUCENT_TRANSPARENCY) + .setLightmapState(LIGHTMAP) + .createCompositeState(false)); private static final RenderType GUI_TRIANGLE_STRIP = RenderType.create("gui_triangle_strip", DefaultVertexFormat.POSITION_COLOR, VertexFormat.Mode.TRIANGLE_STRIP, 256, false, false, RenderType.CompositeState.builder() @@ -72,6 +81,10 @@ public static RenderType guiTexture(ResourceLocation texture) { return GUI_TEXTURE.apply(texture); } + public static RenderType inWorldGui() { + return INWORLD_GUI; + } + public static RenderType guiTriangleStrip() { return GUI_TRIANGLE_STRIP; } diff --git a/src/main/java/com/gregtechceu/gtceu/client/renderer/monitor/MonitorGuiRenderer.java b/src/main/java/com/gregtechceu/gtceu/client/renderer/monitor/MonitorGuiRenderer.java new file mode 100644 index 00000000000..a3355bbfbec --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/client/renderer/monitor/MonitorGuiRenderer.java @@ -0,0 +1,240 @@ +package com.gregtechceu.gtceu.client.renderer.monitor; + +import com.gregtechceu.gtceu.api.machine.MetaMachine; +import com.gregtechceu.gtceu.api.machine.feature.IMuiMachine; +import com.gregtechceu.gtceu.api.mui.InWorldMUIOpenEvent; +import com.gregtechceu.gtceu.api.mui.InWorldMUIRenderEvent; +import com.gregtechceu.gtceu.api.mui.animation.AnimatorManager; +import com.gregtechceu.gtceu.api.mui.base.MCHelper; +import com.gregtechceu.gtceu.api.mui.base.widget.IWidget; +import com.gregtechceu.gtceu.api.mui.factory.GuiManager; +import com.gregtechceu.gtceu.api.mui.factory.PosGuiData; +import com.gregtechceu.gtceu.api.mui.widgets.SlotGroupWidget; +import com.gregtechceu.gtceu.client.CharTypedEvent; +import com.gregtechceu.gtceu.client.EarlyKeyPressEvent; +import com.gregtechceu.gtceu.client.mui.screen.*; +import com.gregtechceu.gtceu.common.machine.multiblock.electric.CentralMonitorMachine; +import com.gregtechceu.gtceu.common.machine.multiblock.electric.monitor.MonitorGroup; +import com.gregtechceu.gtceu.common.machine.multiblock.part.monitor.AdvancedMonitorPartMachine; +import com.gregtechceu.gtceu.common.machine.multiblock.part.monitor.MonitorPartMachine; +import com.gregtechceu.gtceu.common.mui.factory.MachineUIFactory; +import com.gregtechceu.gtceu.core.IGameRenderer; +import com.gregtechceu.gtceu.utils.GTUtil; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.ShaderInstance; +import net.minecraft.core.BlockPos; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraftforge.client.ForgeHooksClient; +import net.minecraftforge.common.ForgeMod; +import net.minecraftforge.common.MinecraftForge; +import net.minecraftforge.eventbus.api.SubscribeEvent; + +import com.mojang.blaze3d.pipeline.RenderTarget; +import com.mojang.blaze3d.pipeline.TextureTarget; +import com.mojang.blaze3d.platform.InputConstants; +import com.mojang.blaze3d.systems.RenderSystem; +import com.mojang.blaze3d.vertex.*; +import com.mojang.datafixers.util.Pair; +import org.joml.Matrix4f; +import org.joml.Vector2d; +import org.lwjgl.glfw.GLFW; + +public class MonitorGuiRenderer implements IMonitorRenderer { + + private static final int RESOLUTION_COEF = 2; + + private ModularScreen screen; + private Screen vanillaScreen; + private int width = 200, height = 200; + private int mouseX = -1, mouseY = -1; + private final Level targetLevel; + private final BlockPos targetPos; + private final RenderTarget renderTarget = new TextureTarget(width, height, true, Minecraft.ON_OSX); + + public MonitorGuiRenderer(Pair target) { + MinecraftForge.EVENT_BUS.register(this); + this.targetLevel = target.getFirst(); + this.targetPos = target.getSecond(); + if (target.getSecond() == null) { + screen = null; + vanillaScreen = null; + return; + } + MetaMachine targetMachine = MetaMachine.getMachine(target.getFirst(), target.getSecond()); + if (targetMachine != null && + (targetMachine.getDefinition().getUI() != null || targetMachine instanceof IMuiMachine)) { + GuiManager.openFromClient(MachineUIFactory.INSTANCE, + new PosGuiData(MCHelper.getPlayer(), target.getSecond()), true); + } else { + screen = null; + vanillaScreen = null; + } + } + + @SubscribeEvent + public void openClientInWorldUI(InWorldMUIOpenEvent event) { + if (this.targetPos != null && event.getGuiData() instanceof PosGuiData posGuiData) { + if (posGuiData.getBlockPos().asLong() == targetPos.asLong() && posGuiData.getLevel() == targetLevel) { + this.screen = event.getScreen(); + this.vanillaScreen = event.getVanillaScreen(); + this.vanillaScreen.init(MCHelper.getMc(), this.width, this.height); + this.screen.onResize(this.width, this.height); + ModularPanel mainPanel = this.screen.getMainPanel(); + for (IWidget child : mainPanel.getChildren()) { + if (child instanceof SlotGroupWidget slotGroupWidget && slotGroupWidget.isPlayerInventory()) { + slotGroupWidget.disabled(); + mainPanel.height(mainPanel.getArea().height - slotGroupWidget.getArea().height); + mainPanel.scheduleResize(); + } + } + } + } + } + + @SubscribeEvent + public void keyPressedEvent(EarlyKeyPressEvent event) { + if (mouseX < 0 || mouseX > width || mouseY < 0 || mouseY > height || MCHelper.getCurrentScreen() != null) + return; + screen.getContext().updateLatestKey(event.getKey(), event.getScanCode(), event.getModifiers()); + boolean early = ClientScreenHandler.handleKeyboardInput(screen, vanillaScreen, + event.getAction() == InputConstants.PRESS, + ClientScreenHandler.InputPhase.EARLY, event.getKey(), event.getScanCode(), event.getModifiers()); + if (early) event.setCanceled(true); + else { + boolean late = ClientScreenHandler.handleKeyboardInput(screen, vanillaScreen, + event.getAction() == InputConstants.PRESS, + ClientScreenHandler.InputPhase.LATE, event.getKey(), event.getScanCode(), event.getModifiers()); + if (late) event.setCanceled(true); + } + } + + @SubscribeEvent + public void charTyped(CharTypedEvent event) { + if (mouseX < 0 || mouseX > width || mouseY < 0 || mouseY > height || MCHelper.getCurrentScreen() != null) + return; + screen.getContext().updateLatestTypedChar(event.getCodepoint(), event.getModifiers()); + if (screen.charTyped(event.getCodepoint(), event.getModifiers())) event.setCanceled(true); + } + + @SubscribeEvent + public void onInWorldGuiRender(InWorldMUIRenderEvent event) { + renderGuiToBuffer(event.getGraphics(), event.getPartialTick()); + } + + @SuppressWarnings("UnstableApiUsage") + public void renderGuiToBuffer(GuiGraphics guiGraphics, float partialTick) { + if (screen == null || MCHelper.getPlayer() == null) return; + screen.getContext().setGraphics(guiGraphics); + screen.onFrameUpdate(); + AnimatorManager.INSTANCE.onDraw(null); + if (width * height == 0) return; + if (renderTarget.width != RESOLUTION_COEF * width || renderTarget.height != RESOLUTION_COEF * height) + renderTarget.resize(RESOLUTION_COEF * width, RESOLUTION_COEF * height, Minecraft.ON_OSX); + renderTarget.enableStencil(); + renderTarget.clear(Minecraft.ON_OSX); + + renderTarget.bindWrite(true); + + RenderSystem.clear(256, Minecraft.ON_OSX); + Matrix4f matrix4f = new Matrix4f().setOrtho(0.0F, RESOLUTION_COEF * width, RESOLUTION_COEF * height, 0.0F, + 1000.0F, + ForgeHooksClient.getGuiFarPlane()); + RenderSystem.setProjectionMatrix(matrix4f, VertexSorting.ORTHOGRAPHIC_Z); + PoseStack posestack = RenderSystem.getModelViewStack(); + posestack.pushPose(); + posestack.setIdentity(); + posestack.translate(0.0D, 0.0D, 1000F - ForgeHooksClient.getGuiFarPlane()); + posestack.scale(RESOLUTION_COEF, RESOLUTION_COEF, RESOLUTION_COEF); + RenderSystem.applyModelViewMatrix(); + + ClientScreenHandler.drawScreen(guiGraphics, screen, vanillaScreen, mouseX, mouseY, partialTick); + ClientScreenHandler.drawDebugScreen(guiGraphics, screen, screen); + + posestack.popPose(); + RenderSystem.applyModelViewMatrix(); + + renderTarget.unbindWrite(); + Minecraft.getInstance().getMainRenderTarget().bindWrite(true); + } + + public void renderGui(int maxWidth, int maxHeight, PoseStack poseStack, MultiBufferSource buffer, + float partialTick, int mouseX, int mouseY) { + poseStack.scale(1 / 256f, 1 / 256f, 1 / 256e3f); + boolean resized = false; + if (maxWidth * 256 != width) { + width = maxWidth * 256; + resized = true; + } + if (maxHeight * 256 != height) { + height = maxHeight * 256; + resized = true; + } + if (resized) screen.onResize(width, height); + screen.getContext().updateState(mouseX, mouseY, partialTick); + screen.onFrameUpdate(); + AnimatorManager.INSTANCE.onDraw(null); + if (width * height == 0) return; + RenderSystem.setShaderTexture(0, renderTarget.getColorTextureId()); + ShaderInstance shaderInstance = MCHelper.getMc().gameRenderer.blitShader; + shaderInstance.setSampler("DiffuseSampler", renderTarget.getColorTextureId()); + ((IGameRenderer) MCHelper.getMc().gameRenderer).gtceu$bob(poseStack, partialTick); + Matrix4f pose = poseStack.last().pose(); + double fov = ((IGameRenderer) MCHelper.getMc().gameRenderer).gtceu$getFov(partialTick); + if (shaderInstance.PROJECTION_MATRIX != null) + shaderInstance.PROJECTION_MATRIX.set(MCHelper.getMc().gameRenderer.getProjectionMatrix(fov)); + + if (shaderInstance.MODEL_VIEW_MATRIX != null) shaderInstance.MODEL_VIEW_MATRIX.set(pose); + shaderInstance.apply(); + Tesselator tesselator = RenderSystem.renderThreadTesselator(); + BufferBuilder bufferbuilder = tesselator.getBuilder(); + bufferbuilder.begin(VertexFormat.Mode.QUADS, DefaultVertexFormat.POSITION_TEX_COLOR); + bufferbuilder.vertex(0.0D, height, 0.0D).uv(0.0F, 0.0F).color(255, 255, 255, 255).endVertex(); + bufferbuilder.vertex(width, height, 0.0D).uv(1, 0.0F).color(255, 255, 255, 255).endVertex(); + bufferbuilder.vertex(width, 0.0D, 0.0D).uv(1, 1).color(255, 255, 255, 255).endVertex(); + bufferbuilder.vertex(0.0D, 0.0D, 0.0D).uv(0.0F, 1).color(255, 255, 255, 255).endVertex(); + BufferUploader.draw(bufferbuilder.end()); + shaderInstance.clear(); + } + + @Override + public void render(CentralMonitorMachine machine, MonitorGroup group, float partialTick, PoseStack poseStack, + MultiBufferSource buffer, int packedLight, int packedOverlay) { + if (screen == null || group.isEmpty()) return; + BlockPos rel = group.getRow(0, machine::toRelative).get(0); + BlockPos size = GTUtil.getLast(group.getRow(-1, machine::toRelative)) + .offset(-rel.getX() + 1, -rel.getY() + 1, -rel.getZ() + 1); + poseStack.translate(rel.getX(), rel.getY(), rel.getZ()); + Player player = MCHelper.getPlayer(); + HitResult hit = player.pick(player.getAttributeValue(ForgeMod.BLOCK_REACH.get()), partialTick, false); + double mouseX = -1, mouseY = -1; + if (hit instanceof BlockHitResult blockHit) { + BlockPos pos = blockHit.getBlockPos(); + BlockPos relPos = machine.toRelative(pos); + if (MetaMachine.getMachine(player.level(), pos) instanceof MonitorPartMachine monitor) { + Vector2d monitorMousePos = monitor.getMousePos(hit); + mouseX = relPos.getX() - rel.getX() + monitorMousePos.x(); + mouseY = relPos.getY() - rel.getY() + 1 - monitorMousePos.y(); + if (monitor instanceof AdvancedMonitorPartMachine advancedMonitor && mouseX >= 0 && mouseY >= 0 && + mouseX <= width && mouseY <= height) { + if (advancedMonitor.isClickedThisFrame()) { + this.screen.onMousePressed(mouseX * 256, mouseY * 256, GLFW.GLFW_MOUSE_BUTTON_LEFT); + this.vanillaScreen.mouseClicked(mouseX * 256, mouseY * 256, GLFW.GLFW_MOUSE_BUTTON_LEFT); + advancedMonitor.setClickedThisFrame(false); + } + } + } + } + if (mouseX >= 0 && mouseY >= 0 && mouseX * 256 <= width && mouseY * 256 <= height) { + this.mouseX = (int) (mouseX * 256); + this.mouseY = (int) (mouseY * 256); + } + renderGui(size.getX(), size.getY(), poseStack, buffer, partialTick, (int) (mouseX * 256), (int) (mouseY * 256)); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/common/data/GTItems.java b/src/main/java/com/gregtechceu/gtceu/common/data/GTItems.java index 424ac52beee..a2e82103927 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/data/GTItems.java +++ b/src/main/java/com/gregtechceu/gtceu/common/data/GTItems.java @@ -26,6 +26,7 @@ import com.gregtechceu.gtceu.common.entity.GTBoat; import com.gregtechceu.gtceu.common.item.*; import com.gregtechceu.gtceu.common.item.armor.*; +import com.gregtechceu.gtceu.common.item.modules.GuiModuleBehaviour; import com.gregtechceu.gtceu.common.item.modules.ImageModuleBehaviour; import com.gregtechceu.gtceu.common.item.modules.TextModuleBehaviour; import com.gregtechceu.gtceu.common.item.tool.behavior.LighterBehavior; @@ -2553,6 +2554,10 @@ public static ItemEntry createFluidCell(Material mat, int capacit .onRegister(attach(new ImageModuleBehaviour())) .register(); + public static ItemEntry GUI_MODULE = REGISTRATE.item("gui_module", ComponentItem::create) + .onRegister(attach(new GuiModuleBehaviour())) + .register(); + public static void init() { GTMaterialItems.generateMaterialItems(); GTMaterialItems.generateTools(); diff --git a/src/main/java/com/gregtechceu/gtceu/common/item/modules/GuiModuleBehaviour.java b/src/main/java/com/gregtechceu/gtceu/common/item/modules/GuiModuleBehaviour.java new file mode 100644 index 00000000000..908b241f6cd --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/common/item/modules/GuiModuleBehaviour.java @@ -0,0 +1,43 @@ +package com.gregtechceu.gtceu.common.item.modules; + +import com.gregtechceu.gtceu.api.item.component.IMonitorModuleItem; +import com.gregtechceu.gtceu.api.mui.base.IPanelHandler; +import com.gregtechceu.gtceu.api.mui.base.drawable.IKey; +import com.gregtechceu.gtceu.api.mui.value.sync.PanelSyncManager; +import com.gregtechceu.gtceu.api.mui.widgets.TextWidget; +import com.gregtechceu.gtceu.client.mui.screen.ModularPanel; +import com.gregtechceu.gtceu.client.renderer.monitor.IMonitorRenderer; +import com.gregtechceu.gtceu.client.renderer.monitor.MonitorGuiRenderer; +import com.gregtechceu.gtceu.common.machine.multiblock.electric.CentralMonitorMachine; +import com.gregtechceu.gtceu.common.machine.multiblock.electric.monitor.MonitorGroup; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; + +import com.mojang.datafixers.util.Pair; + +import java.util.HashMap; +import java.util.Map; + +public class GuiModuleBehaviour implements IMonitorModuleItem { + + private final Map, MonitorGuiRenderer> renderers = new HashMap<>(); + + @Override + public IMonitorRenderer getRenderer(ItemStack stack, CentralMonitorMachine machine, MonitorGroup group) { + return renderers.computeIfAbsent( + Pair.of(group.getTargetLevel(machine.getLevel()), group.getTarget(machine.getLevel())), + MonitorGuiRenderer::new); + } + + @Override + public ModularPanel createModularPanel(ItemStack stack, CentralMonitorMachine machine, MonitorGroup group, + PanelSyncManager syncManager, IPanelHandler panelHandler) { + return new ModularPanel("gui_module_info") + .coverChildren() + .child(new TextWidget<>(IKey.lang("gtceu.gui.central_monitor.gui_module_info")) + .height(50) + .width(200)); + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/common/item/modules/ImageModuleBehaviour.java b/src/main/java/com/gregtechceu/gtceu/common/item/modules/ImageModuleBehaviour.java index fd560be54a5..a9e4bfffd59 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/item/modules/ImageModuleBehaviour.java +++ b/src/main/java/com/gregtechceu/gtceu/common/item/modules/ImageModuleBehaviour.java @@ -1,18 +1,19 @@ package com.gregtechceu.gtceu.common.item.modules; -import com.gregtechceu.gtceu.api.gui.GuiTextures; import com.gregtechceu.gtceu.api.item.component.IMonitorModuleItem; +import com.gregtechceu.gtceu.api.mui.base.IPanelHandler; +import com.gregtechceu.gtceu.api.mui.base.drawable.IKey; +import com.gregtechceu.gtceu.api.mui.utils.Alignment; +import com.gregtechceu.gtceu.api.mui.value.sync.PanelSyncManager; +import com.gregtechceu.gtceu.api.mui.value.sync.SyncHandlers; +import com.gregtechceu.gtceu.api.mui.widgets.TextWidget; +import com.gregtechceu.gtceu.api.mui.widgets.layout.Flow; +import com.gregtechceu.gtceu.api.mui.widgets.textfield.TextFieldWidget; +import com.gregtechceu.gtceu.client.mui.screen.ModularPanel; import com.gregtechceu.gtceu.client.renderer.monitor.IMonitorRenderer; import com.gregtechceu.gtceu.client.renderer.monitor.MonitorImageRenderer; import com.gregtechceu.gtceu.common.machine.multiblock.electric.CentralMonitorMachine; import com.gregtechceu.gtceu.common.machine.multiblock.electric.monitor.MonitorGroup; -import com.gregtechceu.gtceu.common.network.GTNetwork; -import com.gregtechceu.gtceu.common.network.packets.SCPacketMonitorGroupNBTChange; - -import com.lowdragmc.lowdraglib.gui.widget.ButtonWidget; -import com.lowdragmc.lowdraglib.gui.widget.TextFieldWidget; -import com.lowdragmc.lowdraglib.gui.widget.Widget; -import com.lowdragmc.lowdraglib.gui.widget.WidgetGroup; import net.minecraft.world.item.ItemStack; @@ -24,21 +25,19 @@ public IMonitorRenderer getRenderer(ItemStack stack, CentralMonitorMachine machi } @Override - public Widget createUIWidget(ItemStack stack, CentralMonitorMachine machine, MonitorGroup group) { - WidgetGroup builder = new WidgetGroup(); - TextFieldWidget textField = new TextFieldWidget(0, 0, 100, 10, null, null); - textField.setCurrentString(getUrl(stack)); - - ButtonWidget saveButton = new ButtonWidget(-40, 22, 20, 20, click -> { - if (!click.isRemote) return; - - setUrl(stack, textField.getCurrentString()); - GTNetwork.sendToServer(new SCPacketMonitorGroupNBTChange(stack, group, machine)); - }); - saveButton.setButtonTexture(GuiTextures.BUTTON_CHECK); - builder.addWidget(textField); - builder.addWidget(saveButton); - return builder; + public ModularPanel createModularPanel(ItemStack stack, CentralMonitorMachine machine, MonitorGroup group, + PanelSyncManager syncManager, IPanelHandler panelHandler) { + return new ModularPanel("image_module_editor") + .size(200, 50) + .child(Flow.column() + .marginTop(5) + .align(Alignment.CENTER) + .widthRel(1) + .child(new TextWidget<>(IKey.lang("gtceu.gui.central_monitor.url"))) + .child(new TextFieldWidget() + .value(SyncHandlers.string(() -> getUrl(stack), s -> setUrl(stack, s))) + .align(Alignment.CENTER) + .widthRel(.8f))); } @Override diff --git a/src/main/java/com/gregtechceu/gtceu/common/item/modules/TextModuleBehaviour.java b/src/main/java/com/gregtechceu/gtceu/common/item/modules/TextModuleBehaviour.java index d745051fe54..d9bfff4be67 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/item/modules/TextModuleBehaviour.java +++ b/src/main/java/com/gregtechceu/gtceu/common/item/modules/TextModuleBehaviour.java @@ -1,41 +1,31 @@ package com.gregtechceu.gtceu.common.item.modules; -import com.gregtechceu.gtceu.api.gui.GuiTextures; import com.gregtechceu.gtceu.api.item.component.IAddInformation; import com.gregtechceu.gtceu.api.item.component.IMonitorModuleItem; +import com.gregtechceu.gtceu.api.mui.base.IPanelHandler; +import com.gregtechceu.gtceu.api.mui.value.sync.PanelSyncManager; import com.gregtechceu.gtceu.api.placeholder.MultiLineComponent; import com.gregtechceu.gtceu.api.placeholder.PlaceholderContext; import com.gregtechceu.gtceu.api.placeholder.PlaceholderHandler; +import com.gregtechceu.gtceu.client.mui.screen.ModularPanel; import com.gregtechceu.gtceu.client.renderer.monitor.IMonitorRenderer; import com.gregtechceu.gtceu.client.renderer.monitor.MonitorTextRenderer; import com.gregtechceu.gtceu.common.machine.multiblock.electric.CentralMonitorMachine; import com.gregtechceu.gtceu.common.machine.multiblock.electric.monitor.MonitorGroup; -import com.gregtechceu.gtceu.common.network.GTNetwork; -import com.gregtechceu.gtceu.common.network.packets.SCPacketMonitorGroupNBTChange; - -import com.lowdragmc.lowdraglib.gui.widget.ButtonWidget; -import com.lowdragmc.lowdraglib.gui.widget.TextFieldWidget; -import com.lowdragmc.lowdraglib.gui.widget.Widget; -import com.lowdragmc.lowdraglib.gui.widget.WidgetGroup; -import com.lowdragmc.lowdraglib.gui.widget.codeeditor.CodeEditorWidget; import net.minecraft.ChatFormatting; -import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.ListTag; import net.minecraft.nbt.StringTag; import net.minecraft.nbt.Tag; import net.minecraft.network.chat.Component; -import net.minecraft.util.Mth; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.TooltipFlag; import net.minecraft.world.level.Level; import org.jetbrains.annotations.Nullable; -import java.util.ArrayList; import java.util.List; import java.util.UUID; -import java.util.function.Supplier; public class TextModuleBehaviour implements IMonitorModuleItem, IAddInformation { @@ -69,52 +59,12 @@ public IMonitorRenderer getRenderer(ItemStack stack, CentralMonitorMachine machi } @Override - public Widget createUIWidget(ItemStack stack, CentralMonitorMachine machine, MonitorGroup group) { - WidgetGroup builder = new WidgetGroup(); - CodeEditorWidget editor = new CodeEditorWidget(0, 0, 120, 80); - // editor.codeEditor.setLanguageDefinition(PlaceholderHandler.LANG_DEFINITION); - TextFieldWidget scaleInput = new TextFieldWidget( - -50, 47, - 40, 10, - null, - null); - ButtonWidget saveButton = new ButtonWidget(-40, 22, 20, 20, click -> { - if (!click.isRemote) return; - ListTag listTag = new ListTag(); - editor.getLines().forEach(line -> listTag.add(StringTag.valueOf(line))); - CompoundTag tag2 = stack.getOrCreateTag(); - tag2.put("formatStringLines", listTag); - try { - tag2.putDouble("scale", Double.parseDouble(scaleInput.getCurrentString())); - } catch (NumberFormatException ignored) {} - stack.setTag(tag2); - GTNetwork.sendToServer(new SCPacketMonitorGroupNBTChange(stack, group, machine)); - }); - saveButton.setButtonTexture(GuiTextures.BUTTON_CHECK); - List tmp = new ArrayList<>(); - Supplier scaleInputSupplier = () -> { - if (tmp.isEmpty()) tmp.add(true); - else scaleInput.setTextSupplier(null); - if (!stack.getOrCreateTag().contains("scale")) { - stack.getOrCreateTag().putDouble("scale", 1); - GTNetwork.sendToServer(new SCPacketMonitorGroupNBTChange(stack, group, machine)); - return "1"; - } - return String.valueOf(Mth.clamp(stack.getOrCreateTag().getDouble("scale"), .0001, 1000)); - }; - scaleInput.setTextSupplier(scaleInputSupplier); - scaleInput.setHoverTooltips(Component.translatable("gtceu.gui.central_monitor.text_scale")); - ListTag tag = stack.getOrCreateTag().getList("formatStringLines", Tag.TAG_STRING); - List formatStringLines = new ArrayList<>(); - for (Tag line : tag) formatStringLines.add(line.getAsString()); - editor.setLines(formatStringLines); - builder.addWidget(editor); - builder.addWidget(saveButton); - Widget placeholderReference = PlaceholderHandler.getPlaceholderHandlerUI(""); - builder.addWidget(scaleInput); - placeholderReference.setSelfPosition(-100, -50); - builder.addWidget(placeholderReference); - return builder; + public ModularPanel createModularPanel(ItemStack stack, CentralMonitorMachine machine, MonitorGroup group, + PanelSyncManager syncManager, IPanelHandler panelHandler) { + return new ModularPanel("placeholder_editor") + .size(400, 250) + .resizeableOnDrag(true) + .excludeAreaInXei(); } @Override diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CentralMonitorMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CentralMonitorMachine.java index feb3174f190..32d3ece4d5d 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CentralMonitorMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/electric/CentralMonitorMachine.java @@ -6,8 +6,6 @@ import com.gregtechceu.gtceu.api.capability.IMonitorComponent; import com.gregtechceu.gtceu.api.capability.recipe.IO; import com.gregtechceu.gtceu.api.gui.GuiTextures; -import com.gregtechceu.gtceu.api.gui.widget.IntInputWidget; -import com.gregtechceu.gtceu.api.gui.widget.SlotWidget; import com.gregtechceu.gtceu.api.item.IComponentItem; import com.gregtechceu.gtceu.api.item.component.IItemComponent; import com.gregtechceu.gtceu.api.item.component.IMonitorModuleItem; @@ -28,12 +26,9 @@ import com.gregtechceu.gtceu.common.machine.trait.CentralMonitorLogic; import com.gregtechceu.gtceu.common.network.GTNetwork; import com.gregtechceu.gtceu.common.network.packets.SCPacketMonitorGroupNBTChange; -import com.gregtechceu.gtceu.data.lang.LangHandler; import com.gregtechceu.gtceu.syncsystem.annotations.RerenderOnChanged; import com.gregtechceu.gtceu.syncsystem.annotations.SaveField; import com.gregtechceu.gtceu.syncsystem.annotations.SyncToClient; -import com.gregtechceu.gtceu.utils.GTStringUtils; -import com.gregtechceu.gtceu.utils.GTUtil; import com.lowdragmc.lowdraglib.gui.texture.*; import com.lowdragmc.lowdraglib.gui.widget.*; @@ -42,11 +37,9 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.network.chat.Component; -import net.minecraft.util.Mth; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; import net.minecraft.world.level.Level; -import net.minecraftforge.items.IItemHandler; import lombok.Getter; import org.jetbrains.annotations.NotNull; @@ -55,7 +48,6 @@ import java.awt.*; import java.util.*; import java.util.List; -import java.util.function.Consumer; import java.util.stream.Stream; import javax.annotation.ParametersAreNonnullByDefault; @@ -316,345 +308,6 @@ public void addDisplayText(List textList) { getDefinition().getAdditionalDisplay().accept(this, textList); } - @Override - public Widget createUIWidget() { - updateStructureDimensions(); - selectedComponents.clear(); - WidgetGroup builder = (WidgetGroup) super.createUIWidget(); - - WidgetGroup main = new WidgetGroup(); - DraggableScrollableWidgetGroup componentSelection = new DraggableScrollableWidgetGroup(0, 10, 200, 110); - main.addWidget(componentSelection); - WidgetGroup options = new WidgetGroup(-100, 20, 60, 20); - WidgetGroup groupConfig = new WidgetGroup(10, 30, 100, 100); - groupConfig.setVisible(false); - - ButtonWidget infoWidget = new ButtonWidget(200, 10, 20, 20, null); - infoWidget.setButtonTexture(GuiTextures.INFO_ICON); - infoWidget.setHoverTooltips( - GTStringUtils.toImmutable(LangHandler.getSingleOrMultiLang("gtceu.central_monitor.info_tooltip"))); - builder.addWidget(infoWidget); - List configGroup = new ArrayList<>(); - configGroup.add(null); - - Consumer openGroupConfig = (group) -> { - configGroup.set(0, group); - if (group == null) { - main.setVisible(true); - groupConfig.setVisible(false); - return; - } - groupConfig.clearAllWidgets(); - groupConfig.addWidget(new LabelWidget(0, 5, () -> { - String currentName = ""; - if (configGroup.get(0) != null) { - currentName = configGroup.get(0).getName(); - } - return Component.translatable("gtceu.central_monitor.gui.currently_editing", currentName).getString(); - })); - for (int i = 0; i < 8; i++) { - SlotWidget slot = new SlotWidget(group.getPlaceholderSlotsHandler(), i, -38, 16 * i + 46); - slot.setHoverTooltips(GTStringUtils - .toImmutable(LangHandler.getMultiLang("gtceu.gui.computer_monitor_cover.slot_tooltip", i + 1))); - groupConfig.addWidget(slot); - } - SlotWidget slot = new SlotWidget( - group.getItemStackHandler(), 0, - 0, 20); - WidgetGroup itemUI = new WidgetGroup(40, 20, 100, 100); - Runnable changeListener = () -> { - if (slot.getLastItem().is(slot.getItem().getItem())) return; - itemUI.clearAllWidgets(); - if (slot.getItem().getItem() instanceof IComponentItem item) { - for (IItemComponent component : item.getComponents()) { - if (component instanceof IMonitorModuleItem module) { - itemUI.addWidget(module.createUIWidget(slot.getItem(), this, group)); - } - } - } - }; - slot.setChangeListener(changeListener); - changeListener.run(); - groupConfig.addWidget(itemUI); - groupConfig.addWidget(slot); - main.setVisible(false); - groupConfig.setVisible(true); - }; - builder.addWidget(groupConfig); - DraggableScrollableWidgetGroup groupList = new DraggableScrollableWidgetGroup(-100, 50, 70, 80); - - List>>> imageButtons = new ArrayList<>(); - Map rightClickCallbacks = new HashMap<>(); - int[] dataSlot = new int[2]; // list to be able to modify it in lambdas - dataSlot[0] = 1; // the slot (index starts from 1) - dataSlot[1] = 9; // amount of slots - IntInputWidget dataSlotInput = new IntInputWidget(120, 20, 60, -20, () -> dataSlot[0], - n -> dataSlot[0] = Mth.clamp(n, 1, dataSlot[1])); - dataSlotInput.setVisible(false); - builder.addWidget(dataSlotInput); - - Consumer addGroupToList = group -> { - ButtonWidget label = new ButtonWidget(20, groupList.widgets.size() * 15 + 5, 60, 10, null); - TextTexture text = new TextTexture(group.getName()); - text.setType(TextTexture.TextType.LEFT); - label.setButtonTexture(text); - label.setOnPressCallback(click -> { - group.getRelativePositions().forEach(pos -> { - BlockPos rel = toRelative(pos); - if (imageButtons.size() - 1 < rel.getY()) return; - if (imageButtons.get(rel.getY()).size() - 1 < rel.getX()) return; - imageButtons.get(rel.getY()).get(rel.getX()).accept(null); - }); - if (group.getTargetRaw() != null) { - rightClickCallbacks.getOrDefault(group.getTargetRaw(), () -> {}).run(); - } - }); - groupList.addWidget(label); - - ButtonWidget configButton = new ButtonWidget( - 0, label.getSelfPositionY() - 3, - 16, 16, - GuiTextures.IO_CONFIG_COVER_SETTINGS, - click -> { - if (configGroup.get(0) == null) { - openGroupConfig.accept(group); - } else { - openGroupConfig.accept(null); - } - }); - groupList.addWidget(configButton); - }; - - monitorGroups.forEach(addGroupToList); - builder.addWidget(groupList); - main.addWidget(options); - ButtonWidget removeFromGroupButton = new ButtonWidget(0, 0, 60, 20, null); - removeFromGroupButton.setButtonTexture(new TextTexture("gtceu.central_monitor.gui.remove_from_group")); - removeFromGroupButton.setVisible(false); - ButtonWidget setTargetButton = new ButtonWidget(0, 15, 60, 20, null); - setTargetButton.setButtonTexture(new TextTexture("gtceu.central_monitor.gui.set_target")); - setTargetButton.setVisible(false); - ButtonWidget createGroupButton = new ButtonWidget(0, 0, 60, 20, null); - createGroupButton.setOnPressCallback(click -> { - MonitorGroup group = new MonitorGroup( - Component.translatable("gtceu.gui.central_monitor.group_default_name", monitorGroups.size() + 1) - .getString()); - for (IMonitorComponent component : selectedComponents) { - if (isInAnyGroup(component)) return; - group.add(component.getPos()); - } - monitorGroups.add(group); - addGroupToList.accept(group); - - createGroupButton.setVisible(false); - removeFromGroupButton.setVisible(true); - Iterator it = selectedComponents.iterator(); - while (it.hasNext()) { - IMonitorComponent c = it.next(); - BlockPos rel = toRelative(c.getPos()); - imageButtons.get(rel.getY()).get(rel.getX()).accept(it); - } - if (!selectedTargets.isEmpty()) { - rightClickCallbacks.getOrDefault(selectedTargets.get(0).getPos(), () -> {}).run(); - } - }); - setTargetButton.setOnPressCallback(click -> { - MonitorGroup group = null; - for (MonitorGroup group2 : monitorGroups) { - for (IMonitorComponent component : selectedComponents) { - if (group2.contains(component.getPos())) { - group = group2; - break; - } - } - if (group != null) break; - } - if (group == null) return; - if (selectedTargets.isEmpty()) group.setTarget(null); - else { - group.setTarget(selectedTargets.get(0).getPos()); - group.setDataSlot(dataSlot[0] - 1); - } - }); - removeFromGroupButton.setOnPressCallback(click -> { - for (MonitorGroup group : monitorGroups) { - for (IMonitorComponent component : selectedComponents) group.remove(component.getPos()); - } - Iterator itg = monitorGroups.iterator(); - while (itg.hasNext()) { - MonitorGroup group = itg.next(); - if (group.isEmpty()) { - clearInventory(group.getItemStackHandler()); - clearInventory(group.getPlaceholderSlotsHandler()); - itg.remove(); - } - } - groupList.clearAllWidgets(); - monitorGroups.forEach(addGroupToList); - - removeFromGroupButton.setVisible(false); - createGroupButton.setVisible(true); - Iterator it = selectedComponents.iterator(); - while (it.hasNext()) { - IMonitorComponent c = it.next(); - BlockPos rel = toRelative(c.getPos()); - if (imageButtons.size() - 1 < rel.getY()) continue; - if (imageButtons.get(rel.getY()).size() - 1 < rel.getX()) continue; - imageButtons.get(rel.getY()).get(rel.getX()).accept(it); - } - if (!selectedTargets.isEmpty()) { - rightClickCallbacks.getOrDefault(selectedTargets.get(0).getPos(), () -> {}).run(); - } - }); - createGroupButton.setButtonTexture(new TextTexture("gtceu.central_monitor.gui.create_group")); - createGroupButton.setVisible(false); - options.addWidget(removeFromGroupButton); - options.addWidget(createGroupButton); - options.addWidget(setTargetButton); - int startX = 20; - int startY = 30; - for (int row = 0; row <= downDist + upDist; row++) { - imageButtons.add(new ArrayList<>()); - for (int col = 0; col <= leftDist + rightDist; col++) { - IGuiTexture texture = getComponentTexture(row, col); - GuiTextureGroup textures = new GuiTextureGroup(texture, new ColorBorderTexture(2, 0xFFFFFF)); - IMonitorComponent component = getComponent(row, col); - if (component == null) { - GTUtil.getLast(imageButtons).add(it -> {}); - continue; - } - ButtonWidget img = new ButtonWidget(startX + (16 * col), startY + (16 * row), 16, 16, textures, null); - Consumer> callback = (it) -> { - if (!component.isMonitor()) return; - if (selectedComponents.contains(component)) { - if (it == null) { - selectedComponents.remove(component); - } else { - it.remove(); - } - - if (!selectedTargets.isEmpty() && selectedTargets.get(0) == component) { - ColorRectTexture rect = new ColorRectTexture(Color.BLUE); - textures.setTextures(rect, texture); - } else { - textures.setTextures(texture); - } - - createGroupButton.setVisible(selectedComponents.stream().noneMatch(this::isInAnyGroup)); - removeFromGroupButton.setVisible(selectedComponents.stream().allMatch(this::isInAnyGroup)); - setTargetButton.setVisible(removeFromGroupButton.isVisible()); - - if (selectedComponents.isEmpty()) { - createGroupButton.setVisible(false); - removeFromGroupButton.setVisible(false); - setTargetButton.setVisible(false); - } - } else { - boolean inAnyGroup = isInAnyGroup(component); - // yes I know this is terrible but if it works don't touch it :) - if (selectedComponents.isEmpty() && !inAnyGroup) createGroupButton.setVisible(true); - if (inAnyGroup) createGroupButton.setVisible(false); - if (selectedComponents.isEmpty() && inAnyGroup) { - removeFromGroupButton.setVisible(true); - setTargetButton.setVisible(true); - } - if (!inAnyGroup) { - removeFromGroupButton.setVisible(false); - setTargetButton.setVisible(false); - } - selectedComponents.add(component); - ColorRectTexture rect = new ColorRectTexture( - (selectedTargets.isEmpty() || selectedTargets.get(0) != component) ? Color.RED : - Color.PINK); - textures.setTextures(rect, texture); - } - if (isInAnyGroup(component)) { - monitorGroups.forEach(group -> { - if (group.contains(component.getPos())) { - img.setHoverTooltips( - Component.translatable("gtceu.gui.central_monitor.group", group.getName())); - } - }); - } else { - img.setHoverTooltips(Component.translatable("gtceu.gui.central_monitor.group", - Component.translatable("gtceu.gui.central_monitor.none"))); - } - }; - Runnable rightClickCallback = () -> { - if (!selectedTargets.isEmpty()) { - if (selectedTargets.get(0).getPos() == component.getPos()) { - selectedTargets.clear(); - if (selectedComponents.contains(component)) { - ColorRectTexture rect = new ColorRectTexture(Color.RED); - textures.setTextures(rect, texture); - } else { - textures.setTextures(texture); - } - dataSlotInput.setVisible(false); - return; - } else { - try { - rightClickCallbacks.get(selectedTargets.get(0).getPos()).run(); - } catch (StackOverflowError e) { - GTCEu.LOGGER.error( - "Stack overflow when right-clicking monitor component {} at {} (selectedTarget is {} at {})", - component, component.getPos(), selectedTargets.get(0), - selectedTargets.get(0).getPos()); - } - } - } - selectedTargets.add(component); - ColorRectTexture rect; - if (selectedComponents.contains(component)) { - rect = new ColorRectTexture(Color.PINK); - } else { - rect = new ColorRectTexture(Color.BLUE); - } - textures.setTextures(rect, texture); - if (component.getDataItems() != null) { - IItemHandler dataItems = component.getDataItems(); - MonitorGroup selectedGroup = null; - for (MonitorGroup group : monitorGroups) { - for (IMonitorComponent c : selectedComponents) { - if (group.contains(c.getPos())) { - if (selectedGroup == null || selectedGroup == group) { - selectedGroup = group; - } else { - selectedGroup = null; - break; - } - } - } - } - if (selectedGroup != null) { - dataSlot[0] = selectedGroup.getDataSlot() + 1; - } - dataSlot[1] = dataItems.getSlots(); - dataSlotInput.setVisible(true); - } - }; - if (isInAnyGroup(component)) { - monitorGroups.forEach(group -> { - if (group.contains(component.getPos())) img.setHoverTooltips( - Component.translatable("gtceu.gui.central_monitor.group", group.getName())); - }); - } else { - img.setHoverTooltips(Component.translatable("gtceu.gui.central_monitor.group", - Component.translatable("gtceu.gui.central_monitor.none"))); - } - img.setOnPressCallback(click -> { - if (click.button == 0) callback.accept(null); - else if (click.button == 1) rightClickCallback.run(); - }); - componentSelection.addWidget(img); - GTUtil.getLast(imageButtons).add(callback); - rightClickCallbacks.put(component.getPos(), rightClickCallback); - } - } - builder.addWidget(main); - return builder; - } - @Override public IGuiTexture getComponentIcon() { return ResourceTexture.fromSpirit(GTCEu.id("block/multiblock/network_switch/overlay_front_active")); diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/part/monitor/AdvancedMonitorPartMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/part/monitor/AdvancedMonitorPartMachine.java index 2954f696f20..fa4bdc53c4f 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/part/monitor/AdvancedMonitorPartMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/part/monitor/AdvancedMonitorPartMachine.java @@ -3,12 +3,10 @@ import com.gregtechceu.gtceu.api.machine.IMachineBlockEntity; import com.gregtechceu.gtceu.api.machine.TickableSubscription; import com.gregtechceu.gtceu.api.machine.feature.IInteractedMachine; -import com.gregtechceu.gtceu.api.pattern.util.RelativeDirection; import com.gregtechceu.gtceu.syncsystem.annotations.SaveField; import net.minecraft.MethodsReturnNonnullByDefault; import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.entity.player.Player; @@ -17,7 +15,9 @@ import net.minecraft.world.phys.BlockHitResult; import lombok.Getter; +import lombok.Setter; import org.jetbrains.annotations.Nullable; +import org.joml.Vector2d; @MethodsReturnNonnullByDefault public class AdvancedMonitorPartMachine extends MonitorPartMachine implements IInteractedMachine { @@ -34,6 +34,10 @@ public class AdvancedMonitorPartMachine extends MonitorPartMachine implements II @SaveField private boolean resetClickedNextTick = false; + @Getter + @Setter + private boolean clickedThisFrame = false; + @Nullable private TickableSubscription clickResetSubscription; @@ -47,14 +51,10 @@ public InteractionResult onUse(BlockState state, Level world, BlockPos pos, Play if (hit.getDirection() != getFrontFacing()) return IInteractedMachine.super.onUse(state, world, pos, player, hand, hit); clicked = true; - clickPosX = hit.getLocation() - .get(RelativeDirection.RIGHT.getRelative(getFrontFacing(), getUpwardsFacing(), false).getAxis()); - clickPosY = hit.getLocation() - .get(getFrontFacing().getAxis().isVertical() ? Direction.Axis.X : Direction.Axis.Y); - clickPosX -= Math.floor(clickPosX); - if (clickPosX < 0) clickPosX++; - clickPosY -= Math.floor(clickPosY); - if (clickPosY < 0) clickPosY++; + clickedThisFrame = true; + Vector2d clickPos = getMousePos(hit); + clickPosX = clickPos.x(); + clickPosY = clickPos.y(); return InteractionResult.SUCCESS; } diff --git a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/part/monitor/MonitorPartMachine.java b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/part/monitor/MonitorPartMachine.java index 4f999166910..35017bd20e0 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/part/monitor/MonitorPartMachine.java +++ b/src/main/java/com/gregtechceu/gtceu/common/machine/multiblock/part/monitor/MonitorPartMachine.java @@ -2,13 +2,18 @@ import com.gregtechceu.gtceu.GTCEu; import com.gregtechceu.gtceu.api.machine.IMachineBlockEntity; +import com.gregtechceu.gtceu.api.pattern.util.RelativeDirection; import com.lowdragmc.lowdraglib.gui.texture.IGuiTexture; import com.lowdragmc.lowdraglib.gui.texture.ResourceTexture; +import net.minecraft.core.Direction; import net.minecraft.world.InteractionHand; import net.minecraft.world.entity.player.Player; import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; + +import org.joml.Vector2d; public class MonitorPartMachine extends MonitorComponentPartMachine { @@ -30,4 +35,21 @@ public IGuiTexture getComponentIcon() { public boolean shouldOpenUI(Player player, InteractionHand hand, BlockHitResult hit) { return false; } + + public Vector2d getMousePos(HitResult hitResult) { + if (hitResult instanceof BlockHitResult hit) { + Direction direction = RelativeDirection.RIGHT.getRelative(getFrontFacing(), getUpwardsFacing(), false); + double x = hit.getLocation().get(direction.getAxis()); + if (direction.getAxisDirection().getStep() == 1) { + x = 1 - x; + } + double y = hit.getLocation() + .get(getFrontFacing().getAxis().isVertical() ? Direction.Axis.X : Direction.Axis.Y); + x -= Math.floor(x); + if (x < 0) x++; + y -= Math.floor(y); + if (y < 0) y++; + return new Vector2d(x, y); + } else return new Vector2d(); + } } diff --git a/src/main/java/com/gregtechceu/gtceu/common/network/GTNetwork.java b/src/main/java/com/gregtechceu/gtceu/common/network/GTNetwork.java index e5ba24e4c23..1083f2c81b4 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/network/GTNetwork.java +++ b/src/main/java/com/gregtechceu/gtceu/common/network/GTNetwork.java @@ -10,6 +10,8 @@ import com.gregtechceu.gtceu.common.network.packets.prospecting.SPacketProspectBedrockOre; import com.gregtechceu.gtceu.common.network.packets.prospecting.SPacketProspectOre; import com.gregtechceu.gtceu.common.network.packets.ui.*; +import com.gregtechceu.gtceu.common.network.packets.ui.OpenGuiPacket; +import com.gregtechceu.gtceu.common.network.packets.ui.SyncHandlerPacket; import com.gregtechceu.gtceu.syncsystem.network.SPacketUpdateBESyncValue; import net.minecraft.network.FriendlyByteBuf; @@ -126,6 +128,9 @@ public static void init() { register(OpenGuiPacket.class, OpenGuiPacket::new, null); register(SyncHandlerPacket.class, SyncHandlerPacket::new, null); + register(SContainerSetContent.class, SContainerSetContent::new, NetworkDirection.PLAY_TO_CLIENT); + register(SContainerSetData.class, SContainerSetData::new, NetworkDirection.PLAY_TO_CLIENT); + register(SContainerSetSlot.class, SContainerSetSlot::new, NetworkDirection.PLAY_TO_CLIENT); register(CloseAllGuiPacket.class, CloseAllGuiPacket::new, null); register(CloseGuiPacket.class, CloseGuiPacket::new, null); register(ReopenGuiPacket.class, ReopenGuiPacket::new, null); diff --git a/src/main/java/com/gregtechceu/gtceu/common/network/InWorldContainerSynchronizer.java b/src/main/java/com/gregtechceu/gtceu/common/network/InWorldContainerSynchronizer.java new file mode 100644 index 00000000000..a56c725bba3 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/common/network/InWorldContainerSynchronizer.java @@ -0,0 +1,60 @@ +package com.gregtechceu.gtceu.common.network; + +import com.gregtechceu.gtceu.client.mui.screen.ModularContainerMenu; +import com.gregtechceu.gtceu.common.network.packets.ui.SContainerSetContent; +import com.gregtechceu.gtceu.common.network.packets.ui.SContainerSetData; +import com.gregtechceu.gtceu.common.network.packets.ui.SContainerSetSlot; + +import net.minecraft.core.NonNullList; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.inventory.ContainerSynchronizer; +import net.minecraft.world.item.ItemStack; + +import org.jetbrains.annotations.NotNull; + +public class InWorldContainerSynchronizer implements ContainerSynchronizer { + + private final ServerPlayer player; + + public InWorldContainerSynchronizer(ServerPlayer player) { + this.player = player; + } + + @Override + public void sendInitialData(@NotNull AbstractContainerMenu container, @NotNull NonNullList items, + @NotNull ItemStack carriedItem, int @NotNull [] initialData) { + GTNetwork.sendToPlayer(player, new SContainerSetContent(getInWorldId(container), + container.incrementStateId(), items, carriedItem)); + + for (int i = 0; i < initialData.length; ++i) { + this.broadcastDataValue(container, i, initialData[i]); + } + } + + @Override + public void sendSlotChange(@NotNull AbstractContainerMenu container, int slot, @NotNull ItemStack itemStack) { + GTNetwork.sendToPlayer(player, + new SContainerSetSlot(getInWorldId(container), container.incrementStateId(), slot, itemStack)); + } + + @Override + public void sendCarriedChange(@NotNull AbstractContainerMenu containerMenu, @NotNull ItemStack stack) { + GTNetwork.sendToPlayer(player, + new SContainerSetSlot(getInWorldId(containerMenu), containerMenu.incrementStateId(), -1, stack)); + } + + @Override + public void sendDataChange(@NotNull AbstractContainerMenu container, int id, int value) { + this.broadcastDataValue(container, id, value); + } + + private void broadcastDataValue(AbstractContainerMenu container, int id, int value) { + GTNetwork.sendToPlayer(player, new SContainerSetData(getInWorldId(container), id, value)); + } + + private int getInWorldId(AbstractContainerMenu container) { + if (container instanceof ModularContainerMenu modularContainer) return modularContainer.inWorldID; + return -1; + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/common/network/ModularNetworkSide.java b/src/main/java/com/gregtechceu/gtceu/common/network/ModularNetworkSide.java index deb91835105..9abfa82ac5d 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/network/ModularNetworkSide.java +++ b/src/main/java/com/gregtechceu/gtceu/common/network/ModularNetworkSide.java @@ -82,7 +82,8 @@ public void sendSyncHandlerPacket(String panel, SyncHandler syncHandler, Friendl ModularSyncManager msm = syncHandler.getSyncManager().getModularSyncManager(); if (!inverseActiveScreens.containsKey(msm)) return; int id = inverseActiveScreens.getInt(msm); - sendPacket(new SyncHandlerPacket(id, panel, syncHandler.getKey(), false, buffer), player); + sendPacket(new SyncHandlerPacket(msm.getMenu().inWorldID, id, panel, syncHandler.getKey(), false, buffer), + player); } @ApiStatus.Internal @@ -90,7 +91,7 @@ public void sendActionPacket(ModularSyncManager msm, String panel, String key, F Player player) { if (!inverseActiveScreens.containsKey(msm)) return; int id = inverseActiveScreens.getInt(msm); - sendPacket(new SyncHandlerPacket(id, panel, key, true, buffer), player); + sendPacket(new SyncHandlerPacket(msm.getMenu().inWorldID, id, panel, key, true, buffer), player); } @ApiStatus.Internal diff --git a/src/main/java/com/gregtechceu/gtceu/common/network/packets/ui/OpenGuiPacket.java b/src/main/java/com/gregtechceu/gtceu/common/network/packets/ui/OpenGuiPacket.java index 222b3cbd008..5ad0bbb74ce 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/network/packets/ui/OpenGuiPacket.java +++ b/src/main/java/com/gregtechceu/gtceu/common/network/packets/ui/OpenGuiPacket.java @@ -22,9 +22,11 @@ public class OpenGuiPacket implements GTNetwork.INetPacket { private int networkId; private UIFactory factory; private FriendlyByteBuf data; + private boolean inWorldUI; public OpenGuiPacket(FriendlyByteBuf buf) { this.windowId = buf.readVarInt(); + this.inWorldUI = buf.readBoolean(); this.networkId = buf.readVarInt(); this.factory = (UIFactory) GuiManager.getFactory(buf.readResourceLocation()); this.data = NetworkUtils.readFriendlyByteBuf(buf); @@ -33,6 +35,7 @@ public OpenGuiPacket(FriendlyByteBuf buf) { @Override public void encode(FriendlyByteBuf buf) { buf.writeVarInt(this.windowId); + buf.writeBoolean(this.inWorldUI); buf.writeVarInt(this.networkId); buf.writeResourceLocation(this.factory.getFactoryName()); NetworkUtils.writeByteBuf(buf, this.data); @@ -41,11 +44,11 @@ public void encode(FriendlyByteBuf buf) { @Override public void execute(NetworkEvent.Context handler) { if (handler.getDirection() == NetworkDirection.PLAY_TO_CLIENT) { - GuiManager.openFromClient(this.windowId, this.networkId, this.factory, this.data, + GuiManager.openFromClient(this.windowId, this.networkId, this.inWorldUI, this.factory, this.data, Minecraft.getInstance().player); } else if (handler.getDirection() == NetworkDirection.PLAY_TO_SERVER) { T guiData = this.factory.readGuiData(handler.getSender(), this.data); - GuiManager.open(this.factory, guiData, handler.getSender()); + GuiManager.open(this.factory, this.inWorldUI, guiData, handler.getSender()); } } } diff --git a/src/main/java/com/gregtechceu/gtceu/common/network/packets/ui/SContainerSetContent.java b/src/main/java/com/gregtechceu/gtceu/common/network/packets/ui/SContainerSetContent.java new file mode 100644 index 00000000000..03ad0d5ebd1 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/common/network/packets/ui/SContainerSetContent.java @@ -0,0 +1,45 @@ +package com.gregtechceu.gtceu.common.network.packets.ui; + +import com.gregtechceu.gtceu.api.mui.factory.GuiManager; +import com.gregtechceu.gtceu.client.mui.screen.ModularContainerMenu; +import com.gregtechceu.gtceu.common.network.GTNetwork; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.network.NetworkEvent; + +import lombok.AllArgsConstructor; + +import java.util.List; + +@AllArgsConstructor +public class SContainerSetContent implements GTNetwork.INetPacket { + + private int inWorldId; + private int stateId; + private List items; + private ItemStack carriedItem; + + public SContainerSetContent(FriendlyByteBuf buf) { + this.inWorldId = buf.readVarInt(); + this.stateId = buf.readVarInt(); + this.items = buf.readList(FriendlyByteBuf::readItem); + this.carriedItem = buf.readItem(); + } + + @Override + public void encode(FriendlyByteBuf buffer) { + buffer.writeVarInt(this.inWorldId); + buffer.writeVarInt(this.stateId); + buffer.writeCollection(this.items, FriendlyByteBuf::writeItem); + buffer.writeItem(carriedItem); + } + + @Override + public void execute(NetworkEvent.Context context) { + ModularContainerMenu menu = GuiManager.getClientInWorldMenu(this.inWorldId); + if (menu != null) { + menu.initializeContents(this.stateId, this.items, this.carriedItem); + } + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/common/network/packets/ui/SContainerSetData.java b/src/main/java/com/gregtechceu/gtceu/common/network/packets/ui/SContainerSetData.java new file mode 100644 index 00000000000..cf0e83a69a0 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/common/network/packets/ui/SContainerSetData.java @@ -0,0 +1,39 @@ +package com.gregtechceu.gtceu.common.network.packets.ui; + +import com.gregtechceu.gtceu.api.mui.factory.GuiManager; +import com.gregtechceu.gtceu.client.mui.screen.ModularContainerMenu; +import com.gregtechceu.gtceu.common.network.GTNetwork; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraftforge.network.NetworkEvent; + +import lombok.AllArgsConstructor; + +@AllArgsConstructor +public class SContainerSetData implements GTNetwork.INetPacket { + + private int inWorldId; + private int id; + private int value; + + public SContainerSetData(FriendlyByteBuf buf) { + inWorldId = buf.readVarInt(); + id = buf.readVarInt(); + value = buf.readVarInt(); + } + + @Override + public void encode(FriendlyByteBuf buffer) { + buffer.writeVarInt(inWorldId); + buffer.writeVarInt(id); + buffer.writeVarInt(value); + } + + @Override + public void execute(NetworkEvent.Context context) { + ModularContainerMenu menu = GuiManager.getClientInWorldMenu(inWorldId); + if (menu != null) { + menu.setData(id, value); + } + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/common/network/packets/ui/SContainerSetSlot.java b/src/main/java/com/gregtechceu/gtceu/common/network/packets/ui/SContainerSetSlot.java new file mode 100644 index 00000000000..4f67988ced5 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/common/network/packets/ui/SContainerSetSlot.java @@ -0,0 +1,45 @@ +package com.gregtechceu.gtceu.common.network.packets.ui; + +import com.gregtechceu.gtceu.api.mui.factory.GuiManager; +import com.gregtechceu.gtceu.client.mui.screen.ModularContainerMenu; +import com.gregtechceu.gtceu.common.network.GTNetwork; + +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.item.ItemStack; +import net.minecraftforge.network.NetworkEvent; + +import lombok.AllArgsConstructor; + +@AllArgsConstructor +public class SContainerSetSlot implements GTNetwork.INetPacket { + + private int inWorldId; + private int stateId; + private int slot; + private ItemStack stack; + + public SContainerSetSlot(FriendlyByteBuf buf) { + inWorldId = buf.readVarInt(); + stateId = buf.readVarInt(); + slot = buf.readVarInt(); + stack = buf.readItem(); + } + + @Override + public void encode(FriendlyByteBuf buffer) { + buffer.writeVarInt(inWorldId); + buffer.writeVarInt(stateId); + buffer.writeVarInt(slot); + buffer.writeItem(stack); + } + + @Override + public void execute(NetworkEvent.Context context) { + ModularContainerMenu menu = GuiManager.getClientInWorldMenu(inWorldId); + if (menu != null) { + if (slot == -1) { + menu.setCarried(stack); + } else menu.setItem(slot, stateId, stack); + } + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/common/network/packets/ui/SyncHandlerPacket.java b/src/main/java/com/gregtechceu/gtceu/common/network/packets/ui/SyncHandlerPacket.java index 2a2be25130c..8a5f6ec03f3 100644 --- a/src/main/java/com/gregtechceu/gtceu/common/network/packets/ui/SyncHandlerPacket.java +++ b/src/main/java/com/gregtechceu/gtceu/common/network/packets/ui/SyncHandlerPacket.java @@ -17,6 +17,7 @@ @ApiStatus.Internal public class SyncHandlerPacket implements GTNetwork.INetPacket { + public int inWorldID; public int networkId; public String panel; public String key; @@ -25,6 +26,7 @@ public class SyncHandlerPacket implements GTNetwork.INetPacket { @Override public void encode(FriendlyByteBuf buf) { + buf.writeVarInt(this.inWorldID); buf.writeVarInt(this.networkId); NetworkUtils.writeStringSafe(buf, this.panel, 256, true); NetworkUtils.writeStringSafe(buf, this.key, 256, true); @@ -33,6 +35,7 @@ public void encode(FriendlyByteBuf buf) { } public SyncHandlerPacket(FriendlyByteBuf buf) { + this.inWorldID = buf.readVarInt(); this.networkId = buf.readVarInt(); this.panel = NetworkUtils.readStringSafe(buf); this.key = NetworkUtils.readStringSafe(buf); diff --git a/src/main/java/com/gregtechceu/gtceu/core/IGameRenderer.java b/src/main/java/com/gregtechceu/gtceu/core/IGameRenderer.java new file mode 100644 index 00000000000..c62026ef9ed --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/core/IGameRenderer.java @@ -0,0 +1,10 @@ +package com.gregtechceu.gtceu.core; + +import com.mojang.blaze3d.vertex.PoseStack; + +public interface IGameRenderer { + + double gtceu$getFov(float partialTicks); + + void gtceu$bob(PoseStack poseStack, float partialTicks); +} diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/client/GameRendererMixin.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/GameRendererMixin.java new file mode 100644 index 00000000000..6a17a47d612 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/GameRendererMixin.java @@ -0,0 +1,65 @@ +package com.gregtechceu.gtceu.core.mixins.client; + +import com.gregtechceu.gtceu.api.mui.InWorldMUIRenderEvent; +import com.gregtechceu.gtceu.core.IGameRenderer; + +import net.minecraft.client.Camera; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraftforge.common.MinecraftForge; + +import com.mojang.blaze3d.platform.Window; +import com.mojang.blaze3d.vertex.PoseStack; +import org.joml.Matrix4f; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import org.spongepowered.asm.mixin.injection.callback.LocalCapture; + +@Mixin(GameRenderer.class) +public abstract class GameRendererMixin implements IGameRenderer { + + @Shadow + @Final + Minecraft minecraft; + + @Shadow + protected abstract double getFov(Camera activeRenderInfo, float partialTicks, boolean useFOVSetting); + + @Shadow + @Final + private Camera mainCamera; + + @Shadow + protected abstract void bobHurt(PoseStack poseStack, float partialTicks); + + @Shadow + protected abstract void bobView(PoseStack poseStack, float partialTicks); + + @Inject(method = "render", + at = @At(value = "INVOKE_STRING", + target = "Lnet/minecraft/util/profiling/ProfilerFiller;push(Ljava/lang/String;)V", + args = "ldc=toasts"), + locals = LocalCapture.CAPTURE_FAILSOFT) + private void onScreenRender(float partialTicks, long nanoTime, boolean renderLevel, CallbackInfo ci, int i, int j, + Window window, Matrix4f matrix4f, PoseStack posestack, GuiGraphics guigraphics) { + MinecraftForge.EVENT_BUS.post(new InWorldMUIRenderEvent(guigraphics, this.minecraft.getDeltaFrameTime())); + } + + @Override + public double gtceu$getFov(float partialTicks) { + return getFov(mainCamera, partialTicks, true); + } + + @Override + public void gtceu$bob(PoseStack poseStack, float partialTicks) { + bobHurt(poseStack, partialTicks); + if (minecraft.options.bobView().get()) { + bobView(poseStack, partialTicks); + } + } +} diff --git a/src/main/java/com/gregtechceu/gtceu/core/mixins/client/KeyboardHandlerMixin.java b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/KeyboardHandlerMixin.java new file mode 100644 index 00000000000..be66b6bfcd4 --- /dev/null +++ b/src/main/java/com/gregtechceu/gtceu/core/mixins/client/KeyboardHandlerMixin.java @@ -0,0 +1,39 @@ +package com.gregtechceu.gtceu.core.mixins.client; + +import com.gregtechceu.gtceu.client.CharTypedEvent; +import com.gregtechceu.gtceu.client.EarlyKeyPressEvent; + +import net.minecraft.client.KeyboardHandler; +import net.minecraft.client.Minecraft; +import net.minecraftforge.common.MinecraftForge; + +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +@Mixin(KeyboardHandler.class) +public class KeyboardHandlerMixin { + + @Shadow + @Final + private Minecraft minecraft; + + @Inject(method = "charTyped", at = @At(value = "HEAD"), cancellable = true) + private void onCharTyped(long windowPointer, int codePoint, int modifiers, CallbackInfo ci) { + if (windowPointer == this.minecraft.getWindow().getWindow()) { + CharTypedEvent event = new CharTypedEvent((char) codePoint, modifiers); + if (MinecraftForge.EVENT_BUS.post(event)) ci.cancel(); + } + } + + @Inject(method = "keyPress", at = @At(value = "HEAD"), cancellable = true) + private void onKeyPressed(long windowPointer, int key, int scanCode, int action, int modifiers, CallbackInfo ci) { + if (windowPointer == this.minecraft.getWindow().getWindow()) { + EarlyKeyPressEvent event = new EarlyKeyPressEvent(key, scanCode, action, modifiers); + if (MinecraftForge.EVENT_BUS.post(event)) ci.cancel(); + } + } +} diff --git a/src/main/resources/assets/gtceu/textures/item/plugin.fake_gui.png b/src/main/resources/assets/gtceu/textures/item/gui_module.png similarity index 100% rename from src/main/resources/assets/gtceu/textures/item/plugin.fake_gui.png rename to src/main/resources/assets/gtceu/textures/item/gui_module.png diff --git a/src/main/resources/assets/gtceu/textures/item/plugin.online_pic.png b/src/main/resources/assets/gtceu/textures/item/plugin.online_pic.png deleted file mode 100644 index 8b532f20234..00000000000 Binary files a/src/main/resources/assets/gtceu/textures/item/plugin.online_pic.png and /dev/null differ diff --git a/src/main/resources/assets/gtceu/textures/item/plugin.text.png b/src/main/resources/assets/gtceu/textures/item/plugin.text.png deleted file mode 100644 index ad997f1a0ab..00000000000 Binary files a/src/main/resources/assets/gtceu/textures/item/plugin.text.png and /dev/null differ diff --git a/src/main/resources/gtceu.mixins.json b/src/main/resources/gtceu.mixins.json index 0343a250866..51949e48002 100644 --- a/src/main/resources/gtceu.mixins.json +++ b/src/main/resources/gtceu.mixins.json @@ -6,6 +6,7 @@ "compatibilityLevel": "JAVA_17", "plugin": "com.gregtechceu.gtceu.core.mixins.GTMixinPlugin", "client": [ + "client.KeyboardHandlerMixin", "client.AbstractClientPlayerAccessor", "client.AbstractContainerScreenAccessor", "client.AbstractContainerScreenMixin", @@ -15,6 +16,7 @@ "client.BlockModelMixin", "client.ClientLevelAccessor", "client.FaceBakeryMixin", + "client.GameRendererMixin", "client.GuiGraphicsAccessor", "client.GuiGraphicsMixin", "client.GuiHeartTypeMixin",