Skip to content

Java runtime ​

The java plugin, from @opys/minecraft.

A Java runtime for every player.

js
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 ​

OptionWhat it does
versionA major ('21', the newest release of it) or an exact build.
vendor'temurin' (default), 'zulu' or 'graalvm'.
jdktrue ships the whole JDK in place of the JRE.
platformsWhich platforms get one. All six by default.
apiBaseA mirror of the vendor's API.
tokenA 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 ​

MinecraftJava
Up to 1.16.58
1.17 to 1.20.417
1.20.5 to 1.21.x21
26.x25
Cleanroom, lwjgl3ify25

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.

js
plugins: [minecraft({ version: '1.21.1' }), java({ system: true })],
Feature custom_javajava_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:

js
options: options().feature('custom_java', {
  title: 'Use my own Java',
  options: options().directory('java_home', { title: 'Java folder' }),
}),
  • java_home is the JDK's folder, the one that holds bin. 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_HOME is set for the game only when custom_java is 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 ​

KindWhat
FilesOne JRE per platform.
Launchbin, home.
Variablesjava_runtime_dir, java_home, java_bin.
EnvironmentJAVA_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.

js
// 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}',
  },
});
jsonc
// 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.

js
// 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}',
  },
});
jsonc
// 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 writeBecomes
'@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.

js
// 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}',
  },
});
jsonc
// in the manifest
"envs": { "JAVA_HOME": "${java_home}" }

Features ​

FeatureEffect
java_consoleOn Windows, run java.exe instead of javaw.exe.
custom_javaWith 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.