/* * 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; import com.mojang.authlib.exceptions.AuthenticationUnavailableException; import com.mojang.authlib.exceptions.InvalidCredentialsException; import kr.syeyoung.dungeonsguide.launcher.exceptions.AuthServerException; import kr.syeyoung.dungeonsguide.launcher.authentication.Authenticator; import kr.syeyoung.dungeonsguide.launcher.branch.ModDownloader; 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.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; 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; @Mod(modid = Main.MOD_ID, version = Main.VERSION) public class Main { public static final String MOD_ID = "dungeons_guide_wrapper"; public static final String VERSION = "1.0"; public static final String DOMAIN = "http://testmachine:8080/api"; private static Main main; private File configDir; private DGInterface dgInterface; private Authenticator authenticator = new Authenticator(); private ModDownloader modDownloader = new ModDownloader(authenticator); private List listeners = new ArrayList<>(); public void addDGReloadListener(DungeonsGuideReloadListener dungeonsGuideReloadListener) { listeners.add(Objects.requireNonNull(dungeonsGuideReloadListener)); } public void removeDGReloadListener(DungeonsGuideReloadListener dungeonsGuideReloadListener) { listeners.remove(dungeonsGuideReloadListener); } private IDGLoader currentLoader; private Throwable lastError; private boolean isMcLoaded; @EventHandler public void initEvent(FMLInitializationEvent initializationEvent) { MinecraftForge.EVENT_BUS.register(this); if (dgInterface != null) { try { dgInterface.init(configDir); for (DungeonsGuideReloadListener listener : listeners) { listener.onLoad(dgInterface); } } catch (Exception e) { e.printStackTrace(); setLastFatalError(e); } } } public void unload() throws ReferenceLeakedException { if (currentLoader != null && !currentLoader.isUnloadable()) { throw new UnsupportedOperationException("Current version is not unloadable"); } dgInterface = null; for (DungeonsGuideReloadListener listener : listeners) { listener.unloadReference(); } if (currentLoader != null) { currentLoader.unloadJar(); } currentLoader = null; } private void load(IDGLoader newLoader) throws ClassNotFoundException, InstantiationException, IllegalAccessException { partialLoad(newLoader); dgInterface.init(configDir); for (DungeonsGuideReloadListener listener : listeners) { listener.onLoad(dgInterface); } } private void partialLoad(IDGLoader newLoader) throws ClassNotFoundException, InstantiationException, IllegalAccessException { if (dgInterface != null) throw new IllegalStateException("DG is loaded"); newLoader.loadJar(authenticator); dgInterface = newLoader.getInstance(); currentLoader = newLoader; } public void reload(IDGLoader newLoader) { try { unload(); load(newLoader); } catch (Exception e) { dgInterface = null; currentLoader = null; e.printStackTrace(); setLastFatalError(e); } } public void tryOpenError() { if (isMcLoaded) Minecraft.getMinecraft().displayGuiScreen(obtainErrorGUI()); } public GuiScreen obtainErrorGUI() { if (lastError instanceof PrivacyPolicyRequiredException) { } else if (lastError instanceof TokenExpiredException) { } else if (lastError instanceof NoSuitableLoaderFoundException) { } else if (lastError instanceof ReferenceLeakedException) { } else if (lastError instanceof AuthServerException) { } else if (lastError instanceof InvalidCredentialsException) { } else if (lastError instanceof AuthenticationUnavailableException) { } else if (lastError != null){ return new GuiLoadingError(lastError, () -> {lastError = null;}); } 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) { guiOpenEvent.gui = obtainErrorGUI(); } } public String getLoaderName(Configuration configuration) { String loader = System.getProperty("dg.loader"); if (loader == null) { loader = configuration.get("loader", "modsource", "auto").getString(); } if (loader == null) loader = "auto"; return loader; } public IDGLoader obtainLoader(Configuration configuration) { String loader = getLoaderName(configuration); if ("local".equals(loader) || (loader.equals("auto") && this.getClass().getResourceAsStream("/kr/syeyoung/dungeonsguide/DungeonsGuide.class") == null)) { return new LocalLoader(); } else if ("jar".equals(loader) || (loader.equals("auto") && this.getClass().getResourceAsStream("/mod.jar") == null)) { return new JarLoader(); } else if (loader.equals("auto") ){ // remote load throw new UnsupportedOperationException(""); // yet } else { throw new NoSuitableLoaderFoundException(System.getProperty("dg.loader"), configuration.get("loader", "modsource", "auto").getString()); } } @EventHandler public void preInit(FMLPreInitializationEvent preInitializationEvent) { // setup static variables main = this; configDir = preInitializationEvent.getModConfigurationDirectory(); // setup preinit progress bar for well, progress bar! ProgressManager.ProgressBar bar = ProgressManager.push("DungeonsGuide", 2); try { // Try authenticate bar.step("Authenticating..."); authenticator.repeatAuthenticate(5); // If authentication succeeds, obtain loader and partially load dungeons guide File f = new File(preInitializationEvent.getModConfigurationDirectory(), "loader.cfg"); Configuration configuration = new Configuration(f); bar.step("Instantiating..."); partialLoad(obtainLoader(configuration)); // Save config because... well to generate it configuration.save(); } catch (Throwable t) { dgInterface = null; currentLoader = null; t.printStackTrace(); setLastFatalError(t); } finally { while(bar.getStep() < bar.getSteps()) bar.step(""); ProgressManager.pop(bar); } ((IReloadableResourceManager) Minecraft.getMinecraft().getResourceManager()).registerReloadListener(a -> { if (dgInterface != null) dgInterface.onResourceReload(a); }); } public void setLastFatalError(Throwable t) { lastError = t; tryOpenError(); } public static Main getMain() { return main; } }