KotlinForForge icon indicating copy to clipboard operation
KotlinForForge copied to clipboard

Unable to use other Kotlin libraries with KFF on Forge/NeoForge

Open Erdragh opened this issue 1 year ago • 33 comments

I'm writing a Minecraft mod / Discord bot combo: https://github.com/Erdragh/AstralBot It uses JDA to communicate with Discord. JDA has a dependency on okhttp3 which over multiple corners has a dependency on the kotlin stdlib. I'm excluding the org.jetbrains.kotlin dependency from JDA.

I'm using Kotlin for the Mod itself and the build scripts. The Fabric server starts fine, the Forge server doesn't.

To reproduce:

  • Clone repo mentioned above
  • Start the Forge server with the env variable DISCORD_TOKEN set to any value, just so it's defined.

The relevant exception is the following: https://gist.github.com/Erdragh/c84543358f069f43e16e90fb55665324

I'm not sure whether this is an Architectury or a KFF issue, I've already made a support post on the Architectury Discord with no result.

What I find weird is that kotlin.reflect is apparently loading fine judging from the stack trace, but kotlin/Unit just can't be found.

Erdragh avatar Nov 28 '23 11:11 Erdragh

Here are the dependencies for forge using Architectury's forgeRuntimeLibrary: https://gist.github.com/Erdragh/55200d17dda4511c092727654016b549

Erdragh avatar Nov 28 '23 11:11 Erdragh

Possibly related: Something about dependency changes in JDA: https://github.com/discord-jda/JDA/issues/2129 (I'm not manually specifying dependencies tho, so probably not the exact same thing)

Erdragh avatar Nov 28 '23 12:11 Erdragh

To use Kotlin For Forge in Architectury you must use "implementation" instead of "forgeImplementation"

thedarkcolour avatar Nov 28 '23 19:11 thedarkcolour

I am using implementation: https://github.com/Erdragh/AstralBot/blob/main/forge/build.gradle.kts

Erdragh avatar Nov 28 '23 20:11 Erdragh

According to the Architectury Discord this may be caused by okhttp3 not having access to kotlin because it's in the bootstrap class loader, while KFF's kotlin stdlib is in the mod class loader. I don't know enough about forge and especially forge's class loading to give any specifics tho.

Erdragh avatar Nov 28 '23 20:11 Erdragh

If you compile your mod and run it in a Forge instance outside of IntelliJ, does it still crash?

thedarkcolour avatar Nov 29 '23 19:11 thedarkcolour

It does crash but because of a different thing, it can't load the Apache collections things, but that's because from what I can tell they're just not there and I need to include it - or shadow it in.

Edit: said crash also happens when running the built fabric jar on a fabric server, so it's not a forge issue.

Erdragh avatar Nov 29 '23 19:11 Erdragh

You may need to add the Kotlin dependencies to Gradle yourself. If that doesn't work, I know on ForgeGradle there is a snippet that gets shared around on the server with the command !nonmclibs which links to this gist. Not sure what the equivalent is for that in Architectury but you might be able to ask around. If that still doesn't work, then let me know.

thedarkcolour avatar Nov 29 '23 19:11 thedarkcolour

Could you elaborate on that first part a bit? I'm kind of new to gradle and have been reading a lot of documentation, but haven't wrapped my head around everything just yet

Erdragh avatar Nov 29 '23 19:11 Erdragh

Is your buildscript a build.gradle or a build.gradle.kts?

thedarkcolour avatar Nov 29 '23 19:11 thedarkcolour

I've linked the repo, it's all completely .kts

Erdragh avatar Nov 29 '23 19:11 Erdragh

Add this to your dependencies block:

    // Default classpath
    api(kotlin("stdlib"))
    api(kotlin("stdlib-common"))
    api(kotlin("stdlib-jdk8"))
    api(kotlin("stdlib-jdk7"))
    api(kotlin("reflect"))

thedarkcolour avatar Nov 29 '23 19:11 thedarkcolour

Didn't fix it. The equivalent of minecraftLibrary for Architectury seems to be forgeRuntimeLibrary, replacing the api in your suggestion with that results in:

> Could not find org.jetbrains.kotlin:kotlin-stdlib:.
     Required by:
         project :forge

and more for each specified dependency

Erdragh avatar Nov 29 '23 19:11 Erdragh

You might need to try something else besides what I gave you, since gradle cannot find kotlin for some reason

thedarkcolour avatar Nov 29 '23 20:11 thedarkcolour

I've tested with a debugger and it looks like okhttp3 is being loaded on a different classloader than JDA. When stepping into the setter for Dispatcher.maxRequestsPerHost, you can use the Evaluate Expression tool to see that kotlin.Unit crashes, like in your original error message. However, Minecraft classes like Block and Entity also crash, which is strange and indicates that this is probably not a KFF issue.

thedarkcolour avatar Dec 05 '23 03:12 thedarkcolour

I encountered what I think is the same issue while trying to use Ktor on Forge with Architectury, and I came up with a slightly hacky workaround that seems to work pretty well.

As you said, I think the issue is that forgeRuntimeLibrary loads classes on the MC-BOOTSTRAP layer/classloader (via the legacyClassPath.file property), while KFF puts the Kotlin stdlib on the PLUGIN layer. Since MC-BOOTSTRAP only has the BOOT layer as a parent, Kotlin libraries loaded there are unable to access the stdlib on the PLUGIN layer. It works fine in production because JarJar libraries are loaded on the GAME layer, which has access to PLUGIN.

I'm not sure if there's a better way to fix this in dev, but my workaround was to create a Gradle artifact transform that adds FMLModType: GAMELIBRARY to the META-INF/MANIFEST.MF file of each Kotlin dependency. This tells Forge to load the jar as a library on the GAME layer. I'm only using this transform in the localRuntime configuration, so it doesn't affect the libraries included in the production jar.

Links:

I think this is also the same issue behind #94.

object-Object avatar May 02 '24 22:05 object-Object

This issue happens because Kotlin for Forge shadows the Kotlin standard libraries, when it should be using JarJar to include them. However, due to an issue in Forge/NeoForge this is not possible.

Worth mentioning that this issue has been fixed in Kotlin for Forge 5.0.0 on NeoForge 1.20.5.

thedarkcolour avatar May 04 '24 23:05 thedarkcolour

Just to confirm, are JarJar libraries loaded onto the Boot or MC-BOOTSTRAP layer? If not, I'd think this would still be an issue in the dev environment, wouldn't it?

object-Object avatar May 04 '24 23:05 object-Object

JarJar libraries are loaded onto the GAME layer.

thedarkcolour avatar May 05 '24 00:05 thedarkcolour

This should be fixed on Kotlin for Forge 5.x

thedarkcolour avatar Jun 15 '24 22:06 thedarkcolour

Is it possible to backport this to 4.x ?

emyfops avatar Sep 06 '24 22:09 emyfops

It is, but only on very recent versions of Forge.

thedarkcolour avatar Sep 06 '24 22:09 thedarkcolour

Which versions ? Before the bootstrap update ?

emyfops avatar Sep 06 '24 22:09 emyfops

For 1.20.1:

 - 47.3.3 Choose default JarJar mod file type based on parent JAR (#10023)
          Co-authored-by: thedarkcolour <[email protected]>

For 1.19.2:

 - 43.4.1 Choose default JarJar mod file type based on parent JAR (#10025)
          Co-authored-by: thedarkcolour <[email protected]>

thedarkcolour avatar Sep 06 '24 22:09 thedarkcolour

I see that your fix was merged in 1.20.4 https://github.com/MinecraftForge/MinecraftForge/pull/10022 but the issue seems to persist even on the latest version in dev environment

KFF is implemented with the implementation in arch loom

Caused by: java.lang.module.ResolutionException: Module thedarkcolour.kotlinforforge contains package kotlinx.coroutines.selects, module kotlinx.coroutines.core exports package kotlinx.coroutines.selects to thedarkcolour.kotlinforforge

emyfops avatar Sep 06 '24 22:09 emyfops

What do you mean by latest version? I only really wrote documentation for 1.21+ because that's the only relevant versions for which it is fixed (but this should work for 1.20.4 too) kotlin modding skeleton (there is also a Forge branch but I didn't document the library issue for that one)

thedarkcolour avatar Sep 06 '24 22:09 thedarkcolour

The issue happens in my dev environment only Arch Loom 1.7.412 MC 1.20.4 Forge 49.1.4

You said that the issue was fixed in 1.19 to 1.21, right ? I know that there's an issue with architectury-transformer where it cannot remove duplicate modules ~but it shouldn't affect this conflicting kotlin libraries~ actually it might be the reason https://github.com/architectury/architectury-transformer/issues/24

emyfops avatar Sep 06 '24 22:09 emyfops

Yeah Loom tends to break stuff I wish I were more knowledgeable about it but all of my mods are (Neo)Forge-only so I never run into this problem, would be nice to have an ExampleMod project.

thedarkcolour avatar Sep 06 '24 22:09 thedarkcolour

I'm gonna wait for a follow-up from the maintainer and get back to you afterward

emyfops avatar Sep 06 '24 22:09 emyfops