Skip to content

Commit

Permalink
Merge pull request #159 from 3arthqu4ke/1.10.3
Browse files Browse the repository at this point in the history
Install Java 21 on docker image
  • Loading branch information
3arthqu4ke authored Jul 18, 2024
2 parents 775c4e1 + 638ec90 commit 140111c
Show file tree
Hide file tree
Showing 5 changed files with 75 additions and 65 deletions.
3 changes: 3 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
127 changes: 64 additions & 63 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,57 +1,87 @@
# HeadlessMc
<h1 align="center" style="font-weight: normal;"><b>HeadlessMc</b></h1>
<p align="center">A command line launcher for Minecraft Java Edition.</p>
<p align="center"><a href="https://github.com/3arthqu4ke/mc-runtime-test">Mc-Runtime-Test</a> | HMC | <a href="https://github.com/3arthqu4ke/hmc-specifics">HMC-Specifics</a> | <a href="https://github.com/3arthqu4ke/hmc-optimizations">HMC-Optimizations</a></p>

<div align="center">

[![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)
![GitHub](https://img.shields.io/github/license/3arthqu4ke/HeadlessMc)
[![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)

</div>

> [!WARNING]
> NOT AN OFFICIAL MINECRAFT PRODUCT. NOT APPROVED BY OR ASSOCIATED WITH MOJANG OR MICROSOFT.
>
> HeadlessMc will not allow you to play without having bought Minecraft!
> 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 &geq; 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-<version>/bin/java;C:/Program Files/Java/jdk-<version>/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.| \<command/id\> \<arg\> -id |
| quit | Exits HeadlessMc. | |
| versions | Lists all Minecraft versions currently installed. | -release -snapshot -other |
| download | Lists available Minecraft versions and downloads them. | \<version\> -id -release -snapshot -other -refresh |
| login | Logs into a Microsoft account. | \<email\>, will open a context for entering the password. |
| launch | Launches Minecraft. | \<version/id\> -commands -lwjgl -paulscode -lookup -jndi -noout -keep -exit |
| forge | Installs Minecraft Forge. | \<version/id\> \<--uid\> |
| fabric | Installs Fabric. | \<version/id\> |

To launch the game in headless mode type use the launch command with the `-lwjgl` flag:
`launch <version> -lwjgl`
1. Download the `headlessmc-launcher.jar` from the releases tab and install a Java version &geq; 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-<version>/bin/java;C:/Program Files/Java/jdk-<version>/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 <email>` 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 <version>`.
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 "<message>"`,
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
Expand All @@ -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.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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"));
}
Expand Down
2 changes: 1 addition & 1 deletion headlessmc-scripts/HeadlessMC/config.properties
Original file line number Diff line number Diff line change
@@ -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
Expand Down

0 comments on commit 140111c

Please sign in to comment.