forked from Clones/Controlify
🐛 Fix issue with some modded GUIs crashing with controlify (closes #174)
This commit is contained in:
@ -3,12 +3,16 @@ package dev.isxander.controlify.mixins.core;
|
|||||||
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
|
||||||
import dev.isxander.controlify.Controlify;
|
import dev.isxander.controlify.Controlify;
|
||||||
import dev.isxander.controlify.ControllerManager;
|
import dev.isxander.controlify.ControllerManager;
|
||||||
|
import dev.isxander.controlify.api.ControlifyApi;
|
||||||
import dev.isxander.controlify.controller.Controller;
|
import dev.isxander.controlify.controller.Controller;
|
||||||
import dev.isxander.controlify.utils.Animator;
|
import dev.isxander.controlify.utils.Animator;
|
||||||
|
import dev.isxander.controlify.utils.MouseMinecraftCallNotifier;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
|
import net.minecraft.client.MouseHandler;
|
||||||
import net.minecraft.client.gui.screens.Screen;
|
import net.minecraft.client.gui.screens.Screen;
|
||||||
import net.minecraft.server.packs.resources.ReloadInstance;
|
import net.minecraft.server.packs.resources.ReloadInstance;
|
||||||
import org.jetbrains.annotations.Nullable;
|
import org.jetbrains.annotations.Nullable;
|
||||||
|
import org.spongepowered.asm.mixin.Final;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
import org.spongepowered.asm.mixin.Unique;
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
@ -21,8 +25,30 @@ public abstract class MinecraftMixin {
|
|||||||
@Shadow public abstract void setScreen(@Nullable Screen screen);
|
@Shadow public abstract void setScreen(@Nullable Screen screen);
|
||||||
@Shadow public abstract float getDeltaFrameTime();
|
@Shadow public abstract float getDeltaFrameTime();
|
||||||
|
|
||||||
|
@Shadow @Final public MouseHandler mouseHandler;
|
||||||
@Unique private boolean initNextTick = false;
|
@Unique private boolean initNextTick = false;
|
||||||
|
|
||||||
|
// Ideally, this would be done in MouseHandler#releaseMouse, but moving
|
||||||
|
// the mouse before the screen init is bad, because some mods (e.g. PuzzleLib)
|
||||||
|
// have custom mouse events that call into screens, events that have not been
|
||||||
|
// initialised yet in Screen#init. Causing NPEs and many strange issues.
|
||||||
|
@Inject(method = "setScreen", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MouseHandler;releaseMouse()V", shift = At.Shift.BEFORE))
|
||||||
|
private void notifyInjectionToNotRun(Screen screen, CallbackInfo ci) {
|
||||||
|
((MouseMinecraftCallNotifier) mouseHandler).imFromMinecraftSetScreen();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Without this, the mouse would be left in the middle of the
|
||||||
|
* screen, hovering over whatever is there which would look wrong
|
||||||
|
* as there is a focus as well.
|
||||||
|
*/
|
||||||
|
@Inject(method = "setScreen", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/gui/screens/Screen;init(Lnet/minecraft/client/Minecraft;II)V", shift = At.Shift.AFTER))
|
||||||
|
private void hideMouseAfterRelease(Screen screen, CallbackInfo ci) {
|
||||||
|
if (ControlifyApi.get().currentInputMode().isController()) {
|
||||||
|
Controlify.instance().hideMouse(true, true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@ModifyExpressionValue(method = "<init>", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/packs/resources/ReloadableResourceManager;createReload(Ljava/util/concurrent/Executor;Ljava/util/concurrent/Executor;Ljava/util/concurrent/CompletableFuture;Ljava/util/List;)Lnet/minecraft/server/packs/resources/ReloadInstance;"))
|
@ModifyExpressionValue(method = "<init>", at = @At(value = "INVOKE", target = "Lnet/minecraft/server/packs/resources/ReloadableResourceManager;createReload(Ljava/util/concurrent/Executor;Ljava/util/concurrent/Executor;Ljava/util/concurrent/CompletableFuture;Ljava/util/List;)Lnet/minecraft/server/packs/resources/ReloadInstance;"))
|
||||||
private ReloadInstance onInputInitialized(ReloadInstance resourceReload) {
|
private ReloadInstance onInputInitialized(ReloadInstance resourceReload) {
|
||||||
// Controllers need to be initialized extremely late due to the data-driven nature of controllers.
|
// Controllers need to be initialized extremely late due to the data-driven nature of controllers.
|
||||||
|
@ -3,19 +3,23 @@ package dev.isxander.controlify.mixins.core;
|
|||||||
import dev.isxander.controlify.Controlify;
|
import dev.isxander.controlify.Controlify;
|
||||||
import dev.isxander.controlify.InputMode;
|
import dev.isxander.controlify.InputMode;
|
||||||
import dev.isxander.controlify.api.ControlifyApi;
|
import dev.isxander.controlify.api.ControlifyApi;
|
||||||
|
import dev.isxander.controlify.utils.MouseMinecraftCallNotifier;
|
||||||
import net.minecraft.client.Minecraft;
|
import net.minecraft.client.Minecraft;
|
||||||
import net.minecraft.client.MouseHandler;
|
import net.minecraft.client.MouseHandler;
|
||||||
import org.spongepowered.asm.mixin.Final;
|
import org.spongepowered.asm.mixin.Final;
|
||||||
import org.spongepowered.asm.mixin.Mixin;
|
import org.spongepowered.asm.mixin.Mixin;
|
||||||
import org.spongepowered.asm.mixin.Shadow;
|
import org.spongepowered.asm.mixin.Shadow;
|
||||||
|
import org.spongepowered.asm.mixin.Unique;
|
||||||
import org.spongepowered.asm.mixin.injection.At;
|
import org.spongepowered.asm.mixin.injection.At;
|
||||||
import org.spongepowered.asm.mixin.injection.Inject;
|
import org.spongepowered.asm.mixin.injection.Inject;
|
||||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||||
|
|
||||||
@Mixin(MouseHandler.class)
|
@Mixin(MouseHandler.class)
|
||||||
public class MouseHandlerMixin {
|
public class MouseHandlerMixin implements MouseMinecraftCallNotifier {
|
||||||
@Shadow @Final private Minecraft minecraft;
|
@Shadow @Final private Minecraft minecraft;
|
||||||
|
|
||||||
|
@Unique private boolean calledFromMinecraftSetScreen = false;
|
||||||
|
|
||||||
// method_22686 is lambda for GLFW mouse click hook - do it outside of the `onPress` method due to fake inputs
|
// method_22686 is lambda for GLFW mouse click hook - do it outside of the `onPress` method due to fake inputs
|
||||||
@Inject(method = "method_22686", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MouseHandler;onPress(JIII)V"))
|
@Inject(method = "method_22686", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/MouseHandler;onPress(JIII)V"))
|
||||||
private void onMouseClickInput(long window, int button, int action, int modifiers, CallbackInfo ci) {
|
private void onMouseClickInput(long window, int button, int action, int modifiers, CallbackInfo ci) {
|
||||||
@ -34,6 +38,7 @@ public class MouseHandlerMixin {
|
|||||||
onMouse(window);
|
onMouse(window);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Unique
|
||||||
private void onMouse(long window) {
|
private void onMouse(long window) {
|
||||||
if (window == minecraft.getWindow().getWindow()) {
|
if (window == minecraft.getWindow().getWindow()) {
|
||||||
if (Controlify.instance().currentInputMode() != InputMode.MIXED) {
|
if (Controlify.instance().currentInputMode() != InputMode.MIXED) {
|
||||||
@ -49,8 +54,19 @@ public class MouseHandlerMixin {
|
|||||||
*/
|
*/
|
||||||
@Inject(method = "releaseMouse", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/platform/InputConstants;grabOrReleaseMouse(JIDD)V"))
|
@Inject(method = "releaseMouse", at = @At(value = "INVOKE", target = "Lcom/mojang/blaze3d/platform/InputConstants;grabOrReleaseMouse(JIDD)V"))
|
||||||
private void moveMouseIfNecessary(CallbackInfo ci) {
|
private void moveMouseIfNecessary(CallbackInfo ci) {
|
||||||
if (ControlifyApi.get().currentInputMode().isController()) {
|
if (!calledFromMinecraftSetScreen && ControlifyApi.get().currentInputMode().isController()) {
|
||||||
Controlify.instance().hideMouse(true, true);
|
Controlify.instance().hideMouse(true, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// shift after RETURN to escape the if statement scope
|
||||||
|
@Inject(method = "releaseMouse", at = @At(value = "RETURN"))
|
||||||
|
private void resetCalledFromMinecraftSetScreen(CallbackInfo ci) {
|
||||||
|
calledFromMinecraftSetScreen = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void imFromMinecraftSetScreen() {
|
||||||
|
calledFromMinecraftSetScreen = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,5 @@
|
|||||||
|
package dev.isxander.controlify.utils;
|
||||||
|
|
||||||
|
public interface MouseMinecraftCallNotifier {
|
||||||
|
void imFromMinecraftSetScreen();
|
||||||
|
}
|
Reference in New Issue
Block a user