Use a crash callable instead of a mixin for GLWindow

This commit is contained in:
Matthew Messinger 2018-06-10 15:08:41 -04:00
parent c841abe4dc
commit 09e4d5de79
5 changed files with 40 additions and 92 deletions

View file

@ -9,6 +9,8 @@ import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.IReloadableResourceManager; import net.minecraft.client.resources.IReloadableResourceManager;
import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.MinecraftForge;
import net.minecraftforge.fml.client.registry.RenderingRegistry; import net.minecraftforge.fml.client.registry.RenderingRegistry;
import net.minecraftforge.fml.common.FMLCommonHandler;
import net.minecraftforge.fml.common.ICrashCallable;
import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.common.Mod;
import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
@ -53,7 +55,20 @@ public class HDSkins {
} }
} }
// GLWindow.current(); // Create a bogus crash callable so we can properly close the window in case of a crash.
FMLCommonHandler.instance().registerCrashCallable(new ICrashCallable() {
@Override
public String getLabel() {
return "HDSkins";
}
@Override
public String call() {
GLWindow.dispose();
return "";
}
});
} }
private boolean fullscreen; private boolean fullscreen;

View file

@ -1,7 +1,6 @@
package com.voxelmodpack.hdskins.gui; package com.voxelmodpack.hdskins.gui;
import com.google.common.collect.Lists; import com.google.common.collect.Lists;
import net.minecraft.client.Minecraft; import net.minecraft.client.Minecraft;
import net.minecraft.client.resources.DefaultResourcePack; import net.minecraft.client.resources.DefaultResourcePack;
import net.minecraft.util.ResourceLocation; import net.minecraft.util.ResourceLocation;
@ -24,7 +23,6 @@ import javax.swing.*;
/** /**
* Experimental window to control file drop. It kind of sucks. * Experimental window to control file drop. It kind of sucks.
*
*/ */
public class GLWindow extends DropTarget { public class GLWindow extends DropTarget {
@ -60,7 +58,7 @@ public class GLWindow extends DropTarget {
} }
private static int getScaledPixelUnit(int i) { private static int getScaledPixelUnit(int i) {
return (int)Math.floor(i * Display.getPixelScaleFactor()); return (int) Math.floor(i * Display.getPixelScaleFactor());
} }
private final Minecraft mc = Minecraft.getMinecraft(); private final Minecraft mc = Minecraft.getMinecraft();
@ -74,6 +72,8 @@ public class GLWindow extends DropTarget {
private boolean isFullscreen; private boolean isFullscreen;
private boolean open;
private GLWindow() { private GLWindow() {
try { try {
open(); open();
@ -95,12 +95,16 @@ public class GLWindow extends DropTarget {
canvas = new Canvas(); canvas = new Canvas();
frame = new JFrame(Display.getTitle()); frame = new JFrame(Display.getTitle());
frame.add(canvas); frame.getContentPane().add(canvas);
frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE); frame.setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
frame.addWindowListener(new WindowAdapter() { frame.addWindowListener(new WindowAdapter() {
@Override @Override
public void windowClosed(WindowEvent windowEvent) { public void windowClosed(WindowEvent windowEvent) {
mc.shutdown(); // If we don't check this, exiting the skins menu
// will shutdown minecraft.
if (open) {
mc.shutdown();
}
} }
@Override @Override
@ -116,7 +120,7 @@ public class GLWindow extends DropTarget {
float frameFactorX = frame.getWidth() - frame.getContentPane().getWidth(); float frameFactorX = frame.getWidth() - frame.getContentPane().getWidth();
float frameFactorY = frame.getHeight() - frame.getContentPane().getHeight(); float frameFactorY = frame.getHeight() - frame.getContentPane().getHeight();
frame.setSize((int)Math.floor(w + frameFactorX), (int)Math.floor(h + frameFactorY)); frame.setSize((int) Math.floor(w + frameFactorX), (int) Math.floor(h + frameFactorY));
} }
}); });
frame.addComponentListener(new ComponentAdapter() { frame.addComponentListener(new ComponentAdapter() {
@ -139,9 +143,13 @@ public class GLWindow extends DropTarget {
Display.setParent(canvas); Display.setParent(canvas);
Display.setFullscreen(isFullscreen); Display.setFullscreen(isFullscreen);
open = true;
} }
private void close() { private void close() {
open = false;
clearDropTargetListener();
try { try {
Display.setParent(null); Display.setParent(null);
} catch (LWJGLException e) { } catch (LWJGLException e) {
@ -197,7 +205,9 @@ public class GLWindow extends DropTarget {
} }
private void onRefresh(boolean fullscreen) { private void onRefresh(boolean fullscreen) {
if (fullscreen != isFullscreen) { if (fullscreen) {
close();
} else if (open) {
// Repaint the canvas, not the window. // Repaint the canvas, not the window.
// The former strips the window of its state. The latter fixes a viewport scaling bug. // The former strips the window of its state. The latter fixes a viewport scaling bug.
canvas.setBounds(0, 0, 0, 0); canvas.setBounds(0, 0, 0, 0);
@ -206,7 +216,7 @@ public class GLWindow extends DropTarget {
} }
} }
public void clearDropTargetListener() { private void clearDropTargetListener() {
if (dropListener != null) { if (dropListener != null) {
removeDropTargetListener(dropListener); removeDropTargetListener(dropListener);
dropListener = null; dropListener = null;

View file

@ -194,9 +194,11 @@ public class GuiSkins extends GuiScreen implements FutureCallback<SkinUploadResp
} }
private void enableDnd() { private void enableDnd() {
GLWindow.current().setDropTargetListener((FileDropListener) files -> { if (!mc.isFullScreen()) {
files.stream().findFirst().ifPresent(instance::loadLocalFile); GLWindow.current().setDropTargetListener((FileDropListener) files -> {
}); files.stream().findFirst().ifPresent(instance::loadLocalFile);
});
}
} }
private void initPanoramaRenderer() { private void initPanoramaRenderer() {
@ -210,7 +212,7 @@ public class GuiSkins extends GuiScreen implements FutureCallback<SkinUploadResp
remotePlayer.releaseTextures(); remotePlayer.releaseTextures();
HDSkinManager.clearSkinCache(); HDSkinManager.clearSkinCache();
GLWindow.current().clearDropTargetListener(); GLWindow.dispose();
} }
private void onFileOpenDialogClosed(JFileChooser fileDialog, int dialogResult) { private void onFileOpenDialogClosed(JFileChooser fileDialog, int dialogResult) {

View file

@ -1,78 +0,0 @@
package com.voxelmodpack.hdskins.mixin;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
import com.voxelmodpack.hdskins.gui.GLWindow;
import net.minecraft.client.Minecraft;
import net.minecraft.crash.CrashReport;
/**
* Mixin required to close the window after the game detects a crash.
*
* DO NOT REMOVE
*
* That means you, Killjoy.
*
*/
@Mixin(Minecraft.class)
public abstract class MixinMinecraft {
//
// Due to how JFrame works the only way to know for sure when the game hash crashed
// is to have it call us explicitly.
//
// ShutdownListener.onShutDown is unlikely to be called as it depends on the
// Minecraft.running flag to be unset, which is unlikely to happen if the game crashes.
//
// Runtime.current().addShutdownHook won't be called it waits for all
// non-daemon threads to end, one of which is depending on the JFrame being
// disposed to tell it when to end.
//
// If you're thinking 'hey, what about Minecraft.isCrashed?'
// No, that's only set if the internal MinecraftServer crashes.
// Otherwise the value is always false and threads spinning to check any such value
// will only serve to hang up the VM.
//
// But senpai, what about a warden thread joined on the main? I'm sure as soon as
// the main thread closes that would-
//
// Nope. It never runs.
//
// @forge
// Because the minecraft forge team are stupid, they call displayCrashReport on startup
// regardless of whether the game has crashed or not. Thus the window may flicker an additional
// time as the native window is forced back to the front.
// This is a minor issue as the window will simply reassert itself when it's next referenced
// (i.e. The skins GUI uses it for file drops) so I have no intention of fixing this.
//
// This is their problem.
//
// Update 09/06/2018:
// After inspecting the forge source this was found to be nothing but pure lies.
// The only place they call it is from FMLClientHandler#haltGame.
// There is still the possible case where another mod tries to call it,
// but that would be the very definition of 'misbehaving'.
//
// Also note that the method unconditionally calls System.exit, so anyone
// who does will be having a hard time.
//
// @killjoy
// Don't be afraid to use a mixin when the situation calls for it.
// There is no other way to do this.
//
// Do not remove.
//
// [!!!DO NOT REMOVE!!!]
//
// I'm serious, do not remove.
// I don't care how much of a vendeta you have aginst mixins.
//
//public void displayCrashReport(CrashReport crashReportIn)
@Inject(method = "displayCrashReport(Lnet/minecraft/crash/CrashReport;)V", at = @At("HEAD"))
private void onGameCrash(CrashReport report, CallbackInfo info) {
GLWindow.dispose();
}
}

View file

@ -4,7 +4,6 @@
"package": "com.voxelmodpack.hdskins.mixin", "package": "com.voxelmodpack.hdskins.mixin",
"refmap": "hdskins.mixin.refmap.json", "refmap": "hdskins.mixin.refmap.json",
"mixins": [ "mixins": [
"MixinMinecraft",
"MixinImageBufferDownload", "MixinImageBufferDownload",
"MixinPlayerInfo", "MixinPlayerInfo",
"MixinSkullRenderer" "MixinSkullRenderer"