Skip to content

Instantly share code, notes, and snippets.

@maow-tty
Last active August 20, 2023 05:52
Show Gist options
  • Save maow-tty/c528b6f9f5ba07442c094cbdbd2b7af8 to your computer and use it in GitHub Desktop.
Save maow-tty/c528b6f9f5ba07442c094cbdbd2b7af8 to your computer and use it in GitHub Desktop.
Minecraft Observed Client Launching Behaviours

Minecraft Observed Client Launching Behaviours

Author: Maow
Date: 8/19/23

Overview

This is a mostly informal document written to archive my personal analysis (some information may be incorrect or inaccurate) of Minecraft's launch procedure when paired with the latest version of the official, modern launcher. Most launchers, e.g. Legacy/"Notchian", Betacraft, Prism, will operate similarly but likely use a different main class.

This information is valuable for those wanting to manipulate the game for modding purposes, and was originally conducted as research for Betablood.

Versions

It is well-known at this point that the launcher uses a "version manifest" file containing version information.

This version manifest file points to various other version files, which contain necessary libraries, rules for selecting platform-specific libraries (i.e. LWJGL), launch arguments, and various other options, e.g. the class to launch from (main class), the version's compliance level.

If the locally stored version manifest (.minecraft/versions/version_manifest_v2.json) doesn't match the one contained on Mojang's servers, it is re-downloaded.

Version files are also able to inherit properties from other properties. The Fabric Loader uses this to extend the game version file correlating to the version being modded, as it allows the loader to not specify all of Minecraft's launch arguments or libraries.

Fabric's version file modifies the main class property to be KnotClient, a wrapper around Knot which specifies the environment as being a client.

Knot is Fabric's launch bootstrapper, similar to cpw's BootstrapLauncher and Mojang's LegacyLauncher.

The version file is downloaded to the version folder located at .minecraft/versions/<version> and is consulted upon launch to find jars, to replace those which are missing or have an invalid hash, and to find and substitute launch arguments.

Launcher Profiles

Version files simply contain the information for launching versions. Launcher profiles are configured through .minecraft/launcher_profiles.json, and while most profiles point to a version that exists under .minecraft/versions, if given the type/ID latest-snapshot or latest-release, they will instead point to the corresponding latest version located under the version manifest file. These profiles additionally do not require names, as the launcher will assign one automatically.

Profile icons can either be one of the named values, e.g. Cobblestone or Dirt, or a data URI containing a Base64-encoded PNG image.

Miscellaneous

  • The client does not require a valid session token. It will not authenticate with session servers, but the game will not be prevented from launching. This behaviour is used by the launcher's offline mode, as well as mod development environments, i.e. dev-launch-injector.
  • The classpath contains the version jar (.minecraft/versions/<version>/<version>.jar) as well as all required libraries. These are specified by the version file, and are downloaded and stored under .minecraft/libraries. Depending on the user's platform, different jars may be downloaded (most notably lwjgl-platform).
  • The game process's working directory is .minecraft.
  • For older versions, i.e. b1.7.3, the main class is provided by the LegacyLauncher library (net.minecraft.launchwrapper.Launcher).

Classpath can be verified through jinfo, working directory through pwdx.

Command-Line Launching

Minecraft can be launched on the command-line if provided the proper arguments and paths. You will also need to launch the game normally beforehand. I have provided a minimal example command for b1.7.3. This command excludes most JVM and launcher metadata arguments.

<java> -Djava.library.path=<native-libraries> -cp <libraries> <main-class> <user> <user-session-token> --gameDir <game-directory> --assetsDir <assets-directory>

  • java = Minecraft uses its own Java installations. On Linux, these are located under .minecraft/runtime.
    • You will likely not be able to launch the game with newer versions of Java without first updating the native libraries.
    • b1.7.3 uses the jre-legacy installation.
  • native-libraries = A directory containing platform-specific native binaries. This is located under .minecraft/bin/<hash>.
    • The hash is consistent for the version. In what way I'm unsure. You may need to view the arguments for a game process ran by the launcher.
    • b1.7.3's directory is fcea75b79b1181890c01f189503e574173dc37b7.
  • libraries = A set of library jars delimited by :. This includes the version jar, i.e. .minecraft/versions/b1.7.3/b1.7.3.jar.
  • main-class = A class containing a main method. This is the entrypoint for the JVM,.
    • The launcher uses net.minecraft.launchwrapper.Launch, although b1.7.3's actual entrypoint is net.minecraft.client.Minecraft.
  • user = The player's username.
  • user-session-token = The player's session token.
    • As mentioned previously, this doesn't need to be valid. A valid token is prefixed with token:.
    • I'm not sure which authentication scheme this uses. Likely Legacy Minecraft Authentication, as AuthLib (used for Yggdrasil and Microsoft) is not a dependency of b1.7.3.
  • game-directory = Your .minecraft directory as an absolute path, i.e. /home/<user>/.minecraft on Linux.
  • assets-directory = Unsure.
    • On b1.7.3, this points to .minecraft/assets/virtual/pre-1.6, but said directory does not exist.
    • The pre-1.6 id is used by b1.7.3's version file as the value of assets and assetIndex's id.
@maow-tty
Copy link
Author

Addendum for aspiring mod loader developers:

When Fabric is installed on the client, the version jar is empty. Upon launching, the vanilla version jar is downloaded.
The KnotClient class is provided by a library, specifically the net.fabricmc:fabric-loader library, and is accessible because it's on the classpath.

Through your launch bootstrapper, the game's main class can be loaded by a transforming class loader. If initialized, all linked classes will also be resolved by your class loader, which allows you to modify the bytecode of all classes.

With all this in mind, you can implement Mixin through its SPI, initialize the mixin subsystem, and finally provide your mod's mixin configurations. After that, you can boot the game.

You might additionally require access wideners/transformers.

Mod loading is relatively simple, mods must be added to the game classpath so other mods, and code injected through mixin, can reference classes.

Actually loading the jar files and obtaining mod metadata is up to preference.
You can use java.util.zip which is slightly outdated but still functional, or zipfs from java.nio.path. Zipfs allows you to perform all filesystem operations on jars, but is expensive to set up.
There's also the alternative of writing your own zip library, calling zlib from JNI/Panama, or using an alternative zip library.

Mod metadata is usually configured through files. Fabric uses JSON, while Forge uses TOML. Forge additionally uses annotations to mark the mod class, which requires a bytecode annotation scanner (ASM) and might require caching to make subsequent launches faster.

Mods usually require dependencies, so you will need a way to compare SemVer values as well as some way to report dependency issues to the user. Fabric uses a Swing menu for this as far as I know.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment