diff options
author | syeyoung <cyoung06@naver.com> | 2022-11-17 19:19:49 +0900 |
---|---|---|
committer | syeyoung <cyoung06@naver.com> | 2022-11-17 19:19:49 +0900 |
commit | 7a698d3d7e06684419c1c7a99cd59f41fee99524 (patch) | |
tree | cc4596d4176e28741542e677d1243eae44c3b0e6 | |
parent | f033c34b2e2a7824df41ea750b66b21685462279 (diff) | |
download | Skyblock-Dungeons-Guide-7a698d3d7e06684419c1c7a99cd59f41fee99524.tar.gz Skyblock-Dungeons-Guide-7a698d3d7e06684419c1c7a99cd59f41fee99524.tar.bz2 Skyblock-Dungeons-Guide-7a698d3d7e06684419c1c7a99cd59f41fee99524.zip |
- Transformer to inject custom ASMEventHandler to handle classloader inconsistency issue
- Transformer to transform Event classes, because FML for some reason injects some stuff
- Move all event registration into DungeonsGuide.java
Signed-off-by: syeyoung <cyoung06@naver.com>
23 files changed, 610 insertions, 220 deletions
diff --git a/build.gradle b/build.gradle deleted file mode 100644 index 7252969e..00000000 --- a/build.gradle +++ /dev/null @@ -1,147 +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 <https://www.gnu.org/licenses/>. - */ - -plugins { - id "idea" - id "java" - id "com.github.johnrengelman.shadow" version "7.1.2" - id "dev.architectury.architectury-pack200" version "0.1.3" - id "gg.essential.loom" version "0.10.0.+" -} - -tasks.wrapper { - gradleVersion = "7.4" - // You can either download the binary-only version of Gradle (BIN) or - // the full version (with sources and documentation) of Gradle (ALL) - distributionType = Wrapper.DistributionType.ALL -} -version = "3.8.0" -group = "kr.syeyoung.dungeonsguide" -archivesBaseName = "dungeonsguide" - -java { - toolchain.languageVersion.set(JavaLanguageVersion.of(8)) -} - -loom { - launchConfigs { - client { - } - } - runs { - "client" { - property('devauth.enabled','true') - client() - } - } - forge { - pack200Provider.set(new dev.architectury.pack200.java.Pack200Adapter()) - } -} - - -sourceSets.main { - output.setResourcesDir(file("$buildDir/classes/java/main")) -} - - -repositories { - mavenCentral() - maven { url "https://jitpack.io" } - maven {url "https://pkgs.dev.azure.com/djtheredstoner/DevAuth/_packaging/public/maven/v1"} -} - -configurations { - implementation.extendsFrom shadowImpl -} - - -dependencies { - minecraft("com.mojang:minecraft:1.8.9") - mappings("de.oceanlabs.mcp:mcp_stable:22-1.8.9") - forge("net.minecraftforge:forge:1.8.9-11.15.1.2318-1.8.9") - - - implementation 'org.jetbrains:annotations-java5:23.0.0' - implementation 'org.java-websocket:Java-WebSocket:1.5.3' - implementation "org.json:json:20220924" - implementation 'com.twelvemonkeys.imageio:imageio-bmp:3.8.3' - - compileOnly 'org.projectlombok:lombok:1.18.24' - annotationProcessor 'org.projectlombok:lombok:1.18.24' - - compileOnly files("jars/Hychat-1.12.1-BETA.jar") - - testCompileOnly "org.projectlombok:lombok:1.18.24" - testAnnotationProcessor "org.projectlombok:lombok:1.18.24" - modRuntimeOnly("me.djtheredstoner:DevAuth-forge-legacy:1.1.0") -} - -tasks.withType(JavaCompile) { - options.encoding = "UTF-8" -} - -tasks.withType(Jar) { - archivesBaseName = "dungeonsguide" - manifest { - attributes["FMLCorePluginContainsFMLMod"] = "true" - attributes["ForceLoadAsMod"] = "true" - - // If you don't want mixins, remove these lines -// this["TweakClass"] = "org.spongepowered.asm.launch.MixinTweaker" -// this["MixinConfigs"] = "mixins.examplemod.json" - } -} - - -tasks.shadowJar { - - archiveFileName = jar.archiveFileName - - relocate "org.java_websocket", "kr.syeyoung.org.java_websocket" - - dependencies { - include(dependency("org.java-websocket:Java-WebSocket:1.5.3")) - include(dependency("org.slf4j:slf4j-api:1.7.25")) - include(dependency("org.json:json:20220924")) - include(dependency("com.twelvemonkeys..*:.*")) - } -} - -tasks.named("remapJar") { - archiveClassifier = "all" - from(tasks.shadowJar) - input = tasks.shadowJar.archiveFile -} - - -tasks.assemble.dependsOn tasks.remapJar - -processResources { - inputs.property 'version', project.version - - // replace stuff in mcmod.info, nothing else - from(sourceSets.main.resources.srcDirs) { - duplicatesStrategy = 'include' - include 'mcmod.info' - - // replace version and mcversion - expand 'version': project.version - } -}
\ No newline at end of file diff --git a/loader/build.gradle b/loader/build.gradle index 14bd8e7b..921d9d41 100644 --- a/loader/build.gradle +++ b/loader/build.gradle @@ -21,7 +21,7 @@ loom { // probably will have to my own mixin tweaker, due to dungeonsguide's weird dynamic loading stuff // property("mixin.debug", "true") // property("asmhelper.verbose", "true") -// arg("--tweakClass", "org.spongepowered.asm.launch.MixinTweaker") + arg("--tweakClass", "kr.syeyoung.dungeonsguide.launcher.coremod.DGTweaker") // arg("--mixin", "mixins.examplemod.json") } @@ -87,6 +87,7 @@ tasks.withType(Jar) { manifest { attributes["FMLCorePluginContainsFMLMod"] = "true" attributes["ForceLoadAsMod"] = "true" + attributes["TweakClass"] = "kr.syeyoung.dugneonsguide.launcher.coremod.DGTweaker" // If you don't want mixins, remove these lines // this["TweakClass"] = "org.spongepowered.asm.launch.MixinTweaker" 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 782c3648..1678c58f 100755 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/Main.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/Main.java @@ -24,17 +24,16 @@ import kr.syeyoung.dungeonsguide.launcher.exceptions.DungeonsGuideLoadingExcepti import kr.syeyoung.dungeonsguide.launcher.exceptions.NoSuitableLoaderFoundException; import kr.syeyoung.dungeonsguide.launcher.exceptions.NoVersionFoundException; import kr.syeyoung.dungeonsguide.launcher.exceptions.ReferenceLeakedException; -import kr.syeyoung.dungeonsguide.launcher.exceptions.auth.PrivacyPolicyRequiredException; import kr.syeyoung.dungeonsguide.launcher.gui.screen.GuiDisplayer; import kr.syeyoung.dungeonsguide.launcher.gui.screen.GuiLoadingError; -import kr.syeyoung.dungeonsguide.launcher.gui.screen.GuiPrivacyPolicy; -import kr.syeyoung.dungeonsguide.launcher.gui.screen.GuiReferenceLeak; +import kr.syeyoung.dungeonsguide.launcher.gui.screen.GuiUnloadingError; import kr.syeyoung.dungeonsguide.launcher.gui.tooltip.Notification; import kr.syeyoung.dungeonsguide.launcher.gui.tooltip.NotificationManager; import kr.syeyoung.dungeonsguide.launcher.loader.IDGLoader; import kr.syeyoung.dungeonsguide.launcher.loader.JarLoader; import kr.syeyoung.dungeonsguide.launcher.loader.LocalLoader; import kr.syeyoung.dungeonsguide.launcher.loader.RemoteLoader; +import lombok.Getter; import net.minecraft.client.Minecraft; import net.minecraft.client.resources.IReloadableResourceManager; import net.minecraftforge.common.MinecraftForge; @@ -44,8 +43,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.SubscribeEvent; +import net.minecraftforge.fml.common.gameevent.TickEvent; -import javax.swing.*; import java.io.*; import java.util.*; @@ -75,9 +75,11 @@ public class Main listeners.remove(dungeonsGuideReloadListener); } + + @Getter private IDGLoader currentLoader; - private UUID dgUnloaded = UUID.randomUUID(); + private static final UUID dgUnloaded = UUID.randomUUID(); @EventHandler public void initEvent(FMLInitializationEvent initializationEvent) throws ClassNotFoundException, InstantiationException, IllegalAccessException { @@ -121,7 +123,14 @@ public class Main GuiDisplayer.INSTANCE.displayGui(new GuiLoadingError(e)); } catch (DungeonsGuideLoadingException e) { e.printStackTrace(); + + try { + unload(); + } catch (Exception e2) { + GuiDisplayer.INSTANCE.displayGui(new GuiUnloadingError(e2)); + } GuiDisplayer.INSTANCE.displayGui(new GuiLoadingError(e)); + } } @@ -147,7 +156,7 @@ public class Main File f = new File(configDir, "loader.cfg"); Configuration configuration = new Configuration(f); IDGLoader idgLoader = obtainLoader(configuration); - load(idgLoader); + reload(idgLoader); } catch (NoSuitableLoaderFoundException e) { e.printStackTrace(); GuiDisplayer.INSTANCE.displayGui(new GuiLoadingError(e)); @@ -156,7 +165,14 @@ public class Main GuiDisplayer.INSTANCE.displayGui(new GuiLoadingError(e)); } catch (DungeonsGuideLoadingException e) { e.printStackTrace(); + try { + unload(); + } catch (Exception e2) { + GuiDisplayer.INSTANCE.displayGui(new GuiUnloadingError(e2)); + } GuiDisplayer.INSTANCE.displayGui(new GuiLoadingError(e)); + } catch (ReferenceLeakedException e) { + GuiDisplayer.INSTANCE.displayGui(new GuiUnloadingError(e)); } }) .unremovable(true) @@ -166,9 +182,11 @@ public class Main if (dgInterface != null) throw new IllegalStateException("DG is loaded"); dgInterface = newLoader.loadDungeonsGuide(); currentLoader = newLoader; - - dgInterface.init(configDir); - + try { + dgInterface.init(configDir); + } catch (Exception e) { + throw new DungeonsGuideLoadingException("Exception occured while calling init", e); + } for (DungeonsGuideReloadListener listener : listeners) { listener.onLoad(dgInterface); } @@ -183,21 +201,42 @@ public class Main NotificationManager.INSTANCE.removeNotification(dgUnloaded); } - public void reload(IDGLoader newLoader) { + + private volatile IDGLoader reqLoader = null; + public void reloadWithoutStacktraceReference(IDGLoader newLoader) { + reqLoader = newLoader; + } + @SubscribeEvent + public void onTick(TickEvent.ClientTickEvent tickEvent) { + if (reqLoader != null) { + IDGLoader loader = reqLoader; + reqLoader = null; + + try { + reload(loader); + } catch (DungeonsGuideLoadingException e) { + try { + unload(); + } catch (Exception e2) { + GuiDisplayer.INSTANCE.displayGui(new GuiUnloadingError(e2)); + } + GuiDisplayer.INSTANCE.displayGui(new GuiLoadingError(e)); + } catch (ReferenceLeakedException e) { + GuiDisplayer.INSTANCE.displayGui(new GuiUnloadingError(e)); + } + } + } + + public void reload(IDGLoader newLoader) throws DungeonsGuideLoadingException, ReferenceLeakedException { try { unload(); load(newLoader); - } catch (DungeonsGuideLoadingException | ReferenceLeakedException e) { + } catch (DungeonsGuideLoadingException | ReferenceLeakedException | UnsupportedOperationException e) { dgInterface = null; currentLoader = null; e.printStackTrace(); - - if (e instanceof DungeonsGuideLoadingException) { - GuiDisplayer.INSTANCE.displayGui(new GuiLoadingError(e)); - } else { - GuiDisplayer.INSTANCE.displayGui(new GuiReferenceLeak(e)); - } + throw e; } } diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/coremod/DGTweaker.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/coremod/DGTweaker.java new file mode 100644 index 00000000..cd12e47c --- /dev/null +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/coremod/DGTweaker.java @@ -0,0 +1,29 @@ +package kr.syeyoung.dungeonsguide.launcher.coremod; + +import net.minecraft.launchwrapper.ITweaker; +import net.minecraft.launchwrapper.LaunchClassLoader; + +import java.io.File; +import java.util.List; + +public class DGTweaker implements ITweaker { + @Override + public void acceptOptions(List<String> args, File gameDir, File assetsDir, String profile) { + + } + + @Override + public void injectIntoClassLoader(LaunchClassLoader classLoader) { + classLoader.registerTransformer(EventBusTransformer.class.getName()); + } + + @Override + public String getLaunchTarget() { + return null; + } + + @Override + public String[] getLaunchArguments() { + return new String[0]; + } +} diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/coremod/EventBusTransformer.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/coremod/EventBusTransformer.java new file mode 100644 index 00000000..bcfa0cef --- /dev/null +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/coremod/EventBusTransformer.java @@ -0,0 +1,49 @@ +package kr.syeyoung.dungeonsguide.launcher.coremod; + +import net.minecraft.launchwrapper.IClassTransformer; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.tree.*; + +import java.util.Iterator; + +public class EventBusTransformer implements IClassTransformer { + + @Override + public byte[] transform(String name, String transformedName, byte[] basicClass) { + if (name.equals("net.minecraftforge.fml.common.eventhandler.EventBus")) { + + String targetMethodName = "register"; + + ClassNode classNode = new ClassNode(); + ClassReader classReader = new ClassReader(basicClass); + classReader.accept(classNode, 0); + + Iterator<MethodNode> methods = classNode.methods.iterator(); + while(methods.hasNext()) + { + MethodNode m = methods.next(); + if ((m.name.equals(targetMethodName) && m.desc.equals("(Ljava/lang/Class;Ljava/lang/Object;Ljava/lang/reflect/Method;Lnet/minecraftforge/fml/common/ModContainer;)V"))) + { + AbstractInsnNode curr = m.instructions.getFirst(); + while ((curr = curr.getNext()) != m.instructions.getLast()) { + if (curr instanceof TypeInsnNode && ((TypeInsnNode) curr).desc.equals("net/minecraftforge/fml/common/eventhandler/ASMEventHandler")) { + ((TypeInsnNode) curr).desc = "kr/syeyoung/dungeonsguide/launcher/events/OwnerAwareASMEventHandler"; + } + if (curr instanceof MethodInsnNode && ((MethodInsnNode) curr).owner.equals("net/minecraftforge/fml/common/eventhandler/ASMEventHandler")) { + ((MethodInsnNode) curr).owner = "kr/syeyoung/dungeonsguide/launcher/events/OwnerAwareASMEventHandler"; + } + } + + break; + } + } + + ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); + classNode.accept(writer); + return writer.toByteArray(); + } + + return basicClass; + } +} diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/events/DGAwareEventSubscriptionTransformer.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/events/DGAwareEventSubscriptionTransformer.java new file mode 100644 index 00000000..cbe83e9b --- /dev/null +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/events/DGAwareEventSubscriptionTransformer.java @@ -0,0 +1,198 @@ +package kr.syeyoung.dungeonsguide.launcher.events; + +import net.minecraft.launchwrapper.IClassTransformer; +import net.minecraftforge.fml.common.eventhandler.Event; +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.*; + +import java.util.List; + +import static org.objectweb.asm.ClassWriter.COMPUTE_FRAMES; +import static org.objectweb.asm.Opcodes.*; +import static org.objectweb.asm.Type.*; +import static org.objectweb.asm.Type.VOID_TYPE; + +public class DGAwareEventSubscriptionTransformer implements IClassTransformer +{ + private ClassLoader classLoader; + public DGAwareEventSubscriptionTransformer(ClassLoader classLoader) + { + this.classLoader = classLoader; + } + + @Override + public byte[] transform(String name, String transformedName, byte[] bytes) + { + if (bytes == null || name.equals("net.minecraftforge.fml.common.eventhandler.Event") || name.startsWith("net.minecraft.") || name.indexOf('.') == -1) + { + return bytes; + } + ClassReader cr = new ClassReader(bytes); + ClassNode classNode = new ClassNode(); + cr.accept(classNode, 0); + + try + { + if (buildEvents(classNode)) + { + ClassWriter cw = new ClassWriter(COMPUTE_FRAMES); + classNode.accept(cw); + return cw.toByteArray(); + } + return bytes; + } + catch (ClassNotFoundException ex) + { + // Discard silently- it's just noise + } + catch (Exception e) + { + e.printStackTrace(); + } + + return bytes; + } + + private boolean buildEvents(ClassNode classNode) throws Exception + { + // Yes, this recursively loads classes until we get this base class. THIS IS NOT A ISSUE. Coremods should handle re-entry just fine. + // If they do not this a COREMOD issue NOT a Forge/LaunchWrapper issue. + Class<?> parent = classLoader.loadClass(classNode.superName.replace('/', '.')); + if (!Event.class.isAssignableFrom(parent)) + { + return false; + } + + //Class<?> listenerListClazz = Class.forName("net.minecraftforge.fml.common.eventhandler.ListenerList", false, getClass().getClassLoader()); + Type tList = Type.getType("Lnet/minecraftforge/fml/common/eventhandler/ListenerList;"); + + boolean edited = false; + boolean hasSetup = false; + boolean hasGetListenerList = false; + boolean hasDefaultCtr = false; + boolean hasCancelable = false; + boolean hasResult = false; + String voidDesc = Type.getMethodDescriptor(VOID_TYPE); + String boolDesc = Type.getMethodDescriptor(BOOLEAN_TYPE); + String listDesc = tList.getDescriptor(); + String listDescM = Type.getMethodDescriptor(tList); + + for (MethodNode method : (List<MethodNode>)classNode.methods) + { + if (method.name.equals("setup") && method.desc.equals(voidDesc) && (method.access & ACC_PROTECTED) == ACC_PROTECTED) hasSetup = true; + if ((method.access & ACC_PUBLIC) == ACC_PUBLIC) + { + if (method.name.equals("getListenerList") && method.desc.equals(listDescM)) hasGetListenerList = true; + if (method.name.equals("isCancelable") && method.desc.equals(boolDesc)) hasCancelable = true; + if (method.name.equals("hasResult") && method.desc.equals(boolDesc)) hasResult = true; + } + if (method.name.equals("<init>") && method.desc.equals(voidDesc)) hasDefaultCtr = true; + } + + if (classNode.visibleAnnotations != null) + { + for (AnnotationNode node : classNode.visibleAnnotations) + { + if (!hasResult && node.desc.equals("Lnet/minecraftforge/fml/common/eventhandler/Event$HasResult;")) + { + /* Add: + * public boolean hasResult() + * { + * return true; + * } + */ + MethodNode method = new MethodNode(ACC_PUBLIC, "hasResult", boolDesc, null, null); + method.instructions.add(new InsnNode(ICONST_1)); + method.instructions.add(new InsnNode(IRETURN)); + classNode.methods.add(method); + edited = true; + } + else if (!hasCancelable && node.desc.equals("Lnet/minecraftforge/fml/common/eventhandler/Cancelable;")) + { + /* Add: + * public boolean isCancelable() + * { + * return true; + * } + */ + MethodNode method = new MethodNode(ACC_PUBLIC, "isCancelable", boolDesc, null, null); + method.instructions.add(new InsnNode(ICONST_1)); + method.instructions.add(new InsnNode(IRETURN)); + classNode.methods.add(method); + edited = true; + } + } + } + + if (hasSetup) + { + if (!hasGetListenerList) + throw new RuntimeException("Event class defines setup() but does not define getListenerList! " + classNode.name); + else + return edited; + } + + Type tSuper = Type.getType(classNode.superName); + + //Add private static ListenerList LISTENER_LIST + classNode.fields.add(new FieldNode(ACC_PRIVATE | ACC_STATIC, "LISTENER_LIST", listDesc, null, null)); + + /*Add: + * public <init>() + * { + * super(); + * } + */ + if (!hasDefaultCtr) + { + MethodNode method = new MethodNode(ACC_PUBLIC, "<init>", voidDesc, null, null); + method.instructions.add(new VarInsnNode(ALOAD, 0)); + method.instructions.add(new MethodInsnNode(INVOKESPECIAL, tSuper.getInternalName(), "<init>", voidDesc, false)); + method.instructions.add(new InsnNode(RETURN)); + classNode.methods.add(method); + } + + /*Add: + * protected void setup() + * { + * super.setup(); + * if (LISTENER_LIST != NULL) + * { + * return; + * } + * LISTENER_LIST = new ListenerList(super.getListenerList()); + * } + */ + MethodNode method = new MethodNode(ACC_PROTECTED, "setup", voidDesc, null, null); + method.instructions.add(new VarInsnNode(ALOAD, 0)); + method.instructions.add(new MethodInsnNode(INVOKESPECIAL, tSuper.getInternalName(), "setup", voidDesc, false)); + method.instructions.add(new FieldInsnNode(GETSTATIC, classNode.name, "LISTENER_LIST", listDesc)); + LabelNode initLisitener = new LabelNode(); + method.instructions.add(new JumpInsnNode(IFNULL, initLisitener)); + method.instructions.add(new InsnNode(RETURN)); + method.instructions.add(initLisitener); + method.instructions.add(new FrameNode(F_SAME, 0, null, 0, null)); + method.instructions.add(new TypeInsnNode(NEW, tList.getInternalName())); + method.instructions.add(new InsnNode(DUP)); + method.instructions.add(new VarInsnNode(ALOAD, 0)); + method.instructions.add(new MethodInsnNode(INVOKESPECIAL, tSuper.getInternalName(), "getListenerList", listDescM, false)); + method.instructions.add(new MethodInsnNode(INVOKESPECIAL, tList.getInternalName(), "<init>", getMethodDescriptor(VOID_TYPE, tList), false)); + method.instructions.add(new FieldInsnNode(PUTSTATIC, classNode.name, "LISTENER_LIST", listDesc)); + method.instructions.add(new InsnNode(RETURN)); + classNode.methods.add(method); + + /*Add: + * public ListenerList getListenerList() + * { + * return this.LISTENER_LIST; + * } + */ + method = new MethodNode(ACC_PUBLIC, "getListenerList", listDescM, null, null); + method.instructions.add(new FieldInsnNode(GETSTATIC, classNode.name, "LISTENER_LIST", listDesc)); + method.instructions.add(new InsnNode(ARETURN)); + classNode.methods.add(method); + return true; + } +} diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/events/OwnerAwareASMEventHandler.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/events/OwnerAwareASMEventHandler.java new file mode 100644 index 00000000..3475e672 --- /dev/null +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/events/OwnerAwareASMEventHandler.java @@ -0,0 +1,149 @@ +package kr.syeyoung.dungeonsguide.launcher.events; + +import static org.objectweb.asm.Opcodes.*; + +import java.lang.reflect.Method; +import java.util.HashMap; + +import net.minecraftforge.fml.common.ModContainer; + +import net.minecraftforge.fml.common.eventhandler.Event; +import net.minecraftforge.fml.common.eventhandler.EventPriority; +import net.minecraftforge.fml.common.eventhandler.IEventListener; +import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; +import org.apache.logging.log4j.ThreadContext; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Type; + +import com.google.common.collect.Maps; + + +public class OwnerAwareASMEventHandler implements IEventListener +{ + private static int IDs = 0; + private static final String HANDLER_DESC = Type.getInternalName(IEventListener.class); + private static final String HANDLER_FUNC_DESC = Type.getMethodDescriptor(IEventListener.class.getDeclaredMethods()[0]); + private static final HashMap<Method, Class<?>> cache = Maps.newHashMap(); + private static final boolean GETCONTEXT = Boolean.parseBoolean(System.getProperty("fml.LogContext", "false")); + + private final IEventListener handler; + private final SubscribeEvent subInfo; + private ModContainer owner; + private String readable; + + public OwnerAwareASMEventHandler(Object target, Method method, ModContainer owner) throws Exception + { + this.owner = owner; + handler = (IEventListener)createWrapper(method).getConstructor(Object.class).newInstance(target); + subInfo = method.getAnnotation(SubscribeEvent.class); + readable = "ASM: " + target + " " + method.getName() + Type.getMethodDescriptor(method); + } + + @Override + public void invoke(Event event) + { + if (GETCONTEXT) + ThreadContext.put("mod", owner == null ? "" : owner.getName()); + if (handler != null) + { + if (!event.isCancelable() || !event.isCanceled() || subInfo.receiveCanceled()) + { + handler.invoke(event); + } + } + if (GETCONTEXT) + ThreadContext.remove("mod"); + } + + public EventPriority getPriority() + { + return subInfo.priority(); + } + + public Class<?> createWrapper(Method callback) + { + if (cache.containsKey(callback)) + { + return cache.get(callback); + } + + ClassWriter cw = new ClassWriter(0); + MethodVisitor mv; + + String name = getUniqueName(callback); + String desc = name.replace('.', '/'); + String instType = Type.getInternalName(callback.getDeclaringClass()); + String eventType = Type.getInternalName(callback.getParameterTypes()[0]); + + /* + System.out.println("Name: " + name); + System.out.println("Desc: " + desc); + System.out.println("InstType: " + instType); + System.out.println("Callback: " + callback.getName() + Type.getMethodDescriptor(callback)); + System.out.println("Event: " + eventType); + */ + + cw.visit(V1_6, ACC_PUBLIC | ACC_SUPER, desc, null, "java/lang/Object", new String[]{ HANDLER_DESC }); + + cw.visitSource(".dynamic", null); + { + cw.visitField(ACC_PUBLIC, "instance", "Ljava/lang/Object;", null, null).visitEnd(); + } + { + mv = cw.visitMethod(ACC_PUBLIC, "<init>", "(Ljava/lang/Object;)V", null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitMethodInsn(INVOKESPECIAL, "java/lang/Object", "<init>", "()V", false); + mv.visitVarInsn(ALOAD, 0); + mv.visitVarInsn(ALOAD, 1); + mv.visitFieldInsn(PUTFIELD, desc, "instance", "Ljava/lang/Object;"); + mv.visitInsn(RETURN); + mv.visitMaxs(2, 2); + mv.visitEnd(); + } + { + mv = cw.visitMethod(ACC_PUBLIC, "invoke", HANDLER_FUNC_DESC, null, null); + mv.visitCode(); + mv.visitVarInsn(ALOAD, 0); + mv.visitFieldInsn(GETFIELD, desc, "instance", "Ljava/lang/Object;"); + mv.visitTypeInsn(CHECKCAST, instType); + mv.visitVarInsn(ALOAD, 1); + mv.visitTypeInsn(CHECKCAST, eventType); + mv.visitMethodInsn(INVOKEVIRTUAL, instType, callback.getName(), Type.getMethodDescriptor(callback), false); + mv.visitInsn(RETURN); + mv.visitMaxs(2, 2); + mv.visitEnd(); + } + cw.visitEnd(); + Class<?> ret = new ASMClassLoader(callback.getDeclaringClass().getClassLoader()).define(name, cw.toByteArray()); + cache.put(callback, ret); + return ret; + } + + private String getUniqueName(Method callback) + { + return String.format("%s_%d_%s_%s_%s", getClass().getName(), IDs++, + callback.getDeclaringClass().getSimpleName(), + callback.getName(), + callback.getParameterTypes()[0].getSimpleName()); + } + + private static class ASMClassLoader extends ClassLoader + { + private ASMClassLoader(ClassLoader classLoader) + { + super(classLoader); + } + + public Class<?> define(String name, byte[] data) + { + return defineClass(name, data, 0, data.length); + } + } + + public String toString() + { + return readable; + } +} 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/GuiUnloadingError.java index 9c0a5980..dd05dec4 100644 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/gui/screen/GuiReferenceLeak.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/gui/screen/GuiUnloadingError.java @@ -30,9 +30,9 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.PrintStream; -public class GuiReferenceLeak extends SpecialGuiScreen { +public class GuiUnloadingError extends SpecialGuiScreen { private final String stacktrace; - public GuiReferenceLeak(Throwable cause) { + public GuiUnloadingError(Throwable cause) { ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream(); PrintStream printStream = new PrintStream(byteArrayOutputStream); diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/gui/tooltip/NotificationManager.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/gui/tooltip/NotificationManager.java index f3146e7f..661ad93c 100644 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/gui/tooltip/NotificationManager.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/gui/tooltip/NotificationManager.java @@ -6,6 +6,7 @@ import net.minecraft.client.gui.Gui; import net.minecraft.client.gui.ScaledResolution; import net.minecraft.client.renderer.GlStateManager; import net.minecraftforge.client.event.GuiScreenEvent; +import net.minecraftforge.client.event.RenderGameOverlayEvent; import net.minecraftforge.fml.common.eventhandler.SubscribeEvent; import org.lwjgl.input.Mouse; @@ -28,6 +29,64 @@ public class NotificationManager { tooltipList.remove(uid); } + + @SubscribeEvent + public void onRender(RenderGameOverlayEvent.Post postRender) { + ScaledResolution sr = new ScaledResolution(Minecraft.getMinecraft()); + FontRenderer fr = Minecraft.getMinecraft().fontRendererObj; + int widthX = fr.getStringWidth("X"); + + GlStateManager.pushMatrix(); + GlStateManager.translate(sr.getScaledWidth() - 5, sr.getScaledHeight() -5, 0); + + int currY = sr.getScaledHeight() - 5; + + for (Notification tooltip : tooltipList.values()) { + int width, height; + String[] description = tooltip.getDescription().split("\n"); + width = + Math.max( + fr.getStringWidth(tooltip.getTitle()), + Arrays.stream(description).map(fr::getStringWidth).max(Integer::compareTo).orElse(300) + ) + 10; + height = description.length * fr.FONT_HEIGHT + 15 + fr.FONT_HEIGHT; + + GlStateManager.translate(0, -height, 0); + currY -= height; + + GlStateManager.pushMatrix(); + GlStateManager.translate(-width, 0, 0); + Gui.drawRect(0, 0,width,height, 0xFF23272a); + Gui.drawRect(1, 1, width-1, height-1, 0XFF2c2f33); + + if (!tooltip.isUnremovable()) { + fr.drawString("X", width - widthX - 2, 2, 0xFFFF0000); + } + + GlStateManager.translate(5,5,0); + fr.drawString(tooltip.getTitle(), 0,0, tooltip.getTitleColor()); + GlStateManager.translate(0, fr.FONT_HEIGHT + 5, 0); + int y = 0; + for (String line : description) { + fr.drawString(line, 0, y, 0xFFAAAAAA); + y += fr.FONT_HEIGHT; + } + GlStateManager.popMatrix(); + + tooltip.setBoundRect(new Rectangle( + sr.getScaledWidth() - width - 5, + currY, + width, + height + )); + + currY -= 5; + GlStateManager.translate(0, -5, 0); + } + + GlStateManager.popMatrix(); + + } @SubscribeEvent public void onGuiPostRender(GuiScreenEvent.DrawScreenEvent.Post rendered) { ScaledResolution sr = new ScaledResolution(Minecraft.getMinecraft()); diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/DGClassLoader.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/DGClassLoader.java index 1fbc39b0..a2f1a784 100644 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/DGClassLoader.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/DGClassLoader.java @@ -1,12 +1,14 @@ package kr.syeyoung.dungeonsguide.launcher.loader; -import sun.misc.Resource; +import kr.syeyoung.dungeonsguide.launcher.events.DGAwareEventSubscriptionTransformer; import java.io.IOException; import java.net.MalformedURLException; import java.net.URL; public abstract class DGClassLoader extends ClassLoader implements ByteStreamURLHandler.InputStreamGenerator{ + + DGAwareEventSubscriptionTransformer eventSubscriptionTransformer = new DGAwareEventSubscriptionTransformer(this); public DGClassLoader(ClassLoader parent) { super(parent); } @@ -53,6 +55,7 @@ public abstract class DGClassLoader extends ClassLoader implements ByteStreamURL throw new ClassNotFoundException(name, e); } if (res != null) { + res = eventSubscriptionTransformer.transform(name, name, res); return defineClass(name, res, 0, res.length); } else { throw new ClassNotFoundException(name); diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/JarLoader.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/JarLoader.java index dbb86dee..39fcbf58 100644 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/JarLoader.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/JarLoader.java @@ -66,7 +66,7 @@ public class JarLoader implements IDGLoader { @Override public InputStream convert(String name) { // / separated if (this.loadedResources.containsKey(name.substring(1))) - return new ByteArrayInputStream(this.loadedResources.get(name.substring(1))); + return new ByteArrayInputStream(this.loadedResources.get(name)); return null; } } diff --git a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/LocalLoader.java b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/LocalLoader.java index a47b2aaf..ec3e59fb 100644 --- a/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/LocalLoader.java +++ b/loader/src/main/java/kr/syeyoung/dungeonsguide/launcher/loader/LocalLoader.java @@ -23,6 +23,7 @@ import kr.syeyoung.dungeonsguide.launcher.exceptions.DungeonsGuideLoadingExcepti import kr.syeyoung.dungeonsguide.launcher.exceptions.ReferenceLeakedException; import org.apache.commons.io.IOUtils; +import java.io.BufferedInputStream; import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; @@ -47,14 +48,16 @@ public class LocalLoader implements IDGLoader { } @Override public byte[] getClassBytes(String name) throws IOException { // . separated. - InputStream in = convert("/"+name.replace(".", "/")+".class"); + if (name.startsWith("kr.syeyoung.dungeonsguide.launcher")) return null; + InputStream in = convert(name.replace(".", "/")+".class"); + if (!(in instanceof BufferedInputStream)) return null; if (in == null) return null; return IOUtils.toByteArray(in); } @Override public InputStream convert(String name) { // / separated - return LocalLoader.class.getResourceAsStream(name); + return LocalLoader.class.getResourceAsStream("/"+name); } } 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 446958a0..ceafb6f7 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 @@ -73,7 +73,7 @@ public class RemoteLoader implements IDGLoader { @Override public InputStream convert(String name) { // / separated if (this.loadedResources.containsKey(name.substring(1))) - return new ByteArrayInputStream(this.loadedResources.get(name.substring(1))); + return new ByteArrayInputStream(this.loadedResources.get(name)); return null; } } diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/DungeonsGuide.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/DungeonsGuide.java index 912e3ebc..52515a38 100755 --- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/DungeonsGuide.java +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/DungeonsGuide.java @@ -30,6 +30,7 @@ import kr.syeyoung.dungeonsguide.mod.config.Config; import kr.syeyoung.dungeonsguide.mod.cosmetics.CosmeticsManager; import kr.syeyoung.dungeonsguide.mod.discord.rpc.RichPresenceManager; import kr.syeyoung.dungeonsguide.mod.dungeon.DungeonFacade; +import kr.syeyoung.dungeonsguide.mod.events.listener.DungeonListener; import kr.syeyoung.dungeonsguide.mod.events.listener.FeatureListener; import kr.syeyoung.dungeonsguide.mod.events.listener.PacketListener; import kr.syeyoung.dungeonsguide.mod.features.FeatureRegistry; @@ -58,6 +59,7 @@ import org.apache.logging.log4j.Logger; import java.io.File; import java.io.IOException; +import java.util.ArrayList; import java.util.List; import java.util.Set; @@ -91,9 +93,17 @@ public class DungeonsGuide implements DGInterface { CommandReparty commandReparty; + private List<Object> registeredListeners = new ArrayList<>(); + public void registerEventsForge(Object object) { + registeredListeners.add(object); + MinecraftForge.EVENT_BUS.register(object); + } public void init(File f) { + ClassLoader orignalLoader = Thread.currentThread().getContextClassLoader(); + + Thread.currentThread().setContextClassLoader(getClass().getClassLoader()); ProgressManager.ProgressBar progressbar = ProgressManager.push("DungeonsGuide", 4); progressbar.step("Creating Configuration"); @@ -115,18 +125,19 @@ public class DungeonsGuide implements DGInterface { e.printStackTrace(); } - MinecraftForge.EVENT_BUS.register(this); + registerEventsForge(this); progressbar.step("Registering Events & Commands"); skyblockStatus = new SkyblockStatus(); - MinecraftForge.EVENT_BUS.register(skyblockStatus); - + registerEventsForge(skyblockStatus); + registerEventsForge(ChatTransmitter.INSTANCE); + registerEventsForge(new BlockCache()); + registerEventsForge(TitleRender.getInstance()); (new FeatureRegistry()).init(); - new ChatTransmitter(); try { Set<String> invalid = ReflectionHelper.getPrivateValue(LaunchClassLoader.class, (LaunchClassLoader) Main.class.getClassLoader(), "invalidClasses"); @@ -139,7 +150,9 @@ public class DungeonsGuide implements DGInterface { this.blockCache = new BlockCache(); + registerEventsForge(new DungeonListener()); this.dungeonFacade = new DungeonFacade(); + dungeonFacade.init(); @@ -152,24 +165,24 @@ public class DungeonsGuide implements DGInterface { ClientCommandHandler.instance.registerCommand(commandDungeonsGuide); ClientCommandHandler.instance.registerCommand(command); - MinecraftForge.EVENT_BUS.register(command); - MinecraftForge.EVENT_BUS.register(commandDungeonsGuide); + registerEventsForge(command); + registerEventsForge(commandDungeonsGuide); - MinecraftForge.EVENT_BUS.register(commandReparty = new CommandReparty()); + registerEventsForge(commandReparty = new CommandReparty()); - MinecraftForge.EVENT_BUS.register(new FeatureListener()); - MinecraftForge.EVENT_BUS.register(new PacketListener()); - MinecraftForge.EVENT_BUS.register(new Keybinds()); + registerEventsForge(new FeatureListener()); + registerEventsForge(new PacketListener()); + registerEventsForge(new Keybinds()); - MinecraftForge.EVENT_BUS.register(PartyManager.INSTANCE); - MinecraftForge.EVENT_BUS.register(ChatProcessor.INSTANCE); - MinecraftForge.EVENT_BUS.register(StaticResourceCache.INSTANCE); + registerEventsForge(PartyManager.INSTANCE); + registerEventsForge(ChatProcessor.INSTANCE); + registerEventsForge(StaticResourceCache.INSTANCE); - MinecraftForge.EVENT_BUS.register(new AhUtils()); + registerEventsForge(new AhUtils()); progressbar.step("Opening connection"); - MinecraftForge.EVENT_BUS.register(cosmeticsManager = new CosmeticsManager()); + registerEventsForge(cosmeticsManager = new CosmeticsManager()); progressbar.step("Loading Config"); @@ -187,20 +200,20 @@ public class DungeonsGuide implements DGInterface { System.setProperty("dg.safe", "true"); } - MinecraftForge.EVENT_BUS.register(RichPresenceManager.INSTANCE); + registerEventsForge(RichPresenceManager.INSTANCE); TimeScoreUtil.init(); ProgressManager.pop(progressbar); + Thread.currentThread().setContextClassLoader(orignalLoader); } @Override public void unload() { // have FUN! - -// bar.step("Instantiating..."); -// partialLoad(obtainLoader(configuration)); - throw new UnsupportedOperationException("Who the heck registered events in features?? This will stay unsupported for now"); + for (Object registeredListener : registeredListeners) { + MinecraftForge.EVENT_BUS.unregister(registeredListener); + } } @Override diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/chat/ChatTransmitter.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/chat/ChatTransmitter.java index bfdbd5db..8a50211d 100644 --- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/chat/ChatTransmitter.java +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/chat/ChatTransmitter.java @@ -17,9 +17,8 @@ public class ChatTransmitter { public static final String PREFIX = "§eDungeons Guide §7:: "; public static String prefix = "§eDungeons Guide §7:: "; - public ChatTransmitter() { - MinecraftForge.EVENT_BUS.register(this); - } + + public static ChatTransmitter INSTANCE = new ChatTransmitter(); static Queue<ChatComponentText> receiveQueue = new ConcurrentLinkedQueue<>(); diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/commands/CommandDungeonsGuide.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/commands/CommandDungeonsGuide.java index 9b9811cd..5c65424e 100644 --- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/commands/CommandDungeonsGuide.java +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/commands/CommandDungeonsGuide.java @@ -18,6 +18,7 @@ package kr.syeyoung.dungeonsguide.mod.commands; +import kr.syeyoung.dungeonsguide.launcher.Main; import kr.syeyoung.dungeonsguide.mod.DungeonsGuide; import kr.syeyoung.dungeonsguide.mod.chat.ChatTransmitter; import kr.syeyoung.dungeonsguide.mod.config.guiconfig.GuiConfigV2; @@ -139,17 +140,20 @@ public class CommandDungeonsGuide extends CommandBase { sender.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §c" + args[1] + " is not valid number.")); } } + } else if (args[0].equals("reload")) { + Main.getMain().reloadWithoutStacktraceReference(Main.getMain().getCurrentLoader()); } else { - sender.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §e/dg §7-§fOpens configuration gui")); - sender.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §e/dg gui §7-§fOpens configuration gui")); - sender.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §e/dg help §7-§fShows command help")); - sender.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §e/dg reloadah §7-§f Reloads price data from server.")); - sender.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §e/dg reparty §7-§f Reparty.")); - sender.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §e/dg asktojoin or /dg atj §7-§f Toggle ask to join §cRequires Discord Rich Presence enabled. (/dg -> Advanced)")); - sender.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §e/dg partymax [number] or /dg pm [number] §7-§f Sets partymax §7(maximum amount people in party, for discord rpc)")); - sender.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §e/dg pv [ign] §7-§f Profile Viewer")); - sender.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §e/dg pvall §7-§f Profile Viewer For all people on party")); - sender.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §e/dg purge §7-§f Purge api cache.")); + sender.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §e/dg §7-§fOpens configuration gui")); + sender.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §e/dg gui §7-§fOpens configuration gui")); + sender.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §e/dg help §7-§fShows command help")); + sender.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §e/dg reloadah §7-§f Reloads price data from server.")); + sender.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §e/dg reparty §7-§f Reparty.")); + sender.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §e/dg asktojoin or /dg atj §7-§f Toggle ask to join §cRequires Discord Rich Presence enabled. (/dg -> Advanced)")); + sender.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §e/dg partymax [number] or /dg pm [number] §7-§f Sets partymax §7(maximum amount people in party, for discord rpc)")); + sender.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §e/dg pv [ign] §7-§f Profile Viewer")); + sender.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §e/dg pvall §7-§f Profile Viewer For all people on party")); + sender.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §e/dg purge §7-§f Purge api cache.")); + sender.addChatMessage(new ChatComponentText("§eDungeons Guide §7:: §e/dg reload §7-§f Reload Current Version of Dungeons Guide. Auto update versions will not be updated.")); } } diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/DungeonFacade.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/DungeonFacade.java index 434d3998..76fc482e 100644 --- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/DungeonFacade.java +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/dungeon/DungeonFacade.java @@ -6,6 +6,7 @@ import kr.syeyoung.dungeonsguide.mod.events.listener.DungeonListener; import lombok.Getter; import lombok.Setter; import net.minecraftforge.common.MinecraftForge; +import org.apache.logging.log4j.ThreadContext; import javax.crypto.BadPaddingException; import javax.crypto.IllegalBlockSizeException; @@ -22,9 +23,6 @@ public class DungeonFacade { private DungeonContext context; public void init() { - DungeonListener dgEventListener = new DungeonListener(); - MinecraftForge.EVENT_BUS.register(dgEventListener); - try { DungeonRoomInfoRegistry.loadAll(Main.getConfigDir()); } catch (BadPaddingException | InvalidKeyException | NoSuchPaddingException | IllegalBlockSizeException | diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/advanced/FeatureTestPepole.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/advanced/FeatureTestPepole.java index cc2f911a..bd495225 100644 --- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/advanced/FeatureTestPepole.java +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/advanced/FeatureTestPepole.java @@ -56,7 +56,6 @@ public class FeatureTestPepole extends GuiFeature implements ChatListener, Dunge addParameter("scale", new FeatureParameter<>("scale", "Scale", "Scale", 2.0f, "float", nval -> this.scale = nval)); - MinecraftForge.EVENT_BUS.register(this); // (new Thread(() -> { // while (true){ diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/etc/FeatureEpicCountdown.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/etc/FeatureEpicCountdown.java index f88b2884..70af9397 100644 --- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/etc/FeatureEpicCountdown.java +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/features/impl/etc/FeatureEpicCountdown.java @@ -5,6 +5,7 @@ import kr.syeyoung.dungeonsguide.mod.chat.ChatProcessResult; import kr.syeyoung.dungeonsguide.mod.chat.ChatProcessor; import kr.syeyoung.dungeonsguide.mod.features.FeatureParameter; import kr.syeyoung.dungeonsguide.mod.features.SimpleFeature; +import kr.syeyoung.dungeonsguide.mod.features.listener.TickListener; import kr.syeyoung.dungeonsguide.mod.utils.ScoreBoardUtils; import kr.syeyoung.dungeonsguide.mod.utils.TextUtils; import kr.syeyoung.dungeonsguide.mod.utils.TitleRender; @@ -23,7 +24,7 @@ import static kr.syeyoung.dungeonsguide.mod.chat.ChatProcessResult.REMOVE_CHAT; /** * CREDITS FOR THE COUNTDOWN SOUNDTRACK: <a href="https://www.youtube.com/watch?v=acCqrA-JxAw">...</a> */ -public class FeatureEpicCountdown extends SimpleFeature { +public class FeatureEpicCountdown extends SimpleFeature implements TickListener { static volatile long updatedAt; static volatile int secondsLeft; @@ -40,7 +41,6 @@ public class FeatureEpicCountdown extends SimpleFeature { lastSec = GO_TEXT; ChatProcessor.INSTANCE.subscribe(FeatureEpicCountdown::processChat); - MinecraftForge.EVENT_BUS.register(this); } public static ChatProcessResult processChat(String txt, Map<String, Object> context) { @@ -87,8 +87,8 @@ public class FeatureEpicCountdown extends SimpleFeature { String lastSec; @SubscribeEvent - public void onTick(TickEvent.ClientTickEvent e){ - if(e.phase != TickEvent.Phase.START || !isEnabled() || !DungeonsGuide.getDungeonsGuide().getSkyblockStatus().isOnDungeon()) return; + public void onTick(){ + if(!isEnabled() || !DungeonsGuide.getDungeonsGuide().getSkyblockStatus().isOnDungeon()) return; ScoreBoardUtils.forEachLineClean(line -> { diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/stomp/StompClient.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/stomp/StompClient.java index 84705a1d..d23debc2 100644 --- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/stomp/StompClient.java +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/stomp/StompClient.java @@ -131,7 +131,7 @@ public class StompClient extends WebSocketClient { if (heartbeat != null) heartbeat.cancel(true); MinecraftForge.EVENT_BUS.post(new StompDiedEvent(code, reason, remote)); - + StompManager.getInstance().onStompDied(new StompDiedEvent(code, reason, remote)); } @Override diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/stomp/StompManager.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/stomp/StompManager.java index e7248484..d430e586 100644 --- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/stomp/StompManager.java +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/stomp/StompManager.java @@ -21,7 +21,6 @@ public class StompManager { public static StompManager getInstance() { if (instance == null) { instance = new StompManager(); - MinecraftForge.EVENT_BUS.register(instance); } return instance; } @@ -48,7 +47,6 @@ public class StompManager { ScheduledExecutorService ex = Executors.newSingleThreadScheduledExecutor(); - @SubscribeEvent public void onStompDied(StompDiedEvent event) { logger.info("Stomp Connection closed, trying to reconnect - {} - {}", event.reason, event.code); connectStomp(); diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/utils/BlockCache.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/utils/BlockCache.java index b8313778..366e09a0 100644 --- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/utils/BlockCache.java +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/utils/BlockCache.java @@ -15,9 +15,6 @@ import org.jetbrains.annotations.NotNull; import java.util.concurrent.TimeUnit; public class BlockCache { - public BlockCache() { - MinecraftForge.EVENT_BUS.register(this); - } @SuppressWarnings("UnstableApiUsage") private final LoadingCache<BlockPos, IBlockState> cache = CacheBuilder.newBuilder() diff --git a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/utils/TitleRender.java b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/utils/TitleRender.java index dfc0b0a1..3b8fe964 100644 --- a/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/utils/TitleRender.java +++ b/mod/src/main/java/kr/syeyoung/dungeonsguide/mod/utils/TitleRender.java @@ -27,7 +27,6 @@ public class TitleRender { } private TitleRender() { - MinecraftForge.EVENT_BUS.register(this); } protected static int titlesTimer; |