Minecraft in Astral

Being able to play games on your homebrew operating system is a big milestone to strive for. It shows that the system has enough implemented for a graphical application to run and get input, that it is fast enough for a game to be playable and that it is stable enough for the game to be played. Usually, the game of choice is Doom, as it has the reputation of being ported to everything under the sun, as well as being an FPS game that can demonstrate all of the points above about your operating system.
Astral currently has some working game ports, which include Doom and Quake. However, as the capabilities of the operating system grow, so will the complexity of the games that can be played. I have been meaning to add a new game port for a while now, and I eventually decided on a game I had played a lot when I was younger: Minecraft.
The challenges of running Minecraft
Minecraft is *not* an easy game to run. It is written in Java, so you need a working JVM. It uses OpenGL, so you also need a working OpenGL implementation. Additionally, it depends on many different Java libraries that you also have to port. Astral has had OpenJDK 17 and Mesa ported for a while now. The Mesa port works perfectly, but the OpenJDK port ended up bit-rotting and eventually stopped working due to a bug in mlibc.Choosing a version to run
The first step of this process was choosing which Minecraft version would run in Astral and then figuring out the Java command used to start it. I needed something simple and with as few dependencies as possible, so I picked version Alpha 1.2.0. This version only has one dependency, LWJGL2, reducing porting time and making debugging easier later on.Getting the JVM to work again
The next step was getting OpenJDK working in Astral again. As I mentioned earlier, it had bit-rotted and was now suffering from a segmentation fault when starting. The OpenJDK stack trace had given some important information: it was happening inlibc.so after OpenJDK called sscanf(3) with a big %[] specifier which had almost every value from 0 to 255.I eventually figured out that, due to the mlibc code using the
char value from the format string, the values above 127 passed by OpenJDK would be handled as negative integers, which ended up causing accesses to negative array indexes and stack corruption. With this fixed, javac was able to run without issue, and I was ready to move on to the next part of this project.Porting LWJGL2
LWJGL (Lightweight Java Game Library) is a Java library that is used to create cross-platform games in Java, providing access to APIs like OpenGL and abstractions for things like input. Up until Minecraft release 1.12, LWJGL 2 was used, which is no longer maintained as LWJGL 3 has been released. The version of Minecraft that will be run is Alpha 1.2.0, so LWJGL 2 will need to be ported.The process of porting LWJGL2 was quite painful. This mostly involved adding instructions to cross-compile the native libraries for Astral. LWJGL uses Apache Ant as the build system, which I have found to be very hostile to cross-compilation. Most of the patching effort was in the build system, as I did not need to modify any native C code and the only modification to Java code was adding Astral to the list of known OSes. You can find the patch file here, if you are interested.
Running Minecraft and Debugging
With LWJGL ported, all that was left to do was boot Astral and debug any problems that end up happening. During this process, I was joined by Dennis Bonke, who maintains Managarm's ports collection. We worked together so we could eventually get Minecraft running on Managarm as well.To start minecraft I made a simple shell script. It switches to the directory where LWJGL is installed and calls java with all the nescessary arguments for it to start up. This is the version of the script that first got a working Minecraft:
cd /usr/share/lwjgl/usr/lib/jvm/java-17/bin/java -Xint -Xmx1g -Djava.library.path="/usr/share/lwjgl" -cp "lwjgl.jar:lwjgl_util.jar:/home/astral/minecraft.jar" net.minecraft.client.MinecraftIn the first attempt, Java would run for a bit and then exit and mlibc would log about a missing
AWTFontMinByte1 symbol. This is a symbol needed by libfontmanager.so and defined by libawt_xawt.so. Looking at rtld logs, libawt_xawt.so did get loaded by dlopen(3) (twice!), which means that there must have been a bug with mlibc. Eventually, we narrowed it down to the fact that OpenJDK first runs dlopen(3) for libawt_xawt.so with RTLD_LOCAL and then again with RTLD_GLOBAL, and the mlibc shared object promotion code was broken for this case. After fixing this, we actually got a window out of Minecraft!
However, it is clear it is still not working. The crash is an LWJGL error talking about an unknown platform. This was a missing piece of code in the LWJGL patch and was quick to fix. Next run, it went further but crashed with another missing symbol,
SUNWprivate_1.1. We figured out this was a symbol that is not present in modern OpenJDK versions so this was clearly an issue with the cross-compilation.
This was a simple but annoying fix, I had to add specific variables to the astral_ant XML in LWJGL to make cross compilation easier and to use the proper headers, as it was still trying to use the host OpenJDK 8 headers. Now, LWJGL actually got further! Running it again, we hit another issue: an ArrayIndexOutOfBoundsException while initializing the display.
Diving into the LWJGL source code, we eventually figured out that the issue was in the
XRandR class populate() function, as the exception Seek not possible (ESPIPE) was happening while populating the screen hashmap. After adding a print to get the backtrace, we ended up at the native OpenJDK function handleAvailable(), which returns the number of bytes left to read in a file. The issue here was that Astral did not implement FIONREAD for pipe objects, causing it to fall back to seeking. Since seeking on a pipe is not possible, the ESPIPE error is returned. After implementing it, Minecraft got into the menu screen!
Playing Minecraft
After that, it was smooth sailing. We were able to load into a world and verified that the game was working, from breaking blocks to saving. This was, to my knowledge, the first time a hobbyist OS ran Minecraft, which is a huge milestone not just for Astral but for the OSDev community as a whole, since it not only proves that it is possible, but also paves the way for others to do it as well with the open-source patches and mlibc fixes.

What's next for Astral?
A lot of the recent Astral work has been towards self-hosting, speed, stability and just general usability. There is now a working package manager (xbps) and all the necessary tools for a networked install to disk. This work will likely continue for the near future, and, after more improvements, I have plans of eventually releasing a sort of Astral from scratch guide to build an Astral distribution from inside another Astral distribution. There are also plans to revive the Wine port (which is still not fully functional) with Dennis for both Astral and Managarm, as well as a possible future WebKitGTK port.Thanks for reading!