Incompatibility with OptiFine D6
makamys opened this issue ยท 4 comments
I'm not sure if there's any way to fix this from LWJGL3ify's side, but I figured it would be worth reporting.
OptiFine D6 obtains a ZipFile reference to its own jar file roughly like this:
URLClassLoader ucl = (URLClassLoader)OptiFineClassTransformer.class.getClassLoader();
URL[] urls = ucl.getURLs();
// ...
ZipFile self = new ZipFile(new File(urls[i]));
An exception happens on the first line since in new versions of Java, AppClassLoader
is no longer a subclass of URLClassLoader
.
[15:00:19] [main/INFO] [LaunchWrapper/]: Calling tweak class optifine.OptiFineForgeTweaker
[15:00:19] [main/INFO] [STDOUT/]: [optifine.OptiFineForgeTweaker:dbg:56]: OptiFineForgeTweaker: acceptOptions
[15:00:19] [main/INFO] [STDOUT/]: [optifine.OptiFineForgeTweaker:dbg:56]: OptiFineForgeTweaker: injectIntoClassLoader
[15:00:19] [main/INFO] [STDERR/]: [java.lang.Throwable$WrappedPrintStream:println:785]: java.lang.ClassCastException: class jdk.internal.loader.ClassLoaders$AppClassLoader cannot be cast to class java.net.URLClassLoader (jdk.internal.loader.ClassLoaders$AppClassLoader and java.net.URLClassLoader are in module java.base of loader 'bootstrap')
[15:00:19] [main/INFO] [STDERR/]: [java.lang.Throwable$WrappedPrintStream:println:785]: at optifine.OptiFineClassTransformer.<init>(OptiFineClassTransformer.java:40)
[15:00:19] [main/INFO] [STDERR/]: [java.lang.Throwable$WrappedPrintStream:println:785]: at java.base/jdk.internal.reflect.DirectConstructorHandleAccessor.newInstance(DirectConstructorHandleAccessor.java:67)
[15:00:19] [main/INFO] [STDERR/]: [java.lang.Throwable$WrappedPrintStream:println:785]: at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:500)
[15:00:19] [main/INFO] [STDERR/]: [java.lang.Throwable$WrappedPrintStream:println:785]: at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:484)
[15:00:19] [main/INFO] [STDERR/]: [java.lang.Throwable$WrappedPrintStream:println:785]: at net.minecraft.launchwrapper.LaunchClassLoader.registerTransformer(LaunchClassLoader.java:94)
[15:00:19] [main/INFO] [STDERR/]: [java.lang.Throwable$WrappedPrintStream:println:785]: at optifine.OptiFineForgeTweaker.injectIntoClassLoader(OptiFineForgeTweaker.java:38)
[15:00:19] [main/INFO] [STDERR/]: [java.lang.Throwable$WrappedPrintStream:println:785]: at net.minecraft.launchwrapper.Launch.launch(Launch.java:145)
[15:00:19] [main/INFO] [STDERR/]: [java.lang.Throwable$WrappedPrintStream:println:785]: at net.minecraft.launchwrapper.Launch.main(Launch.java:29)
[15:00:19] [main/INFO] [STDERR/]: [java.lang.Throwable$WrappedPrintStream:println:785]: at org.prismlauncher.launcher.impl.StandardLauncher.launch(StandardLauncher.java:88)
[15:00:19] [main/INFO] [STDERR/]: [java.lang.Throwable$WrappedPrintStream:println:785]: at org.prismlauncher.EntryPoint.listen(EntryPoint.java:126)
[15:00:19] [main/INFO] [STDERR/]: [java.lang.Throwable$WrappedPrintStream:println:785]: at org.prismlauncher.EntryPoint.main(EntryPoint.java:71)
[15:00:19] [main/INFO] [STDOUT/]: [optifine.OptiFineClassTransformer:dbg:266]: *** Can not find the OptiFine JAR in the classpath ***
[15:00:19] [main/INFO] [STDOUT/]: [optifine.OptiFineClassTransformer:dbg:266]: *** OptiFine will not be loaded! ***
OptiFine E7 doesn't have this problem, since it instead uses OptiFineClassTransformer.class.getProtectionDomain().getCodeSource().getLocation()
to get the URL. The reason D6 is relevant is because it has been found to give better performance than E7 in some cases.
With FastCraft 1.23 + OptiFine D6, disabling stbiTextureStiching
is required because the flashing issue happens otherwise. I'll make a PR that updates the auto-detection logic in a moment.
I have released a tiny mod that hacks Java 9 compat into OptiFine D6, so a workaround exists now.
https://github.com/makamys/OptiFine3ify
Ponderings on merging this into LWJGL3ify
This hack cannot be cleanly added to LWJGL3ify (at least the mod) since it requires precise ordering between coremod initialization events. Here are the events we're working with:
1a. OptiFine tweaker gets loaded -> optifine
gets added as a class loader exception
1b. Mixin tweaker gets loaded -> FML plugins of mixins run
2. OptiFine tweaker gets called -> OptiFineTransformer gets loaded
3. Mixin tweaker gets called -> PREINIT phase starts -> mixin config plugins run
The order between 1a and 1b is dependent on jar name, so it cannot be guaranteed. The order between 2 and 3 is decided by the TweakOrder
of the tweakers, which is -1000 in OptiFine's case, and always 0 in practice in the case of the MixinTweaker.
Transforming OptiFineClassTransformer
is difficult because its package gets added as a class loader exclusion during the construction of the OptiFine tweaker. If we wish to transform it using a class transformer, we must remove the exclusion between 1a and 2. OptiFine3ify can do this easily since it can choose whatever TweakOrder
it wants. But LWJGL3ify cannot, and as such has no way to guarantee whether its code runs before or after 1a.
There does exist an order-agnostic solution: if we're before 1a, replace LaunchClassLoader#classLoaderExceptions
with a proxy object that refuses to add optifine
to the underlying set. But I assume that's too hacky for the project's standards.