From 3708965c0c22c216336f8aa28158ba22bfc03b60 Mon Sep 17 00:00:00 2001 From: syeyoung Date: Wed, 16 Nov 2022 00:52:17 +0900 Subject: - Better Exception Handling Signed-off-by: syeyoung --- .../kr/syeyoung/dungeonsguide/launcher/Main.java | 104 +++++---------------- .../dungeonsguide/launcher/auth/AuthManager.java | 23 +++-- .../launcher/exceptions/AuthFailedExeption.java | 2 +- .../launcher/exceptions/AuthServerException.java | 2 +- .../AuthenticationUnavailableException.java | 12 +++ .../exceptions/PrivacyPolicyRequiredException.java | 2 +- .../launcher/exceptions/TokenExpiredException.java | 2 +- .../launcher/gui/GuiLoadingError.java | 90 ------------------ .../launcher/gui/GuiPrivacyPolicy.java | 53 ----------- .../launcher/gui/screen/GuiDisplayer.java | 44 +++++++++ .../launcher/gui/screen/GuiLoadingError.java | 86 +++++++++++++++++ .../launcher/gui/screen/GuiPrivacyPolicy.java | 49 ++++++++++ .../launcher/gui/screen/GuiReferenceLeak.java | 90 ++++++++++++++++++ .../launcher/gui/screen/SpecialGuiScreen.java | 17 ++++ .../launcher/loader/RemoteLoader.java | 55 +++++++++++ 15 files changed, 398 insertions(+), 233 deletions(-) create mode 100644 loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/AuthenticationUnavailableException.java delete mode 100644 loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/gui/GuiLoadingError.java delete mode 100644 loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/gui/GuiPrivacyPolicy.java create mode 100644 loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/gui/screen/GuiDisplayer.java create mode 100644 loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/gui/screen/GuiLoadingError.java create mode 100644 loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/gui/screen/GuiPrivacyPolicy.java create mode 100644 loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/gui/screen/GuiReferenceLeak.java create mode 100644 loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/gui/screen/SpecialGuiScreen.java (limited to 'loader/src') diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/Main.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/Main.java index efba137d..0ec65780 100755 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/Main.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/Main.java @@ -18,24 +18,18 @@ package kr.syeyoung.dungeonsguide.launcher; -import com.mojang.authlib.exceptions.AuthenticationUnavailableException; -import com.mojang.authlib.exceptions.InvalidCredentialsException; import kr.syeyoung.dungeonsguide.launcher.auth.AuthManager; -import kr.syeyoung.dungeonsguide.launcher.exceptions.AuthServerException; import kr.syeyoung.dungeonsguide.launcher.exceptions.NoSuitableLoaderFoundException; -import kr.syeyoung.dungeonsguide.launcher.exceptions.PrivacyPolicyRequiredException; import kr.syeyoung.dungeonsguide.launcher.exceptions.ReferenceLeakedException; -import kr.syeyoung.dungeonsguide.launcher.exceptions.TokenExpiredException; -import kr.syeyoung.dungeonsguide.launcher.gui.GuiLoadingError; -import kr.syeyoung.dungeonsguide.launcher.gui.GuiPrivacyPolicy; +import kr.syeyoung.dungeonsguide.launcher.gui.screen.GuiDisplayer; +import kr.syeyoung.dungeonsguide.launcher.gui.screen.GuiLoadingError; +import kr.syeyoung.dungeonsguide.launcher.gui.screen.GuiReferenceLeak; +import kr.syeyoung.dungeonsguide.launcher.gui.screen.SpecialGuiScreen; import kr.syeyoung.dungeonsguide.launcher.loader.IDGLoader; import kr.syeyoung.dungeonsguide.launcher.loader.JarLoader; import kr.syeyoung.dungeonsguide.launcher.loader.LocalLoader; import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiMainMenu; -import net.minecraft.client.gui.GuiScreen; import net.minecraft.client.resources.IReloadableResourceManager; -import net.minecraftforge.client.event.GuiOpenEvent; import net.minecraftforge.common.MinecraftForge; import net.minecraftforge.common.config.Configuration; import net.minecraftforge.fml.common.Mod; @@ -43,13 +37,9 @@ import net.minecraftforge.fml.common.Mod.EventHandler; import net.minecraftforge.fml.common.ProgressManager; import net.minecraftforge.fml.common.event.FMLInitializationEvent; import net.minecraftforge.fml.common.event.FMLPreInitializationEvent; -import net.minecraftforge.fml.common.eventhandler.EventPriority; -import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import java.io.*; -import java.util.ArrayList; -import java.util.List; -import java.util.Objects; +import java.util.*; @Mod(modid = Main.MOD_ID, version = Main.VERSION) public class Main @@ -78,28 +68,18 @@ public class Main } private IDGLoader currentLoader; - - private Throwable lastError; - private boolean isMcLoaded; - - - - @EventHandler - public void initEvent(FMLInitializationEvent initializationEvent) - { + public void initEvent(FMLInitializationEvent initializationEvent) throws ClassNotFoundException, InstantiationException, IllegalAccessException { MinecraftForge.EVENT_BUS.register(this); - if (dgInterface != null) { - try { - dgInterface.init(configDir); + MinecraftForge.EVENT_BUS.register(GuiDisplayer.INSTANCE); - for (DungeonsGuideReloadListener listener : listeners) { - listener.onLoad(dgInterface); - } - } catch (Exception e) { - e.printStackTrace(); - setLastFatalError(e); - } + try { + File f = new File(configDir, "loader.cfg"); + Configuration configuration = new Configuration(f); + IDGLoader idgLoader = obtainLoader(configuration); + load(idgLoader); + } catch (Throwable e) { + GuiDisplayer.INSTANCE.displayGui(obtainErrorGUI(e)); } } @@ -117,7 +97,9 @@ public class Main currentLoader = null; } private void load(IDGLoader newLoader) throws ClassNotFoundException, InstantiationException, IllegalAccessException { - partialLoad(newLoader); + if (dgInterface != null) throw new IllegalStateException("DG is loaded"); + dgInterface = newLoader.loadDungeonsGuide(); + currentLoader = newLoader; dgInterface.init(configDir); @@ -125,12 +107,6 @@ public class Main listener.onLoad(dgInterface); } } - private void partialLoad(IDGLoader newLoader) throws ClassNotFoundException, InstantiationException, IllegalAccessException { - if (dgInterface != null) throw new IllegalStateException("DG is loaded"); - dgInterface = newLoader.loadDungeonsGuide(); - currentLoader = newLoader; - } - public void reload(IDGLoader newLoader) { try { unload(); @@ -140,49 +116,25 @@ public class Main currentLoader = null; e.printStackTrace(); - setLastFatalError(e); - } - } - public void tryOpenError() { - if (isMcLoaded) Minecraft.getMinecraft().displayGuiScreen(obtainErrorGUI()); + GuiDisplayer.INSTANCE.displayGui(obtainErrorGUI(e)); + } } - public GuiScreen obtainErrorGUI() { - if (lastError instanceof PrivacyPolicyRequiredException) { - return new GuiPrivacyPolicy(); - } else if (lastError instanceof TokenExpiredException) { - + public SpecialGuiScreen obtainErrorGUI(Throwable lastError) { + if (lastError instanceof kr.syeyoung.dungeonsguide.launcher.exceptions.AuthenticationUnavailableException) { + return null; } else if (lastError instanceof NoSuitableLoaderFoundException) { - + return new GuiLoadingError(lastError); } else if (lastError instanceof ReferenceLeakedException) { - - } else if (lastError instanceof AuthServerException) { - - } else if (lastError instanceof InvalidCredentialsException) { - - } else if (lastError instanceof AuthenticationUnavailableException) { - + return new GuiReferenceLeak(lastError); } else if (lastError != null){ - return new GuiLoadingError(lastError, () -> {lastError = null;}); + return new GuiLoadingError(lastError); } - if (lastError != null) - lastError.printStackTrace(); // when gets called init and stuff remove thing return null; } - @SubscribeEvent(priority = EventPriority.LOWEST) - public void onGuiOpen(GuiOpenEvent guiOpenEvent) { - if (guiOpenEvent.gui instanceof GuiMainMenu) { - isMcLoaded = true; - } - if (lastError != null && guiOpenEvent.gui instanceof GuiMainMenu) { - GuiScreen gui = obtainErrorGUI(); - if (gui != null) - guiOpenEvent.gui = gui; - } - } public String getLoaderName(Configuration configuration) { String loader = System.getProperty("dg.loader"); @@ -236,7 +188,6 @@ public class Main currentLoader = null; t.printStackTrace(); - setLastFatalError(t); } finally { while(bar.getStep() < bar.getSteps()) bar.step(""); ProgressManager.pop(bar); @@ -247,11 +198,6 @@ public class Main }); } - public void setLastFatalError(Throwable t) { - lastError = t; - tryOpenError(); - } - public static Main getMain() { return main; } diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/AuthManager.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/AuthManager.java index 5aa6962b..1613e687 100644 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/AuthManager.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/auth/AuthManager.java @@ -2,12 +2,13 @@ package kr.syeyoung.dungeonsguide.launcher.auth; import com.google.common.base.Throwables; import com.google.common.util.concurrent.ThreadFactoryBuilder; -import com.google.gson.JsonObject; import com.mojang.authlib.exceptions.AuthenticationException; import kr.syeyoung.dungeonsguide.launcher.auth.token.*; import kr.syeyoung.dungeonsguide.launcher.events.AuthChangedEvent; import kr.syeyoung.dungeonsguide.launcher.exceptions.AuthFailedExeption; import kr.syeyoung.dungeonsguide.launcher.exceptions.PrivacyPolicyRequiredException; +import kr.syeyoung.dungeonsguide.launcher.gui.screen.GuiDisplayer; +import kr.syeyoung.dungeonsguide.launcher.gui.screen.GuiPrivacyPolicy; import lombok.Setter; import net.minecraft.client.Minecraft; import net.minecraftforge.common.MinecraftForge; @@ -19,10 +20,8 @@ import javax.crypto.IllegalBlockSizeException; import javax.crypto.NoSuchPaddingException; import java.io.IOException; import java.security.InvalidKeyException; -import java.security.KeyPair; import java.security.NoSuchAlgorithmException; import java.security.spec.InvalidKeySpecException; -import java.util.Objects; import java.util.concurrent.*; @@ -49,16 +48,23 @@ public class AuthManager { else return null; } + public String getWorkingTokenOrThrow() { + if (currentToken instanceof DGAuthToken) return currentToken.getToken(); + else if (currentToken instanceof FailedAuthToken) throw new AuthFailedExeption(((FailedAuthToken) currentToken).getException()); + else if (currentToken instanceof NullToken) throw new IllegalStateException("No Token"); + else if (currentToken instanceof PrivacyPolicyRequiredToken) throw new PrivacyPolicyRequiredException(); + throw new IllegalStateException("weird token: "+currentToken); + } + private volatile boolean initlock = false; public void init() { if (initlock) { logger.info("Cannot init AuthManger twice"); - return; + throw new IllegalStateException("Can not init AuthManager twice"); } - initlock = true; ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("DgAuth Pool").build(); @@ -85,7 +91,7 @@ public class AuthManager { AuthToken reAuth() { if (reauthLock) { - while(reauthLock); + while (reauthLock) ; return currentToken; } @@ -97,7 +103,10 @@ public class AuthManager { currentToken = DgAuthUtil.verifyAuth(token, encSecret, baseserverurl); MinecraftForge.EVENT_BUS.post(new AuthChangedEvent(currentToken)); - if (currentToken instanceof PrivacyPolicyRequiredToken) throw new PrivacyPolicyRequiredException(); + if (currentToken instanceof PrivacyPolicyRequiredToken) { + GuiDisplayer.INSTANCE.displayGui(new GuiPrivacyPolicy()); + throw new PrivacyPolicyRequiredException(); + } } catch (NoSuchAlgorithmException | AuthenticationException | IOException | NoSuchPaddingException | InvalidKeyException | InvalidKeySpecException | IllegalBlockSizeException | BadPaddingException e) { currentToken = new FailedAuthToken(e); diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/AuthFailedExeption.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/AuthFailedExeption.java index 881f7a1e..d860afb6 100644 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/AuthFailedExeption.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/AuthFailedExeption.java @@ -1,6 +1,6 @@ package kr.syeyoung.dungeonsguide.launcher.exceptions; -public class AuthFailedExeption extends RuntimeException { +public class AuthFailedExeption extends AuthenticationUnavailableException { public AuthFailedExeption(Throwable cause) { super(cause); } diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/AuthServerException.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/AuthServerException.java index 1c7a44af..67647b9b 100644 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/AuthServerException.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/AuthServerException.java @@ -24,7 +24,7 @@ import org.json.JSONObject; import java.util.Objects; -public class AuthServerException extends RuntimeException { +public class AuthServerException extends AuthenticationUnavailableException { private DGResponse response; public AuthServerException(DGResponse response) { diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/AuthenticationUnavailableException.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/AuthenticationUnavailableException.java new file mode 100644 index 00000000..a42ddd93 --- /dev/null +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/AuthenticationUnavailableException.java @@ -0,0 +1,12 @@ +package kr.syeyoung.dungeonsguide.launcher.exceptions; + +public class AuthenticationUnavailableException extends RuntimeException { + public AuthenticationUnavailableException(Throwable cause){ + super(cause); + } + + public AuthenticationUnavailableException(String s) { + super(s); + } + public AuthenticationUnavailableException() {} +} diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/PrivacyPolicyRequiredException.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/PrivacyPolicyRequiredException.java index 006e03ca..a48632dc 100644 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/PrivacyPolicyRequiredException.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/PrivacyPolicyRequiredException.java @@ -18,5 +18,5 @@ package kr.syeyoung.dungeonsguide.launcher.exceptions; -public class PrivacyPolicyRequiredException extends RuntimeException{ +public class PrivacyPolicyRequiredException extends AuthenticationUnavailableException { } diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/TokenExpiredException.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/TokenExpiredException.java index 2c115e2f..4826b1ba 100644 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/TokenExpiredException.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/exceptions/TokenExpiredException.java @@ -18,7 +18,7 @@ package kr.syeyoung.dungeonsguide.launcher.exceptions; -public class TokenExpiredException extends RuntimeException{ +public class TokenExpiredException extends AuthenticationUnavailableException { public TokenExpiredException(Throwable parent) { super(parent); diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/gui/GuiLoadingError.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/gui/GuiLoadingError.java deleted file mode 100644 index f699b1d7..00000000 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/gui/GuiLoadingError.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod - * Copyright (C) 2021 cyoung06 - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU Affero General Public License as published - * by the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Affero General Public License for more details. - * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . - */ - -package kr.syeyoung.dungeonsguide.launcher.gui; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.*; -import net.minecraftforge.fml.common.FMLCommonHandler; -import org.lwjgl.opengl.GL11; - -import java.io.ByteArrayOutputStream; -import java.io.IOException; -import java.io.PrintStream; - -public class GuiLoadingError extends GuiScreen { - static Throwable cause; - private final String stacktrace; - private final GuiScreen originalGUI; - public GuiLoadingError(GuiScreen originalGUI) { - - ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); - PrintStream printStream = new PrintStream(byteArrayOutputStream); - cause.printStackTrace(printStream); - this.stacktrace = byteArrayOutputStream.toString(); - - this.originalGUI = originalGUI; - } - - @Override - public void initGui() { - ScaledResolution sr = new ScaledResolution(Minecraft.getMinecraft()); - this.buttonList.add(new GuiButton(0, sr.getScaledWidth()/2-100,sr.getScaledHeight()-70 ,"Close Minecraft")); - this.buttonList.add(new GuiButton(1, sr.getScaledWidth()/2-100,sr.getScaledHeight()-40 ,"Play Without DG")); - } - - @Override - protected void actionPerformed(GuiButton button) throws IOException { - super.actionPerformed(button); - if (button.id == 0) { - FMLCommonHandler.instance().exitJava(-1,true); - } else if (button.id == 1) { - Minecraft.getMinecraft().displayGuiScreen(originalGUI); - } - } - - @Override - public void drawScreen(int mouseX, int mouseY, float partialTicks) { - super.drawBackground(1); - - ScaledResolution sr = new ScaledResolution(Minecraft.getMinecraft()); - FontRenderer fontRenderer = Minecraft.getMinecraft().fontRendererObj; - fontRenderer.drawString("DungeonsGuide has ran into error while loading itself", (sr.getScaledWidth()-fontRenderer.getStringWidth("DungeonsGuide has ran into error while loading itself"))/2,40,0xFFFF0000); - fontRenderer.drawString("Please contact DungeonsGuide support with this screen", (sr.getScaledWidth()-fontRenderer.getStringWidth("Please contact developer with this screen"))/2, (int) (40+fontRenderer.FONT_HEIGHT*1.5),0xFFFF0000); - - int tenth = sr.getScaledWidth() / 10; - - Gui.drawRect(tenth, 70,sr.getScaledWidth()-tenth, sr.getScaledHeight()-80, 0xFF5B5B5B); - String[] split = stacktrace.split("\n"); - clip(sr, tenth, 70,sr.getScaledWidth()-2*tenth, sr.getScaledHeight()-150); - GL11.glEnable(GL11.GL_SCISSOR_TEST); - for (int i = 0; i < split.length; i++) { - fontRenderer.drawString(split[i].replace("\t", " "), tenth+2,i*fontRenderer.FONT_HEIGHT + 72, 0xFFFFFFFF); - } - GL11.glDisable(GL11.GL_SCISSOR_TEST); - - super.drawScreen(mouseX, mouseY, partialTicks); - } - - public static void clip(ScaledResolution resolution, int x, int y, int width, int height) { - if (width < 0 || height < 0) return; - - int scale = resolution.getScaleFactor(); - GL11.glScissor((x ) * scale, Minecraft.getMinecraft().displayHeight - (y + height) * scale, (width) * scale, height * scale); - } -} diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/gui/GuiPrivacyPolicy.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/gui/GuiPrivacyPolicy.java deleted file mode 100644 index b7d21b16..00000000 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/gui/GuiPrivacyPolicy.java +++ /dev/null @@ -1,53 +0,0 @@ -package kr.syeyoung.dungeonsguide.launcher.gui; - -import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.*; -import net.minecraft.client.renderer.GlStateManager; -import net.minecraft.client.renderer.Tessellator; -import net.minecraft.client.renderer.WorldRenderer; -import net.minecraft.client.renderer.vertex.DefaultVertexFormats; -import net.minecraftforge.fml.common.FMLCommonHandler; -import org.lwjgl.opengl.GL11; - -import java.io.IOException; - -public class GuiPrivacyPolicy extends GuiScreen { - @Override - public void initGui() { - ScaledResolution sr = new ScaledResolution(Minecraft.getMinecraft()); - this.buttonList.add(new GuiButton(0, sr.getScaledWidth()/2+50,sr.getScaledHeight()-40, 300, 20,"Accept Privacy Policy")); - this.buttonList.add(new GuiButton(1, sr.getScaledWidth()/2-50-300,sr.getScaledHeight()-40, 300, 20,"Deny and Play Without DG")); - } - - - @Override - protected void actionPerformed(GuiButton button) throws IOException { - super.actionPerformed(button); - if (button.id == 0) { - // accept - } else if (button.id == 1) { - Minecraft.getMinecraft().displayGuiScreen(null); - } - } - - - @Override - public void drawScreen(int mouseX, int mouseY, float partialTicks) { - super.drawBackground(0); - - ScaledResolution sr = new ScaledResolution(Minecraft.getMinecraft()); - FontRenderer fontRenderer = Minecraft.getMinecraft().fontRendererObj; - - fontRenderer.drawString("", (sr.getScaledWidth()-fontRenderer.getStringWidth("Please accept or deny Dungeons Guide Privacy Policy to continue"))/2,40,0xFFFF0000); - - - super.drawScreen(mouseX, mouseY, partialTicks); - } - - public static void clip(ScaledResolution resolution, int x, int y, int width, int height) { - if (width < 0 || height < 0) return; - - int scale = resolution.getScaleFactor(); - GL11.glScissor((x ) * scale, Minecraft.getMinecraft().displayHeight - (y + height) * scale, (width) * scale, height * scale); - } -} diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/gui/screen/GuiDisplayer.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/gui/screen/GuiDisplayer.java new file mode 100644 index 00000000..ab772e5d --- /dev/null +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/gui/screen/GuiDisplayer.java @@ -0,0 +1,44 @@ +package kr.syeyoung.dungeonsguide.launcher.gui.screen; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiMainMenu; +import net.minecraftforge.client.event.GuiOpenEvent; +import net.minecraftforge.fml.common.eventhandler.EventPriority; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; + +import java.util.LinkedList; +import java.util.Queue; + +public class GuiDisplayer { + public static GuiDisplayer INSTANCE = new GuiDisplayer(); + private GuiDisplayer() {} + + private Queue guiScreensToShow = new LinkedList<>(); + private boolean isMcLoaded; + + + @SubscribeEvent(priority = EventPriority.LOWEST) + public void onGuiOpen(GuiOpenEvent guiOpenEvent) { + if (guiOpenEvent.gui instanceof GuiMainMenu) { + isMcLoaded = true; + } + if (guiScreensToShow.size() > 0 && guiOpenEvent.gui != guiScreensToShow.peek()) { + SpecialGuiScreen gui = guiScreensToShow.peek(); + if (gui == null) return; + gui.setOnDismiss(guiScreensToShow::poll); + guiOpenEvent.gui = gui; + } + } + + public void displayGui(SpecialGuiScreen specialGuiScreen) { + if (specialGuiScreen == null) return; + if (!guiScreensToShow.contains(specialGuiScreen)) + guiScreensToShow.add(specialGuiScreen); + if (isMcLoaded) { + SpecialGuiScreen gui = guiScreensToShow.peek(); + if (gui == null) return; + gui.setOnDismiss(guiScreensToShow::poll); + Minecraft.getMinecraft().displayGuiScreen(gui); + } + } +} diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/gui/screen/GuiLoadingError.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/gui/screen/GuiLoadingError.java new file mode 100644 index 00000000..436d5d8c --- /dev/null +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/gui/screen/GuiLoadingError.java @@ -0,0 +1,86 @@ +/* + * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod + * Copyright (C) 2021 cyoung06 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package kr.syeyoung.dungeonsguide.launcher.gui.screen; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.*; +import net.minecraftforge.fml.common.FMLCommonHandler; +import org.lwjgl.opengl.GL11; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; + +public class GuiLoadingError extends SpecialGuiScreen { + private final String stacktrace; + public GuiLoadingError(Throwable cause) { + + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + PrintStream printStream = new PrintStream(byteArrayOutputStream); + cause.printStackTrace(printStream); + this.stacktrace = byteArrayOutputStream.toString(); + } + + @Override + public void initGui() { + ScaledResolution sr = new ScaledResolution(Minecraft.getMinecraft()); + this.buttonList.add(new GuiButton(0, sr.getScaledWidth()/2-100,sr.getScaledHeight()-70 ,"Close Minecraft")); + this.buttonList.add(new GuiButton(1, sr.getScaledWidth()/2-100,sr.getScaledHeight()-40 ,"Play Without DG")); + } + + @Override + protected void actionPerformed(GuiButton button) throws IOException { + super.actionPerformed(button); + if (button.id == 0) { + FMLCommonHandler.instance().exitJava(-1,true); + } else if (button.id == 1) { + dismiss(); + } + } + + @Override + public void drawScreen(int mouseX, int mouseY, float partialTicks) { + super.drawBackground(1); + + ScaledResolution sr = new ScaledResolution(Minecraft.getMinecraft()); + FontRenderer fontRenderer = Minecraft.getMinecraft().fontRendererObj; + fontRenderer.drawString("DungeonsGuide has ran into error while loading itself", (sr.getScaledWidth()-fontRenderer.getStringWidth("DungeonsGuide has ran into error while loading itself"))/2,40,0xFFFF0000); + fontRenderer.drawString("Please contact DungeonsGuide support with this screen", (sr.getScaledWidth()-fontRenderer.getStringWidth("Please contact developer with this screen"))/2, (int) (40+fontRenderer.FONT_HEIGHT*1.5),0xFFFF0000); + + int tenth = sr.getScaledWidth() / 10; + + Gui.drawRect(tenth, 70,sr.getScaledWidth()-tenth, sr.getScaledHeight()-80, 0xFF5B5B5B); + String[] split = stacktrace.split("\n"); + clip(sr, tenth, 70,sr.getScaledWidth()-2*tenth, sr.getScaledHeight()-150); + GL11.glEnable(GL11.GL_SCISSOR_TEST); + for (int i = 0; i < split.length; i++) { + fontRenderer.drawString(split[i].replace("\t", " "), tenth+2,i*fontRenderer.FONT_HEIGHT + 72, 0xFFFFFFFF); + } + GL11.glDisable(GL11.GL_SCISSOR_TEST); + + super.drawScreen(mouseX, mouseY, partialTicks); + } + + public static void clip(ScaledResolution resolution, int x, int y, int width, int height) { + if (width < 0 || height < 0) return; + + int scale = resolution.getScaleFactor(); + GL11.glScissor((x ) * scale, Minecraft.getMinecraft().displayHeight - (y + height) * scale, (width) * scale, height * scale); + } +} diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/gui/screen/GuiPrivacyPolicy.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/gui/screen/GuiPrivacyPolicy.java new file mode 100644 index 00000000..f7acb18a --- /dev/null +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/gui/screen/GuiPrivacyPolicy.java @@ -0,0 +1,49 @@ +package kr.syeyoung.dungeonsguide.launcher.gui.screen; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.*; +import org.lwjgl.opengl.GL11; + +import java.io.IOException; + +public class GuiPrivacyPolicy extends SpecialGuiScreen { + @Override + public void initGui() { + ScaledResolution sr = new ScaledResolution(Minecraft.getMinecraft()); + this.buttonList.add(new GuiButton(0, sr.getScaledWidth()/2+50,sr.getScaledHeight()-40, 300, 20,"Accept Privacy Policy")); + this.buttonList.add(new GuiButton(1, sr.getScaledWidth()/2-50-300,sr.getScaledHeight()-40, 300, 20,"Deny and Play Without DG")); + } + + + @Override + protected void actionPerformed(GuiButton button) throws IOException { + super.actionPerformed(button); + if (button.id == 0) { + // accept + dismiss(); + } else if (button.id == 1) { + dismiss(); + } + } + + + @Override + public void drawScreen(int mouseX, int mouseY, float partialTicks) { + super.drawBackground(0); + + ScaledResolution sr = new ScaledResolution(Minecraft.getMinecraft()); + FontRenderer fontRenderer = Minecraft.getMinecraft().fontRendererObj; + + fontRenderer.drawString("Please accept or deny Dungeons Guide Privacy Policy to continue", (sr.getScaledWidth()-fontRenderer.getStringWidth("Please accept or deny Dungeons Guide Privacy Policy to continue"))/2,40,0xFFFF0000); + + + super.drawScreen(mouseX, mouseY, partialTicks); + } + + public static void clip(ScaledResolution resolution, int x, int y, int width, int height) { + if (width < 0 || height < 0) return; + + int scale = resolution.getScaleFactor(); + GL11.glScissor((x ) * scale, Minecraft.getMinecraft().displayHeight - (y + height) * scale, (width) * scale, height * scale); + } +} diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/gui/screen/GuiReferenceLeak.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/gui/screen/GuiReferenceLeak.java new file mode 100644 index 00000000..9c0a5980 --- /dev/null +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/gui/screen/GuiReferenceLeak.java @@ -0,0 +1,90 @@ +/* + * Dungeons Guide - The most intelligent Hypixel Skyblock Dungeons Mod + * Copyright (C) 2021 cyoung06 + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as published + * by the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + */ + +package kr.syeyoung.dungeonsguide.launcher.gui.screen; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.FontRenderer; +import net.minecraft.client.gui.Gui; +import net.minecraft.client.gui.GuiButton; +import net.minecraft.client.gui.ScaledResolution; +import net.minecraftforge.fml.common.FMLCommonHandler; +import org.lwjgl.opengl.GL11; + +import java.io.ByteArrayOutputStream; +import java.io.IOException; +import java.io.PrintStream; + +public class GuiReferenceLeak extends SpecialGuiScreen { + private final String stacktrace; + public GuiReferenceLeak(Throwable cause) { + + ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); + PrintStream printStream = new PrintStream(byteArrayOutputStream); + cause.printStackTrace(printStream); + this.stacktrace = byteArrayOutputStream.toString(); + } + + @Override + public void initGui() { + ScaledResolution sr = new ScaledResolution(Minecraft.getMinecraft()); + this.buttonList.add(new GuiButton(0, sr.getScaledWidth()/2-100,sr.getScaledHeight()-70 ,"Close Minecraft")); + this.buttonList.add(new GuiButton(1, sr.getScaledWidth()/2-100,sr.getScaledHeight()-40 ,"Play With DG in Inconsistent State")); + } + + @Override + protected void actionPerformed(GuiButton button) throws IOException { + super.actionPerformed(button); + if (button.id == 0) { + FMLCommonHandler.instance().exitJava(-1,true); + } else if (button.id == 1) { + dismiss(); + } + } + + @Override + public void drawScreen(int mouseX, int mouseY, float partialTicks) { + super.drawBackground(1); + + ScaledResolution sr = new ScaledResolution(Minecraft.getMinecraft()); + FontRenderer fontRenderer = Minecraft.getMinecraft().fontRendererObj; + fontRenderer.drawString("DungeonsGuide has ran into error while reloading", (sr.getScaledWidth()-fontRenderer.getStringWidth("DungeonsGuide has ran into error while reloading"))/2,40,0xFFFF0000); + fontRenderer.drawString("Please contact DungeonsGuide support with this screen", (sr.getScaledWidth()-fontRenderer.getStringWidth("Please contact developer with this screen"))/2, (int) (40+fontRenderer.FONT_HEIGHT*1.5),0xFFFF0000); + fontRenderer.drawString("Playing in this state is VERY UNSUGGESTED. Undesired behaviors might occur.", (sr.getScaledWidth()-fontRenderer.getStringWidth("Playing in this state is VERY UNSUGGESTED. Undesired behaviors might occur."))/2, (int) (40+fontRenderer.FONT_HEIGHT*3),0xFFFF0000); + + int tenth = sr.getScaledWidth() / 10; + + Gui.drawRect(tenth, 90,sr.getScaledWidth()-tenth, sr.getScaledHeight()-80, 0xFF5B5B5B); + String[] split = stacktrace.split("\n"); + clip(sr, tenth, 90,sr.getScaledWidth()-2*tenth, sr.getScaledHeight()-150); + GL11.glEnable(GL11.GL_SCISSOR_TEST); + for (int i = 0; i < split.length; i++) { + fontRenderer.drawString(split[i].replace("\t", " "), tenth+2,i*fontRenderer.FONT_HEIGHT + 92, 0xFFFFFFFF); + } + GL11.glDisable(GL11.GL_SCISSOR_TEST); + + super.drawScreen(mouseX, mouseY, partialTicks); + } + + public static void clip(ScaledResolution resolution, int x, int y, int width, int height) { + if (width < 0 || height < 0) return; + + int scale = resolution.getScaleFactor(); + GL11.glScissor((x ) * scale, Minecraft.getMinecraft().displayHeight - (y + height) * scale, (width) * scale, height * scale); + } +} diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/gui/screen/SpecialGuiScreen.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/gui/screen/SpecialGuiScreen.java new file mode 100644 index 00000000..0a9f2602 --- /dev/null +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/gui/screen/SpecialGuiScreen.java @@ -0,0 +1,17 @@ +package kr.syeyoung.dungeonsguide.launcher.gui.screen; + +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiScreen; + +public abstract class SpecialGuiScreen extends GuiScreen { + + private Runnable onDismiss; + public void setOnDismiss(Runnable dismissed) { + this.onDismiss = dismissed; + } + + protected void dismiss() { + onDismiss.run(); + Minecraft.getMinecraft().displayGuiScreen(null); + } +} diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/RemoteLoader.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/RemoteLoader.java index f3baaa9d..98155245 100644 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/RemoteLoader.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/RemoteLoader.java @@ -3,10 +3,65 @@ package kr.syeyoung.dungeonsguide.launcher.loader; import kr.syeyoung.dungeonsguide.launcher.DGInterface; import kr.syeyoung.dungeonsguide.launcher.exceptions.ReferenceLeakedException; +import java.lang.ref.PhantomReference; +import java.lang.ref.ReferenceQueue; +import java.net.URL; +import java.net.URLClassLoader; + public class RemoteLoader implements IDGLoader { private String branch; private String version; + + private ReferenceQueue refQueue = new ReferenceQueue<>(); + private PhantomReference phantomReference; + + private boolean loaded; + + public static class JarClassLoader extends URLClassLoader { + public JarClassLoader(URL[] urls, ClassLoader parent) { + super(urls, parent); + } + + @Override + protected Class loadClass(String name, boolean resolve) throws ClassNotFoundException { + + synchronized (getClassLoadingLock(name)) { + Class c = findLoadedClass(name); + if (c == null) { + + try { + if (c == null) { + long t0 = System.nanoTime(); + c = findClass(name); + + sun.misc.PerfCounter.getFindClassTime().addElapsedTimeFrom(t0); + sun.misc.PerfCounter.getFindClasses().increment(); + } + } catch (ClassNotFoundException e) { + // ClassNotFoundException thrown if class not found + // from the non-null parent class loader + } + if (getParent() != null && c == null) { + long t0 = System.nanoTime(); + c = getParent().loadClass(name); + long t1 = System.nanoTime(); + sun.misc.PerfCounter.getParentDelegationTime().addTime(t1 - t0); + } + } + if (resolve) { + resolveClass(c); + } + return c; + } + } + + public Class loadClassResolve(String name, boolean resolve) throws ClassNotFoundException { + return this.loadClass(name, resolve); + } + } + + private JarLoader.JarClassLoader classLoader; @Override public DGInterface loadDungeonsGuide() throws InstantiationException, IllegalAccessException, ClassNotFoundException { return null; -- cgit