Java runtime
The java plugin, from @opys/minecraft.
A Java runtime for every player.
java({ version: '21' });Nothing is installed on your machine. The plugin adds a JRE to the pack, and each player downloads the one for their computer.
Why not use the player's Java: most players have none, or the wrong one. A pack that brings its own always starts.
Options
| Option | What it does |
|---|---|
version | A major ('21', the newest release of it) or an exact build. |
vendor | 'temurin' (default), 'zulu' or 'graalvm'. |
jdk | true ships the whole JDK in place of the JRE. |
platforms | Which platforms get one. All six by default. |
apiBase | A mirror of the vendor's API. |
token | A GitHub token, for GraalVM's rate limit. |
Why a JRE and not a JDK: a game needs no compiler, and the JDK is four times the download. Say jdk: true for a pack that does need one. GraalVM is published as a JDK only, so vendor: 'graalvm' has to say it too.
An exact build is written the vendor's way: '21.0.12.1+1' or '8u312-b07' for Temurin, '21.0.12' for Zulu and GraalVM.
Which Java for which Minecraft
| Minecraft | Java |
|---|---|
| Up to 1.16.5 | 8 |
| 1.17 to 1.20.4 | 17 |
| 1.20.5 to 1.21.x | 21 |
| 26.x | 25 |
| Cleanroom, lwjgl3ify | 25 |
opys does not check the pairing. A wrong Java shows up as the game failing to start.
The machine's own Java
java({ system: true }) ships no JDK. The game runs on a Java that is already installed, and nothing is downloaded.
plugins: [minecraft({ version: '1.21.1' }), java({ system: true })],Feature custom_java | java_bin |
|---|---|
| off (default) | java, found on the PATH. |
| on | ${java_home}/bin/java, from the launcher's var. |
On Windows it is javaw, or java with the java_console feature, as for a shipped JDK.
To let a player pick their Java, describe the two in the config's options:
options: options().feature('custom_java', {
title: 'Use my own Java',
options: options().directory('java_home', { title: 'Java folder' }),
}),java_homeis the JDK's folder, the one that holdsbin. On macOS that is…/Contents/Home.- It adds one variable,
java_bin, and one launch piece,'@java.bin'. There is no'@java.home', since the pack does not know where a JDK is. JAVA_HOMEis set for the game only whencustom_javais on.- No other option goes with
system.java({ system: true, version: '21' })stops the build: opys cannot promise which Java a machine has.
Why a feature? A manifest cannot ask whether a variable was given. Its rules test the OS and the features, nothing else. So "the player named a Java" has to be a feature.
When to use it: a server you run yourself, or a pack for people who already manage their Java. For players, ship a JDK. It is the only way to know which Java the game gets.
What it adds
| Kind | What |
|---|---|
| Files | One JRE per platform. |
| Launch | bin, home. |
| Variables | java_runtime_dir, java_home, java_bin. |
| Environment | JAVA_HOME. |
Each one below: what it is, and how it ends up in the manifest.
Files · one JRE per platform
Six archives: Linux, macOS and Windows, each on x86_64 and ARM. The rules mean a player downloads exactly one. extract unpacks it.
// opys.config.mjs
export default defineConfig({
plugins: [
minecraft({ version: '1.21.1' }),
java({ version: '21' }),
],
manifest: {
command: '@java.bin',
args: ['@minecraft.jvmArgs', '@minecraft.mainClass', '@minecraft.gameArgs'],
workdir: '${game_directory}',
},
});// in the manifest
{
"path": "${java_runtime_dir}/OpenJDK21U-jre_x64_linux_hotspot_21.0.12.1_1.tar.gz",
"source": { "url": "https://github.com/adoptium/temurin21-binaries/releases/download/…_x64_linux_….tar.gz" },
"size": 52059408,
"rules": ["allow.os.linux", "allow.arch.x86_64"],
"integrity": { "sha256": "2413149700df0f7d440500a84a8f764c535f21e5a5e87d38328b64eec2c5b500" },
"extract": { "matches": "*", "into": "${java_runtime_dir}/jre-21", "strip": ["*/"] }
}Variables
Where the JDK is. The paths differ per OS, which is why they are variables with one value per platform.
// opys.config.mjs
export default defineConfig({
plugins: [
minecraft({ version: '1.21.1' }),
java({ version: '21' }),
],
manifest: {
command: '@java.bin',
args: ['@minecraft.jvmArgs', '@minecraft.mainClass', '@minecraft.gameArgs'],
workdir: '${game_directory}',
},
});// in the manifest
"vars": {
"java_runtime_dir": "${root}/runtimes",
"java_home": [
{ "value": "${java_runtime_dir}/jre-21", "rules": "allow.os.linux" },
{ "value": "${java_runtime_dir}/jre-21/Contents/Home", "rules": "allow.os.osx" },
{ "value": "${java_runtime_dir}/jre-21", "rules": "allow.os.windows" }
],
"java_bin": [
{ "value": "${java_home}/bin/java", "rules": "allow.os.linux" },
{ "value": "${java_home}/bin/java", "rules": "allow.os.osx" },
{ "value": "${java_home}/bin/javaw.exe", "rules": ["allow.os.windows", "disallow.features.java_console"] },
{ "value": "${java_home}/bin/java.exe", "rules": ["allow.os.windows", "allow.features.java_console"] }
]
}Override java_runtime_dir to keep JDKs somewhere else.
Launch
Two pieces. bin you rarely name, since a loader's command already resolves to it. home is for something that wants the folder the JDK is in and not its java.
| You write | Becomes |
|---|---|
'@java.bin' | ${java_bin}, the java executable. |
'@java.home' | ${java_home}, the folder the JDK is in. |
Why pieces, when ${java_bin} and ${java_home} exist: a piece is checked when you build. A misspelt variable is not.
Environment · JAVA_HOME
Set for the game process. Tools started along with the game find Java through it.
// opys.config.mjs
export default defineConfig({
plugins: [
minecraft({ version: '1.21.1' }),
java({ version: '21' }),
],
manifest: {
command: '@java.bin',
args: ['@minecraft.jvmArgs', '@minecraft.mainClass', '@minecraft.gameArgs'],
workdir: '${game_directory}',
},
});// in the manifest
"envs": { "JAVA_HOME": "${java_home}" }Features
| Feature | Effect |
|---|---|
java_console | On Windows, run java.exe instead of javaw.exe. |
custom_java | With system: true, run the Java in ${java_home}. |
Why: javaw.exe shows no console window, which is what players want. opys launch --feature java_console brings the game's output back when you are debugging.
Good to know
- A platform the vendor has no build for is left out. A player on it gets no Java.
- Check what Zulu gave you. Its API answers with its newest JDK when it cannot read a version. Look at the
[java]line the build prints. - No pack Java at all? Use
java({ system: true }). See The machine's own Java.