oracle / graal

GraalVM compiles Java applications into native executables that start instantly, scale fast, and use fewer compute resources 🚀
https://www.graalvm.org
Other
20.45k stars 1.64k forks source link

[Native Image] Minecraft server is successfully built to native executable, but it doesn't accept/receive any incoming connections #10224

Open BlueGradientHorizon opened 13 hours ago

BlueGradientHorizon commented 13 hours ago

Describe the Issue

Hello. I've been trying to build native image of most recent version of Minecraft server fork PaperMC and achieved some sort of success. The server is running, generating all of needed files, chunks, executing commands, etc, but it doesn't accept any clients. Nothing is being printed in the console when client tries to connect.

Using the latest version of GraalVM can resolve many issues.

GraalVM Version

java version "24" 2025-03-18
Java(TM) SE Runtime Environment Oracle GraalVM 24-dev+23.1 (build 24+23-jvmci-b01)
Java HotSpot(TM) 64-Bit Server VM Oracle GraalVM 24-dev+23.1 (build 24+23-jvmci-b01, mixed mode, sharing)

Oracle GraalVM for JDK 24 - early access build - 24.0.0-ea.22

Operating System and Version

Windows 11 23H2 22631.4317 amd64

Troubleshooting Confirmation

Run Command

See Steps to Reproduce section.

Expected Behavior

To be able for clients to connect to the native-image-compiled PaperMC server.

Actual Behavior

Clients can't connect to the server, including getting its MOTD, like it isn't even running.

Steps to Reproduce

  1. I'm on Windows, and JFR isn't supported (source):

Note: JFR event recording is not yet available with Native Image on Windows.

But, interestingly, although I didn't enable it via passing cmd arguments to native-image, mc server was crashing.

Stacktrace ``` [18:27:55] [main/WARN]: Failed to load datapacks, can't proceed with server load. You can either fix your datapacks or reset to vanilla with --safeMode java.util.concurrent.ExecutionException: java.lang.UnsatisfiedLinkError: jdk.jfr.internal.JVM.isExcluded(Ljava/lang/Class;)Z [symbol: Java_jdk_jfr_internal_JVM_isExcluded or Java_jdk_jfr_internal_JVM_isExcluded__Ljava_lang_Class_2] at java.base/java.util.concurrent.CompletableFuture.wrapInExecutionException(CompletableFuture.java:347) ~[org.bukkit.craftbukkit.main.exe:?] at java.base/java.util.concurrent.CompletableFuture.reportGet(CompletableFuture.java:442) ~[org.bukkit.craftbukkit.main.exe:?] at java.base/java.util.concurrent.CompletableFuture.get(CompletableFuture.java:2119) ~[org.bukkit.craftbukkit.main.exe:?] at net.minecraft.server.Main.main(Main.java:304) ~[?:?] at io.papermc.paper.PaperBootstrap.boot(PaperBootstrap.java:21) ~[?:?] at org.bukkit.craftbukkit.Main.main(Main.java:281) ~[?:?] at java.base/java.lang.invoke.LambdaForm$DMH/sa346b79c.invokeStaticInit(LambdaForm$DMH) ~[?:?] Caused by: java.lang.UnsatisfiedLinkError: jdk.jfr.internal.JVM.isExcluded(Ljava/lang/Class;)Z [symbol: Java_jdk_jfr_internal_JVM_isExcluded or Java_jdk_jfr_internal_JVM_isExcluded__Ljava_lang_Class_2] at org.graalvm.nativeimage.builder/com.oracle.svm.core.jni.access.JNINativeLinkage.getOrFindEntryPoint(JNINativeLinkage.java:152) ~[?:?] at org.graalvm.nativeimage.builder/com.oracle.svm.core.jni.JNIGeneratedMethodSupport.nativeCallAddress(JNIGeneratedMethodSupport.java:41) ~[?:?] at jdk.jfr@24/jdk.jfr.internal.JVM.isExcluded(Native Method) ~[?:?] at jdk.jfr@24/jdk.jfr.internal.MetadataRepository.register(MetadataRepository.java:139) ~[?:?] at jdk.jfr@24/jdk.jfr.internal.MetadataRepository.register(MetadataRepository.java:134) ~[?:?] at jdk.jfr@24/jdk.jfr.FlightRecorder.register(FlightRecorder.java:129) ~[org.bukkit.craftbukkit.main.exe:?] at java.base/java.lang.Iterable.forEach(Iterable.java:75) ~[org.bukkit.craftbukkit.main.exe:?] at net.minecraft.util.profiling.jfr.JfrProfiler.(JfrProfiler.java:79) ~[?:?] at net.minecraft.util.profiling.jfr.JfrProfiler.(JfrProfiler.java:79) ~[?:?] at net.minecraft.util.profiling.jfr.JvmProfiler.(JvmProfiler.java:49) ~[org.bukkit.craftbukkit.main.exe:1.21.3-80-c2294d7] at net.minecraft.commands.Commands.(Commands.java:225) ~[org.bukkit.craftbukkit.main.exe:1.21.3-80-c2294d7] at net.minecraft.server.ReloadableServerResources.(ReloadableServerResources.java:41) ~[?:?] at net.minecraft.server.ReloadableServerResources.lambda$loadResources$1(ReloadableServerResources.java:85) ~[?:?] at java.base/java.util.concurrent.CompletableFuture$UniCompose.tryFire(CompletableFuture.java:1196) ~[?:?] at java.base/java.util.concurrent.CompletableFuture.postComplete(CompletableFuture.java:556) ~[org.bukkit.craftbukkit.main.exe:?] at java.base/java.util.concurrent.CompletableFuture.postFire(CompletableFuture.java:660) ~[org.bukkit.craftbukkit.main.exe:?] at java.base/java.util.concurrent.CompletableFuture$UniApply.tryFire(CompletableFuture.java:699) ~[?:?] at java.base/java.util.concurrent.CompletableFuture$Completion.run(CompletableFuture.java:528) ~[org.bukkit.craftbukkit.main.exe:?] at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1144) ~[org.bukkit.craftbukkit.main.exe:?] at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:642) ~[?:?] at java.base/java.lang.Thread.runWith(Thread.java:1589) ~[org.bukkit.craftbukkit.main.exe:?] at java.base/java.lang.Thread.run(Thread.java:1576) ~[org.bukkit.craftbukkit.main.exe:?] at org.graalvm.nativeimage.builder/com.oracle.svm.core.thread.PlatformThreads.threadStartRoutine(PlatformThreads.java:832) [org.bukkit.craftbukkit.main.exe:?] at org.graalvm.nativeimage.builder/com.oracle.svm.core.thread.PlatformThreads.threadStartRoutine(PlatformThreads.java:808) [org.bukkit.craftbukkit.main.exe:?] ```

Later I've checked how native executable will behave if compiled for linux aarch64 (Termux, ubuntu proot-distro) using the same GraalVM EA version, but I got the same exception message. Anyway I solved this problem by creating a patch for PaperMC and compiling it from source.

  1. Run the server bootstrapper for the first time to unpack libraries and patch official server with Paper patches

    "C:\Program Files\graalvm-jdk-24+23.1\bin\java.exe" -jar paper-paperclip-1.21.3-R0.1-SNAPSHOT-mojmap.jar
  2. Generate the list of needed libraries for classpath argument

    (ls .\libraries\ -Recurse -Include *.jar | % { $_.FullName }) -Split([Environment]::NewLine, [System.StringSplitOptions]::RemoveEmptyEntries) -join ";" > libraries.txt
  3. Create file arg.txt with classpath and main launch class for convenience

    -cp versions\1.21.3\paper-1.21.3.jar;<contents of libraries.txt> org.bukkit.craftbukkit.Main
  4. Run the server with metadata collection

    "C:\Program Files\graalvm-jdk-24+23.1\bin\java.exe" -agentlib:native-image-agent=config-merge-dir=./,config-write-period-secs=10 @arg.txt nogui

    First, you'll need to accept Minecraft EULA. Edit eula.txt and set eula value to true and then run the server again using the same command.

  5. Slightly modify reachability-metadata.json By some reason, native image agent does not include all files of the data directory inside server jar into that file, but these are crucial for server to run, so replace:

    {
      "glob": "data/.mcassetsroot"
    },

    with

    {
      "glob": "data/**"
    },
  6. Build native image

    "C:\Program Files\graalvm-jdk-24+23.1\bin\native-image.cmd" --no-fallback --enable-url-protocols=http,https --initialize-at-build-time=net.minecraft.util.profiling.jfr.event,org.apache.logging.log4j,net.minecrell.terminalconsole.TCALookup -H:+UnlockExperimentalVMOptions -H:ConfigurationFileDirectories=./ -H:+AddAllCharsets -H:+IncludeAllLocales @arg.txt
  7. Run native executable

    org.bukkit.craftbukkit.main.exe nogui

    nogui is mandatory or you'll get java.lang.NoSuchMethodError: java.awt.Toolkit.getDefaultToolkit()Ljava/awt/Toolkit; (by default it will try to open GUI window with console and memory monitor).

  8. Try connecting to the server using official unmodified Minecraft 1.21.3 client You'll not be able to do so, like the server isn't even running. But it actually opens a default 25565 port (I've checked it by using TCPView).

Additional Context

PaperMC server (commit da71382) with my patch - link Compiled native image of that server for Windows amd64 - link Native image bundle - link

Minecraft uses Netty for network communications.

Run-Time Log Output and Error Messages

Nothing is being printed in the console when client tries to connect.

selhagani commented 9 hours ago

Hi @BlueGradientHorizon,

Thank you for reaching out!

Since there’s no specific error log provided, it’s difficult to pinpoint exactly what went wrong with the native executable. It’s possible that despite using the tracing agent, there are still missing metadata registration issues. I recommend diagnosing this by following the steps outlined in this documentation. These steps can help identify and resolve missing metadata problems.

Unfortunately, I’m unable to reproduce this on my end as I don’t have a Minecraft account.

thejudge156 commented 4 hours ago

Hey! I work on MCNative, a (albeit work-in-progress) project that does the MC Client and (soon) different server software. I have some Proof-of-concept in my repo, but you should look at these files. I suspect the issue is not these files that I linked however. If I remember correctly, you have to run the metadata agent and join the server on a client and then stop the server. This is also not good enough for stuff like the Ender Dragon, (which uses reflection for some reason). So if you want to even go to the end, you should run the following command: /execute in minecraft:the_end run tp @s 0 128 0

Just make sure you are in creative, (because fall damage will steal your soul), then let the ender dragon do its thing for like 3 minutes. Then you can stop the server and fight it in the native image.

If you would like to join forces on this, let me know. I am more than happy to share my knowledge and experience.

thejudge156 commented 4 hours ago

Also, rather than manually patching the jar, take a look at this substitution I made using GraalVM's sub api.