diff --git a/common/src/main/java/me/shedaniel/architectury/event/events/GuiEvent.java b/common/src/main/java/me/shedaniel/architectury/event/events/GuiEvent.java index 92843b16..d29374f9 100644 --- a/common/src/main/java/me/shedaniel/architectury/event/events/GuiEvent.java +++ b/common/src/main/java/me/shedaniel/architectury/event/events/GuiEvent.java @@ -28,6 +28,7 @@ import net.minecraft.client.gui.components.AbstractWidget; import net.minecraft.client.gui.components.events.GuiEventListener; import net.minecraft.client.gui.screens.Screen; import net.minecraft.world.InteractionResult; +import net.minecraft.world.InteractionResultHolder; import java.util.List; @@ -49,32 +50,42 @@ public interface GuiEvent { Event INIT_POST = EventFactory.createLoop(ScreenInitPost.class); Event RENDER_PRE = EventFactory.createInteractionResult(ScreenRenderPre.class); Event RENDER_POST = EventFactory.createInteractionResult(ScreenRenderPost.class); - + + /** + * Invoked during Minecraft#setScreen, equivalent to forge's {@code GuiOpenEvent}. + */ + Event SET_SCREEN = EventFactory.createInteractionResultHolder(); + + @Environment(EnvType.CLIENT) + interface SetScreenEvent { + InteractionResultHolder modifyScreen(Screen screen); + } + @Environment(EnvType.CLIENT) interface RenderHud { void renderHud(PoseStack matrices, float tickDelta); } - + @Environment(EnvType.CLIENT) interface DebugText { void gatherText(List strings); } - + @Environment(EnvType.CLIENT) interface ScreenInitPre { InteractionResult init(Screen screen, List widgets, List children); } - + @Environment(EnvType.CLIENT) interface ScreenInitPost { void init(Screen screen, List widgets, List children); } - + @Environment(EnvType.CLIENT) interface ScreenRenderPre { InteractionResult render(Screen screen, PoseStack matrices, int mouseX, int mouseY, float delta); } - + @Environment(EnvType.CLIENT) interface ScreenRenderPost { void render(Screen screen, PoseStack matrices, int mouseX, int mouseY, float delta); diff --git a/fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/client/MixinMinecraft.java b/fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/client/MixinMinecraft.java index 5eaea2be..f908fea4 100644 --- a/fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/client/MixinMinecraft.java +++ b/fabric/src/main/java/me/shedaniel/architectury/mixin/fabric/client/MixinMinecraft.java @@ -19,34 +19,51 @@ package me.shedaniel.architectury.mixin.fabric.client; +import me.shedaniel.architectury.event.events.GuiEvent; import me.shedaniel.architectury.event.events.InteractionEvent; import me.shedaniel.architectury.event.events.client.ClientPlayerEvent; import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.screens.ConnectScreen; import net.minecraft.client.gui.screens.Screen; +import net.minecraft.client.gui.screens.TitleScreen; +import net.minecraft.client.main.GameConfig; import net.minecraft.client.player.LocalPlayer; import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.InteractionResultHolder; import net.minecraft.world.item.ItemStack; import net.minecraft.world.phys.HitResult; import org.jetbrains.annotations.Nullable; 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.Unique; +import org.spongepowered.asm.mixin.injection.*; import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; import org.spongepowered.asm.mixin.injection.callback.LocalCapture; +import java.io.File; + @Mixin(Minecraft.class) -public class MixinMinecraft { +public abstract class MixinMinecraft { + // @formatter:off @Shadow @Nullable public LocalPlayer player; - + @Shadow @Nullable public HitResult hitResult; - + + @Shadow public abstract void setScreen(@Nullable Screen screen); + + private @Unique boolean setScreenCancelled; + + private @Unique String hostname; + private @Unique int port; + // @formatter:on + @Inject(method = "clearLevel(Lnet/minecraft/client/gui/screens/Screen;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/chat/NarratorChatListener;clear()V")) private void handleLogin(Screen screen, CallbackInfo ci) { ClientPlayerEvent.CLIENT_PLAYER_QUIT.invoker().quit(player); } - + @Inject(method = "startUseItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;isEmpty()Z", ordinal = 1), locals = LocalCapture.CAPTURE_FAILHARD) private void rightClickAir(CallbackInfo ci, InteractionHand var1[], int var2, int var3, InteractionHand interactionHand, ItemStack itemStack) { @@ -54,9 +71,80 @@ public class MixinMinecraft { InteractionEvent.CLIENT_RIGHT_CLICK_AIR.invoker().click(player, interactionHand); } } - + @Inject(method = "startAttack", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/player/LocalPlayer;resetAttackStrengthTicker()V", ordinal = 0)) private void leftClickAir(CallbackInfo ci) { InteractionEvent.CLIENT_LEFT_CLICK_AIR.invoker().click(player, InteractionHand.MAIN_HAND); } + + @ModifyVariable( + method = "setScreen", + at = @At(value = "INVOKE", + target = "Lnet/minecraft/client/player/LocalPlayer;respawn()V", + shift = At.Shift.BY, + by = 2), + argsOnly = true + ) + public Screen modifyScreen(Screen screen) { + Screen old = screen; + InteractionResultHolder event = GuiEvent.SET_SCREEN.invoker().modifyScreen(screen); + if (event.getResult() == InteractionResult.FAIL) { + setScreenCancelled = true; + return old; + } + setScreenCancelled = false; + screen = event.getObject(); + if (old != null && screen != old) { + old.removed(); + } + return screen; + } + + @Inject( + method = "setScreen", + at = @At(value = "INVOKE", + target = "Lnet/minecraft/client/player/LocalPlayer;respawn()V", + shift = At.Shift.BY, + by = 3), + cancellable = true + ) + public void cancelSetScreen(@Nullable Screen screen, CallbackInfo ci) { + if (setScreenCancelled) { + ci.cancel(); + } + } + + @Redirect( + method = "", + at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;setScreen(Lnet/minecraft/client/gui/screens/Screen;)V"), + slice = @Slice( + from = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;resizeDisplay()V"), + to = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screens/LoadingOverlay;registerTextures(Lnet/minecraft/client/Minecraft;)V") + ) + ) + public void minecraftWhy(Minecraft mc, Screen screen) { + } + + @Inject( + method = "", + at = @At(value = "INVOKE", target = "Lnet/minecraft/client/Minecraft;resizeDisplay()V"), + locals = LocalCapture.CAPTURE_FAILHARD + ) + public void saveLocals(GameConfig gc, CallbackInfo ci, File f, String string2, int j) { + hostname = string2; + port = j; + } + + @SuppressWarnings("UnresolvedMixinReference") + @Inject( + method = {"method_29338", "lambda$null$1"}, // .lambda$null$1 + at = @At("RETURN") + ) + public void registerMainScreens(CallbackInfo ci) { + if (hostname != null) { + setScreen(new ConnectScreen(new TitleScreen(), (Minecraft) ((Object) this), hostname, port)); + } else { + setScreen(new TitleScreen(true)); + } + } } diff --git a/fabric/src/main/resources/architectury.mixins.json b/fabric/src/main/resources/architectury.mixins.json index 33df1a24..71f945a8 100644 --- a/fabric/src/main/resources/architectury.mixins.json +++ b/fabric/src/main/resources/architectury.mixins.json @@ -4,16 +4,41 @@ "compatibilityLevel": "JAVA_8", "minVersion": "0.7.11", "client": [ - "client.MixinClientLevel", "client.MixinClientPacketListener", "client.MixinDebugScreenOverlay", "client.MixinGameRenderer", "client.MixinIntegratedServer", - "client.MixinKeyboardHandler", "client.MixinMinecraft", "client.MixinMouseHandler", "client.MixinMultiPlayerGameMode", "client.MixinScreen", + "client.MixinClientLevel", + "client.MixinClientPacketListener", + "client.MixinDebugScreenOverlay", + "client.MixinGameRenderer", + "client.MixinIntegratedServer", + "client.MixinKeyboardHandler", + "client.MixinMinecraft", + "client.MixinMouseHandler", + "client.MixinMultiPlayerGameMode", + "client.MixinScreen", "client.MixinTextureAtlas" ], "mixins": [ - "ExplosionPreInvoker", "LivingDeathInvoker", "MixinBlockEntityExtension", "MixinBlockItem", "MixinCommands", "MixinDedicatedServer", "MixinExplosion", - "MixinFurnaceResultSlot", "MixinItemEntity", "MixinLivingEntity", "MixinPlayer", "MixinPlayerAdvancements", "MixinPlayerList", "MixinResultSlot", - "MixinServerGamePacketListenerImpl", "MixinServerLevel", "MixinServerPlayer", "MixinServerPlayerGameMode", "PlayerAttackInvoker" + "ExplosionPreInvoker", + "LivingDeathInvoker", + "MixinBlockEntityExtension", + "MixinBlockItem", + "MixinCommands", + "MixinDedicatedServer", + "MixinExplosion", + "MixinFurnaceResultSlot", + "MixinItemEntity", + "MixinLivingEntity", + "MixinPlayer", + "MixinPlayerAdvancements", + "MixinPlayerList", + "MixinResultSlot", + "MixinServerGamePacketListenerImpl", + "MixinServerLevel", + "MixinServerPlayer", + "MixinServerPlayerGameMode", + "PlayerAttackInvoker" ], "injectors": { + "maxShiftBy": 5, "defaultRequire": 1 } } diff --git a/forge/src/main/java/me/shedaniel/architectury/event/forge/EventHandlerImplClient.java b/forge/src/main/java/me/shedaniel/architectury/event/forge/EventHandlerImplClient.java index b394d242..cc70f9f2 100644 --- a/forge/src/main/java/me/shedaniel/architectury/event/forge/EventHandlerImplClient.java +++ b/forge/src/main/java/me/shedaniel/architectury/event/forge/EventHandlerImplClient.java @@ -27,6 +27,7 @@ import me.shedaniel.architectury.impl.TooltipEventColorContextImpl; import me.shedaniel.architectury.impl.TooltipEventPositionContextImpl; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.components.events.GuiEventListener; +import net.minecraft.client.gui.screens.Screen; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.network.chat.Component; import net.minecraft.world.InteractionResult; @@ -48,7 +49,7 @@ public class EventHandlerImplClient { public static void event(ItemTooltipEvent event) { TooltipEvent.ITEM.invoker().append(event.getItemStack(), event.getToolTip(), event.getFlags()); } - + @SubscribeEvent public static void event(net.minecraftforge.event.TickEvent.ClientTickEvent event) { if (event.phase == net.minecraftforge.event.TickEvent.Phase.START) @@ -56,40 +57,40 @@ public class EventHandlerImplClient { else if (event.phase == net.minecraftforge.event.TickEvent.Phase.END) ClientTickEvent.CLIENT_POST.invoker().tick(Minecraft.getInstance()); } - + @SubscribeEvent public static void event(RenderGameOverlayEvent.Post event) { if (event.getType() == RenderGameOverlayEvent.ElementType.ALL) GuiEvent.RENDER_HUD.invoker().renderHud(event.getMatrixStack(), event.getPartialTicks()); } - + @SubscribeEvent public static void event(ClientPlayerNetworkEvent.LoggedInEvent event) { ClientPlayerEvent.CLIENT_PLAYER_JOIN.invoker().join(event.getPlayer()); } - + @SubscribeEvent public static void event(ClientPlayerNetworkEvent.LoggedOutEvent event) { ClientPlayerEvent.CLIENT_PLAYER_QUIT.invoker().quit(event.getPlayer()); } - + @SubscribeEvent public static void event(ClientPlayerNetworkEvent.RespawnEvent event) { ClientPlayerEvent.CLIENT_PLAYER_RESPAWN.invoker().respawn(event.getOldPlayer(), event.getNewPlayer()); } - + @SubscribeEvent public static void event(GuiScreenEvent.InitGuiEvent.Pre event) { if (GuiEvent.INIT_PRE.invoker().init(event.getGui(), event.getWidgetList(), (List) event.getGui().children()) == InteractionResult.FAIL) { event.setCanceled(true); } } - + @SubscribeEvent public static void event(GuiScreenEvent.InitGuiEvent.Post event) { GuiEvent.INIT_POST.invoker().init(event.getGui(), event.getWidgetList(), (List) event.getGui().children()); } - + @SubscribeEvent public static void event(RenderGameOverlayEvent.Text event) { if (Minecraft.getInstance().options.renderDebug) { @@ -97,7 +98,7 @@ public class EventHandlerImplClient { GuiEvent.DEBUG_TEXT_RIGHT.invoker().gatherText(event.getRight()); } } - + @SubscribeEvent public static void event(net.minecraftforge.client.event.ClientChatEvent event) { InteractionResultHolder process = ClientChatEvent.CLIENT.invoker().process(event.getMessage()); @@ -106,7 +107,7 @@ public class EventHandlerImplClient { if (process.getResult() == InteractionResult.FAIL) event.setCanceled(true); } - + @SubscribeEvent public static void event(ClientChatReceivedEvent event) { InteractionResultHolder process = ClientChatEvent.CLIENT_RECEIVED.invoker().process(event.getType(), event.getMessage(), event.getSenderUUID()); @@ -115,7 +116,7 @@ public class EventHandlerImplClient { if (process.getResult() == InteractionResult.FAIL) event.setCanceled(true); } - + @SubscribeEvent public static void event(WorldEvent.Save event) { if (event.getWorld() instanceof ClientLevel) { @@ -123,51 +124,61 @@ public class EventHandlerImplClient { ClientLifecycleEvent.CLIENT_WORLD_LOAD.invoker().act(world); } } - + + @SubscribeEvent + public static void event(GuiOpenEvent event) { + InteractionResultHolder result = GuiEvent.SET_SCREEN.invoker().modifyScreen(event.getGui()); + if (result.getResult() == InteractionResult.FAIL) { + event.setCanceled(true); + return; + } + event.setGui(result.getObject()); + } + @SubscribeEvent public static void event(GuiScreenEvent.DrawScreenEvent.Pre event) { if (GuiEvent.RENDER_PRE.invoker().render(event.getGui(), event.getMatrixStack(), event.getMouseX(), event.getMouseY(), event.getRenderPartialTicks()) == InteractionResult.FAIL) { event.setCanceled(true); } } - + @SubscribeEvent public static void event(GuiScreenEvent.DrawScreenEvent.Post event) { GuiEvent.RENDER_POST.invoker().render(event.getGui(), event.getMatrixStack(), event.getMouseX(), event.getMouseY(), event.getRenderPartialTicks()); } - + @SubscribeEvent public static void event(PlayerInteractEvent.RightClickEmpty event) { InteractionEvent.CLIENT_RIGHT_CLICK_AIR.invoker().click(event.getPlayer(), event.getHand()); } - + @SubscribeEvent public static void event(PlayerInteractEvent.LeftClickEmpty event) { InteractionEvent.CLIENT_LEFT_CLICK_AIR.invoker().click(event.getPlayer(), event.getHand()); } - + @SubscribeEvent public static void event(RecipesUpdatedEvent event) { RecipeUpdateEvent.EVENT.invoker().update(event.getRecipeManager()); } - + private static final ThreadLocal tooltipColorContext = ThreadLocal.withInitial(TooltipEventColorContextImpl::new); private static final ThreadLocal tooltipPositionContext = ThreadLocal.withInitial(TooltipEventPositionContextImpl::new); - + @SubscribeEvent public static void event(RenderTooltipEvent.Pre event) { if (TooltipEvent.RENDER_FORGE_PRE.invoker().renderTooltip(event.getMatrixStack(), event.getLines(), event.getX(), event.getY()) == InteractionResult.FAIL) { event.setCanceled(true); return; } - + TooltipEventPositionContextImpl positionContext = tooltipPositionContext.get(); positionContext.reset(event.getX(), event.getY()); TooltipEvent.RENDER_MODIFY_POSITION.invoker().renderTooltip(event.getMatrixStack(), positionContext); event.setX(positionContext.getTooltipX()); event.setY(positionContext.getTooltipY()); } - + @SubscribeEvent public static void event(RenderTooltipEvent.Color event) { TooltipEventColorContextImpl colorContext = tooltipColorContext.get(); @@ -180,127 +191,127 @@ public class EventHandlerImplClient { event.setBorderEnd(colorContext.getOutlineGradientBottomColor()); event.setBorderStart(colorContext.getOutlineGradientTopColor()); } - + @SubscribeEvent public static void event(GuiScreenEvent.MouseScrollEvent.Pre event) { if (ClientScreenInputEvent.MOUSE_SCROLLED_PRE.invoker().mouseScrolled(Minecraft.getInstance(), event.getGui(), event.getMouseX(), event.getMouseY(), event.getScrollDelta()) == InteractionResult.FAIL) { event.setCanceled(true); } } - + @SubscribeEvent public static void event(GuiScreenEvent.MouseScrollEvent.Post event) { ClientScreenInputEvent.MOUSE_SCROLLED_POST.invoker().mouseScrolled(Minecraft.getInstance(), event.getGui(), event.getMouseX(), event.getMouseY(), event.getScrollDelta()); } - + @SubscribeEvent public static void event(GuiScreenEvent.MouseClickedEvent.Pre event) { if (ClientScreenInputEvent.MOUSE_CLICKED_PRE.invoker().mouseClicked(Minecraft.getInstance(), event.getGui(), event.getMouseX(), event.getMouseY(), event.getButton()) == InteractionResult.FAIL) { event.setCanceled(true); } } - + @SubscribeEvent public static void event(GuiScreenEvent.MouseClickedEvent.Post event) { ClientScreenInputEvent.MOUSE_CLICKED_POST.invoker().mouseClicked(Minecraft.getInstance(), event.getGui(), event.getMouseX(), event.getMouseY(), event.getButton()); } - + @SubscribeEvent public static void event(GuiScreenEvent.MouseDragEvent.Pre event) { if (ClientScreenInputEvent.MOUSE_DRAGGED_PRE.invoker().mouseDragged(Minecraft.getInstance(), event.getGui(), event.getMouseX(), event.getMouseY(), event.getMouseButton(), event.getDragX(), event.getDragY()) == InteractionResult.FAIL) { event.setCanceled(true); } } - + @SubscribeEvent public static void event(GuiScreenEvent.MouseDragEvent.Post event) { ClientScreenInputEvent.MOUSE_DRAGGED_POST.invoker().mouseDragged(Minecraft.getInstance(), event.getGui(), event.getMouseX(), event.getMouseY(), event.getMouseButton(), event.getDragX(), event.getDragY()); } - + @SubscribeEvent public static void event(GuiScreenEvent.MouseReleasedEvent.Pre event) { if (ClientScreenInputEvent.MOUSE_RELEASED_PRE.invoker().mouseReleased(Minecraft.getInstance(), event.getGui(), event.getMouseX(), event.getMouseY(), event.getButton()) == InteractionResult.FAIL) { event.setCanceled(true); } } - + @SubscribeEvent public static void event(GuiScreenEvent.MouseReleasedEvent.Post event) { ClientScreenInputEvent.MOUSE_RELEASED_PRE.invoker().mouseReleased(Minecraft.getInstance(), event.getGui(), event.getMouseX(), event.getMouseY(), event.getButton()); } - + @SubscribeEvent public static void event(GuiScreenEvent.KeyboardCharTypedEvent.Pre event) { if (ClientScreenInputEvent.CHAR_TYPED_PRE.invoker().charTyped(Minecraft.getInstance(), event.getGui(), event.getCodePoint(), event.getModifiers()) == InteractionResult.FAIL) { event.setCanceled(true); } } - + @SubscribeEvent public static void event(GuiScreenEvent.KeyboardCharTypedEvent.Post event) { ClientScreenInputEvent.CHAR_TYPED_POST.invoker().charTyped(Minecraft.getInstance(), event.getGui(), event.getCodePoint(), event.getModifiers()); } - + @SubscribeEvent public static void event(GuiScreenEvent.KeyboardKeyPressedEvent.Pre event) { if (ClientScreenInputEvent.KEY_PRESSED_PRE.invoker().keyPressed(Minecraft.getInstance(), event.getGui(), event.getKeyCode(), event.getScanCode(), event.getModifiers()) == InteractionResult.FAIL) { event.setCanceled(true); } } - + @SubscribeEvent public static void event(GuiScreenEvent.KeyboardKeyPressedEvent.Post event) { ClientScreenInputEvent.KEY_PRESSED_POST.invoker().keyPressed(Minecraft.getInstance(), event.getGui(), event.getKeyCode(), event.getScanCode(), event.getModifiers()); } - + @SubscribeEvent public static void event(GuiScreenEvent.KeyboardKeyReleasedEvent.Pre event) { if (ClientScreenInputEvent.KEY_RELEASED_PRE.invoker().keyReleased(Minecraft.getInstance(), event.getGui(), event.getKeyCode(), event.getScanCode(), event.getModifiers()) == InteractionResult.FAIL) { event.setCanceled(true); } } - + @SubscribeEvent public static void event(GuiScreenEvent.KeyboardKeyReleasedEvent.Post event) { ClientScreenInputEvent.KEY_RELEASED_POST.invoker().keyReleased(Minecraft.getInstance(), event.getGui(), event.getKeyCode(), event.getScanCode(), event.getModifiers()); } - + @SubscribeEvent public static void event(InputEvent.MouseScrollEvent event) { if (ClientRawInputEvent.MOUSE_SCROLLED.invoker().mouseScrolled(Minecraft.getInstance(), event.getScrollDelta()) == InteractionResult.FAIL) { event.setCanceled(true); } } - + @SubscribeEvent public static void event(InputEvent.RawMouseEvent event) { if (ClientRawInputEvent.MOUSE_CLICKED_PRE.invoker().mouseClicked(Minecraft.getInstance(), event.getButton(), event.getAction(), event.getMods()) == InteractionResult.FAIL) { event.setCanceled(true); } } - + @SubscribeEvent public static void event(InputEvent.MouseInputEvent event) { ClientRawInputEvent.MOUSE_CLICKED_POST.invoker().mouseClicked(Minecraft.getInstance(), event.getButton(), event.getAction(), event.getMods()); } - + @SubscribeEvent public static void event(InputEvent.KeyInputEvent event) { ClientRawInputEvent.KEY_PRESSED.invoker().keyPressed(Minecraft.getInstance(), event.getKey(), event.getScanCode(), event.getAction(), event.getModifiers()); } - + @OnlyIn(Dist.CLIENT) public static class ModBasedEventHandler { @SubscribeEvent public static void event(net.minecraftforge.client.event.TextureStitchEvent.Pre event) { TextureStitchEvent.PRE.invoker().stitch(event.getMap(), event::addSprite); } - + @SubscribeEvent public static void event(net.minecraftforge.client.event.TextureStitchEvent.Post event) { TextureStitchEvent.POST.invoker().stitch(event.getMap()); } - + @SubscribeEvent public static void event(FMLClientSetupEvent event) { ClientLifecycleEvent.CLIENT_SETUP.invoker().stateChanged(event.getMinecraftSupplier().get());