Rewrite the GuiEvent.SET_SCREEN mixin to fix #35

This commit is contained in:
shedaniel
2021-03-11 21:09:22 +08:00
parent db1237448a
commit 833d6014ea
2 changed files with 32 additions and 64 deletions

View File

@@ -23,40 +23,35 @@ 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.InteractionResultHolder;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.phys.HitResult;
import org.jetbrains.annotations.Nullable;
import org.objectweb.asm.Opcodes;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.*;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.ModifyVariable;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
import java.io.File;
@Unique
@Mixin(Minecraft.class)
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 boolean setScreenCancelled;
private String hostname;
private int port;
// @formatter:on
@Shadow
public abstract void setScreen(@Nullable Screen screen);
@Unique
private ThreadLocal<Boolean> setScreenCancelled = new ThreadLocal<>();
@Inject(method = "clearLevel(Lnet/minecraft/client/gui/screens/Screen;)V",
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/chat/NarratorChatListener;clear()V"))
@@ -80,9 +75,9 @@ public abstract class MixinMinecraft {
@ModifyVariable(
method = "setScreen",
at = @At(value = "INVOKE",
target = "Lnet/minecraft/client/player/LocalPlayer;respawn()V",
shift = At.Shift.BY,
by = 2),
target = "Lnet/minecraft/client/player/LocalPlayer;respawn()V",
shift = At.Shift.BY,
by = 2),
argsOnly = true
)
public Screen modifyScreen(Screen screen) {
@@ -90,7 +85,7 @@ public abstract class MixinMinecraft {
InteractionResultHolder<Screen> event = GuiEvent.SET_SCREEN.invoker().modifyScreen(screen);
switch (event.getResult()) {
case FAIL:
setScreenCancelled = true;
setScreenCancelled.set(true);
return old;
case SUCCESS:
screen = event.getObject();
@@ -98,56 +93,24 @@ public abstract class MixinMinecraft {
old.removed();
}
default:
setScreenCancelled = false;
setScreenCancelled.set(false);
return screen;
}
}
@Inject(
method = "setScreen",
at = @At(value = "INVOKE",
target = "Lnet/minecraft/client/player/LocalPlayer;respawn()V",
shift = At.Shift.BY,
by = 3),
at = @At(value = "FIELD",
opcode = Opcodes.PUTFIELD,
target = "Lnet/minecraft/client/Minecraft;screen:Lnet/minecraft/client/gui/screens/Screen;",
shift = At.Shift.BY,
by = -1),
cancellable = true
)
public void cancelSetScreen(@Nullable Screen screen, CallbackInfo ci) {
if (setScreenCancelled) {
if (setScreenCancelled.get()) {
ci.cancel();
}
}
@Redirect(
method = "<init>",
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 = "<init>",
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", "ConstantConditions"})
@Inject(
method = {"method_29338", "lambda$null$1"}, // <init>.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));
setScreenCancelled.set(false);
}
}
}

View File

@@ -27,6 +27,7 @@ import me.shedaniel.architectury.platform.Platform;
import me.shedaniel.architectury.utils.Env;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.gui.screens.ChatScreen;
import net.minecraft.core.Position;
import net.minecraft.core.Vec3i;
import net.minecraft.network.chat.TranslatableComponent;
@@ -211,10 +212,6 @@ public class DebugEvents {
ClientPlayerEvent.CLIENT_PLAYER_RESPAWN.register((oldPlayer, newPlayer) -> {
SINK.accept(newPlayer.getScoreboardName() + " respawned (client)");
});
GuiEvent.SET_SCREEN.register((screen -> {
SINK.accept("Screen has been changed to " + toSimpleName(screen));
return InteractionResultHolder.pass(screen);
}));
GuiEvent.INIT_PRE.register((screen, widgets, children) -> {
SINK.accept(toSimpleName(screen) + " initializes");
return InteractionResult.PASS;
@@ -271,6 +268,14 @@ public class DebugEvents {
SINK.accept("Raw Key pressed: " + InputConstants.getKey(keyCode, scanCode).getDisplayName().getString());
return InteractionResult.PASS;
});
GuiEvent.SET_SCREEN.register(screen -> {
if (screen instanceof ChatScreen) {
return InteractionResultHolder.fail(screen);
}
SINK.accept("Screen has been changed to " + toSimpleName(screen));
return InteractionResultHolder.pass(screen);
});
}
private static String toSimpleName(Object o) {