diff --git a/Dockerfile b/Dockerfile index a0edf3ae..b7d4d311 100644 --- a/Dockerfile +++ b/Dockerfile @@ -3,12 +3,15 @@ # TODO: download HMC-Specifics? FROM openjdk:17.0.2-jdk as java17 +FROM openjdk:21-jdk as java21 FROM openjdk:8u332-jdk COPY --from=java17 /usr/java/openjdk-17 /usr/java/openjdk-17 +COPY --from=java21 /usr/java/openjdk-21 /usr/java/openjdk-21 # For some reason the jdk17 image does not come with any certificates, which causes problems RUN cp --remove-destination /usr/local/openjdk-8/jre/lib/security/cacerts /usr/java/openjdk-17/lib/security/cacerts +RUN cp --remove-destination /usr/local/openjdk-8/jre/lib/security/cacerts /usr/java/openjdk-21/lib/security/cacerts COPY . /headlessmc WORKDIR /headlessmc diff --git a/README.md b/README.md index ff5549b7..770f2440 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,9 @@ -# HeadlessMc +

HeadlessMc

+

A command line launcher for Minecraft Java Edition.

+

Mc-Runtime-Test | HMC | HMC-Specifics | HMC-Optimizations

+ +
+ [![Codacy Badge](https://app.codacy.com/project/badge/Grade/6a86b3e62d3b47909de670b09737f8fd)](https://app.codacy.com/gh/3arthqu4ke/headlessmc/dashboard?utm_source=gh&utm_medium=referral&utm_content=&utm_campaign=Badge_grade) [![GitHub All Releases](https://img.shields.io/github/downloads/3arthqu4ke/HeadlessMc/total.svg)](https://github.com/3arthqu4ke/HeadlessMc/releases) ![](https://github.com/3arthqu4ke/HeadlessMc/actions/workflows/gradle-publish.yml/badge.svg) @@ -6,6 +11,8 @@ [![Docker Image Size](https://badgen.net/docker/size/3arthqu4ke/headlessmc?icon=docker&label=image%20size)](https://hub.docker.com/r/3arthqu4ke/headlessmc/) ![Github last-commit](https://img.shields.io/github/last-commit/3arthqu4ke/HeadlessMc) +
+ > [!WARNING] > NOT AN OFFICIAL MINECRAFT PRODUCT. NOT APPROVED BY OR ASSOCIATED WITH MOJANG OR MICROSOFT. > @@ -13,45 +20,68 @@ > Accounts will always be validated. > Offline accounts can only be used to run the game headlessly in CI/CD pipelines. -HeadlessMc allows you to launch Minecraft from the command line. It is also able to instrument the game: before -launch the bytecode of the games libraries can be modified. HeadlessMc aims to use this feature to - -* add a command line interface to Minecraft, which can control the game. -* redirect every method in the lwjgl library, causing Minecraft not to render anything, thus making it "headless". -* patch the Log4J vulnerability. +HeadlessMc (HMC) allows you to launch Minecraft Java Edition from the command line. +It can also modify the game while and before running it. +This feature can be used to make the Minecraft client run in headless mode, +without displaying a UI, controlled by the command line. +HeadlessMc also patches the Log4J vulnerability +and can be used +to test the game in your CI/CD pipeline with [mc-runtime-test](https://github.com/3arthqu4ke/mc-runtime-test). ## How to use -All you need is the `headlessmc-launcher.jar` file and java ≥ 8 installed. The launcher will start after you -executed `java -jar headlessmc-launcher.jar` in a terminal of your choice. Double-clicking the jar is not supported. -After that HeadlessMc will create a `HeadlessMc/config.properties` file. Edit that file, create a key -`hmc.java.versions` inside. The value should be a `;` separated list to of java executables HeadlessMc can use, like -this: - -```properties -hmc.java.versions=C:/Program Files/Java/jre-/bin/java;C:/Program Files/Java/jdk-/bin/java -``` - -After you are done, type `config -refresh` then `java -refresh`, press enter, and you are ready start. Here are some of -the most important commands: - -| Name | Description | Args/Flags | -| ----------- | ----------- | ----------- | -| help | Lists commands and prints informations.| \ \ -id | -| quit | Exits HeadlessMc. | | -| versions | Lists all Minecraft versions currently installed. | -release -snapshot -other | -| download | Lists available Minecraft versions and downloads them. | \ -id -release -snapshot -other -refresh | -| login | Logs into a Microsoft account. | \, will open a context for entering the password. | -| launch | Launches Minecraft. | \ -commands -lwjgl -paulscode -lookup -jndi -noout -keep -exit | -| forge | Installs Minecraft Forge. | \ \<--uid\> | -| fabric | Installs Fabric. | \ | - -To launch the game in headless mode type use the launch command with the `-lwjgl` flag: -`launch -lwjgl` +1. Download the `headlessmc-launcher.jar` from the releases tab and install a Java version ≥ 8. +2. Run the launcher with `java -jar headlessmc-launcher.jar` in your terminal. +You can also use the `hmc.sh/bat` scripts for convenience. +3. You need to specify which Java installations HeadlessMc can use to run the game. +Open the file `HeadlessMC/config.properties` and add a key called `hmc.java.versions`, +with a `;` seperated list of java versions HeadlessMc can use, like this: + ```properties + hmc.java.versions=C:/Program Files/Java/jre-/bin/java;C:/Program Files/Java/jdk-/bin/java + ``` + On Windows Java versions in `Program Files/Java` will already get detected automatically. +4. Execute `config -refresh` and then `java -refresh`, HeadlessMc should now know which Java versions to use. +5. HeadlessMc will generally not allow you to start the game without an account. +Login to your Minecraft account by executing the `login ` command. +For now, Microsoft's 2FA is not supported in headless mode, +but you can use the `login -webview` flag to open Microsoft's login UI +(You can then copy over the HeadlessMC folder with all files to your headless machine). +6. You can download Minecraft Vanilla versions with the download command, e.g. `download 1.21`. +7. After downloading a Vanilla version you can also install modloaders +with the `forge`, `fabric`, and `neoforge` commands, e.g. `fabric 1.21`. +8. With `versions` you can list your downloaded Minecraft versions. +9. With `help` you can list other available commands. +10. If you are ready to launch the game execute `launch `. +If you want to start the game in headless mode add the `-lwjgl` flag. + +The [hmc-specifics](https://github.com/3arthqu4ke/hmc-specifics) are mods +that you can place inside your .minecraft/mods folder. +With HeadlessMc they allow you to control the game via the command line, e.g. +by sending chat messages and commands with `msg ""`, +visualizing the menus displayed by Minecraft via `gui` and clicking through menus via `click`. Arguments passed to commands have to be separated using spaces. If you want to pass an Argument which contains spaces you need to escape it using quotation marks, like this: -`"argument with spaces"`. Quotation marks and backslashes can be escaped by using a backslash. +`"argument with spaces"`. +Quotation marks and backslashes can be escaped by using a backslash. +So `msg "A text with spaces"` will send the chat message `A text with spaces`, +while `msg "\"A text with spaces\"" additional space` +will send the chat message `"A text with spaces"` and the argument `additional space` will be dropped. + +HeadlessMc also has a preconfigured [docker image](https://hub.docker.com/r/3arthqu4ke/headlessmc/), +which comes with Java 8, 17 and 21 installed. +Pull it via `docker pull 3arthqu4ke/headlessmc` +and run it with `docker run -i -t -p 3arthqu4ke/headlessmc`. +Inside the container you can use the `hmc` command anywhere. + +HeadlessMc achieves headless mode by patching the LWJGL library: +every of its functions is rewritten to do nothing, or to return stub values. +This has the advantage of being independent of Minecraft versions, +but comes with some overhead. +A Minecraft version dependent approach are the [hmc-optimizations](https://github.com/3arthqu4ke/hmc-optimizations), +another set of mods which patch Minecraft itself to skip all rendering code. +You can also achieve headless mode without patching lwjgl by running headlessmc with a virtual framebuffer like +[Xvfb](https://www.x.org/releases/X11R7.6/doc/man/man1/Xvfb.1.xhtml). HeadlessMc can be configured using properties. These can be passed as SystemProperties from the command line or via the `HeadlessMc/config.properties` file. Additional configs can be added to the `HeadlessMc/configs` folder. For available @@ -60,35 +90,6 @@ information see the [HmcProperties](headlessmc-commons/src/main/java/me/earth/he [RuntimeProperties](headlessmc-runtime/src/main/java/me/earth/headlessmc/runtime/RuntimeProperties.java) or the [LwjglProperties](headlessmc-lwjgl/src/main/java/me/earth/headlessmc/lwjgl/LwjglProperties.java). -> :warning: Because I don't want to get into trouble HeadlessMc will not store your account credentials. If you don't want to enter them everytime you can supply them using the properties (**at your own risk**). - -## Runtime - -In attempt to provide some debuggability HeadlessMc can control the game using commands when launching it with the -`-commands` flag. However, because I wanted this to be "not-version-specific", this is just java-reflection in form of -commands. For more comfortable implementations, which you can use without java-knowledge, take a look at the -[HMC-Specifics](https://github.com/3arthqu4ke/HMC-Specifics). - -I don't want to go into greater detail about this because it's awful, and I don't even use it myself, so just a quick -example on how to exit the game gracefully in Minecraft 1.12.2 vanilla: - -Get the Minecraft class and store it in the 0th register (since this is vanilla we need to use obfuscated names):\ -`class bib 0 -dump`\ -Get the Minecraft instance from the class and store it in the 1st register:\ -`field 0 R 1` or `method 0 z 1`\ -Invoke the shutdown method on the Minecraft instance in the 1st register:\ -`method 1 n 2` - -One day I might add support for mappings, so you don't need to look up the obfuscated names. - -## Contributing - -You don't need to be able to code to contribute. It would be cool to eliminate as many potential crashes as possible by -running as many versions as possible using the `-lwjgl` flag. When your game crashes please open an issue. - -If you contribute code: Please document your stuff and write tests. Also try to follow the code style: wrap your lines -after 80 characters. [codestyle.xml](codestyle.xml) is code style configuration for Intellij. - ## License, more documentation, etc. Look [here](DEV.md) for more in-depth documentation about the project. diff --git a/headlessmc-launcher/src/main/java/me/earth/headlessmc/launcher/java/JavaVersionParser.java b/headlessmc-launcher/src/main/java/me/earth/headlessmc/launcher/java/JavaVersionParser.java index e46cd218..01efa889 100644 --- a/headlessmc-launcher/src/main/java/me/earth/headlessmc/launcher/java/JavaVersionParser.java +++ b/headlessmc-launcher/src/main/java/me/earth/headlessmc/launcher/java/JavaVersionParser.java @@ -11,7 +11,7 @@ public class JavaVersionParser { private static final Pattern PATTERN = Pattern.compile( - "version \"(\\d+)[.-](\\d*)"); + "version \"(\\d+)[.-]?(\\d*)"); public int parseVersionCommand(String path) throws IOException { Process prcs = new ProcessBuilder().command(path, "-version").start(); diff --git a/headlessmc-launcher/src/test/java/me/earth/headlessmc/launcher/java/JavaVersionParserTest.java b/headlessmc-launcher/src/test/java/me/earth/headlessmc/launcher/java/JavaVersionParserTest.java index 0722b3c6..9d823fe5 100644 --- a/headlessmc-launcher/src/test/java/me/earth/headlessmc/launcher/java/JavaVersionParserTest.java +++ b/headlessmc-launcher/src/test/java/me/earth/headlessmc/launcher/java/JavaVersionParserTest.java @@ -37,6 +37,12 @@ public void testParse() throws IOException { "internal+0-adhoc..src)"); Assertions.assertEquals(17, version); + version = parser.parseVersion( + "openjdk version \"21\" 2023-09-19\n" + + "OpenJDK Runtime Environment (build 21+35-2513)\n" + + "OpenJDK 64-Bit Server VM (build 21+35-2513, mixed mode, sharing)"); + Assertions.assertEquals(21, version); + Assertions.assertThrows(IOException.class, () -> parser.parseVersion("test")); } diff --git a/headlessmc-scripts/HeadlessMC/config.properties b/headlessmc-scripts/HeadlessMC/config.properties index 55a2a853..4977d188 100644 --- a/headlessmc-scripts/HeadlessMC/config.properties +++ b/headlessmc-scripts/HeadlessMC/config.properties @@ -1,7 +1,7 @@ # suppress inspection "UnusedProperty" for whole file # This config is for the docker container. hmc.gamedir=/headlessmc/headlessmc-scripts/HeadlessMC/run -hmc.java.versions=/usr/local/openjdk-8/bin/java;/usr/java/openjdk-17/bin/java +hmc.java.versions=/usr/local/openjdk-8/bin/java;/usr/java/openjdk-17/bin/java;/usr/java/openjdk-21/bin/java hmc.invert.lwjgl.flag=true hmc.invert.pauls.flag=true hmc.store.accounts=true