fabric-loader
fabric-loader copied to clipboard
AppletLoader should not assume that all "applets" are true Applets
This is something that most people will not notice, but in the case of old versions such as rd-132211
, the Applet is not a "true applet," but instead a Runnable
like so.
public class MinecraftApplet implements Runnable {...}
AppletLoader assumes that the object that is passed in is an Applet and will fail because of invalid cast. Such as the error below:
[19:53:26] [main/INFO] (Fabric|Loader) [FabricLoader] Loading 4 mods: minecraft@132211, java@15, [email protected], [email protected]
[19:53:26] [main/INFO] (mixin) SpongePowered MIXIN Subsystem Version=0.8.2 Source=file:/C:/Users/Zer0/.gradle/caches/modules-2/files-2.1/net.fabricmc/sponge-mixin/0.8.2+build.24/e5a741445d0f425bf3cce946c6cf8c7fb8376b2/sponge-mixin-0.8.2+build.24.jar Service=Knot/Fabric Env=CLIENT
[19:53:26] [main/INFO] (Fabric|MixinBootstrap) Loaded Fabric development mappings for mixin remapper!
Hello Fabric world!
Exception in thread "main" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
at net.fabricmc.loader.game.MinecraftGameProvider.launch(MinecraftGameProvider.java:228)
at net.fabricmc.loader.launch.knot.Knot.init(Knot.java:139)
at net.fabricmc.loader.launch.knot.KnotClient.main(KnotClient.java:27)
at net.fabricmc.devlaunchinjector.Main.main(Main.java:86)
Caused by: java.lang.reflect.InvocationTargetException
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:64)
at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.base/java.lang.reflect.Method.invoke(Method.java:564)
at net.fabricmc.loader.game.MinecraftGameProvider.launch(MinecraftGameProvider.java:226)
... 3 more
Caused by: java.lang.ClassCastException: class com.mojang.minecraft.MinecraftApplet cannot be cast to class java.applet.Applet (com.mojang.minecraft.MinecraftApplet is in unnamed module of loader net.fabricmc.loader.launch.knot.KnotClassLoader @46cdf8bd; java.applet.Applet is in module java.desktop of loader 'bootstrap')
at net.fabricmc.loader.entrypoint.applet.AppletLauncher.<init>(AppletLauncher.java:64)
at net.fabricmc.loader.entrypoint.applet.AppletFrame.launch(AppletFrame.java:91)
at net.fabricmc.loader.entrypoint.applet.AppletMain.main(AppletMain.java:37)
... 8 more
The lucky part about this is that the onInitialize
method has a chance to call the Applet as a Runnable like so:
// This is a workaround to let loader load the class.
try {
MinecraftApplet clazz = (MinecraftApplet) FabricLauncherBase.getLauncher().getTargetClassLoader().loadClass(EntrypointTransformer.appletMainClass).getDeclaredConstructor().newInstance();
clazz.run();
} catch (InstantiationException | IllegalAccessException | InvocationTargetException | NoSuchMethodException | ClassNotFoundException e) {
e.printStackTrace();
}
Honestly, should not assume that it's a "true applet" or have a fallback to a generic Runnable runner.
The problem with the lucky part above is that the "Applet"
is called again after each closing and requires external intervention to stop the program. And it's hacky, so I don't like it.