Build offline OpenPrestige release bundles

Rename the injector and package it with an embedded payload for Windows, Linux, and macOS x64/ARM64. Add a core-only ImGui native build, multi-platform CI and release packaging, and shared per-user storage with legacy config migration.
This commit is contained in:
bbldrizzy committed 2026-11-03 18:45:13 +00:00
1 parent 5152e6e0a6
commit 2d6b2a3cd1
37 files changed
+1284 -451

No files matched your search

+45 -90
View File
@@ -1,111 +1,66 @@
# Prestige injector (Rust)
# OpenPrestige offline injector
`PrestigeInjector` loads the native loader library (`prestige_native.dll` / `libprestige_native.so` / `libprestige_native.dylib`)
into a running Minecraft **1.21.11 Fabric** JVM (64-bit, Fabric Loader 0.19.x, Fabric API installed). It uses the same overall
method as the openvape bundle, written from scratch in Rust with no external crates.
## Supported platforms
| OS | Architectures | Injector binary | Loader library |
|---------|--------------------|-----------------------|-----------------------------|
| Windows | x86_64 | `PrestigeInjector.exe`| `prestige_native.dll` |
| Linux | x86_64 | `PrestigeInjector` | `libprestige_native.so` |
| macOS | x86_64, arm64 | `PrestigeInjector` | `libprestige_native.dylib` |
The injector and library must be built for the same architecture as the target JVM.
## How it works
1. **Injector** lists the running Minecraft JVMs, then loads the library into the chosen process.
- **Windows:** lists visible `java.exe`/`javaw.exe` windows (refreshed every 750 ms), then runs `LoadLibraryW` in the chosen
process through `CreateRemoteThread` and confirms the module is mapped.
- **Linux / macOS:** uses the HotSpot attach protocol (the same mechanism as `jcmd <pid> JVMTI.agent_load`). The injector
creates `.attach_pid<pid>` and sends `SIGQUIT` to the JVM, connects to its attach socket (`/tmp/.java_pid<pid>`, under
`$TMPDIR` on macOS) and asks it to load the library. The JVM `dlopen`s `libprestige_native` and calls its
`Agent_OnAttach` entry point. No ptrace, no root, no per-architecture shellcode.
Processes are found via `/proc` (Linux) or `ps` (macOS); there are no window titles, so the picker shows the pid and
instance name.
2. **The native library** only spawns a worker thread from its entry point (`DllMain` on Windows, `Agent_OnAttach` on
unix, which also hands over the `JavaVM*`). The worker:
- waits for the JVM (Windows: `jvm.dll`, `JNI_GetCreatedJavaVMs`), attaches, acquires the JVMTI redefine/retransform capabilities;
- writes the embedded payload jar (the remapped `prestige-*.jar`) to the temp directory under `PrestigeLoader`;
- looks for Fabric through the render thread's context class loader, then the system and other thread loaders;
- `FabricLauncherBase.getLauncher().addToClassPath(jar)` so payload and game classes share the launcher's game class loader;
- registers `NativeBridge.classBytes` / `NativeBridge.redefine` and calls `Bootstrap.start()`.
3. **`Bootstrap`** (Java) waits for the client window, then for every ClassTransform hook target gets the current class bytes
(JVMTI retransform capture), runs the hooks through `InPlaceTransformer` and redefines the class. The bundled ClassTransform
inlines hook handlers into the target methods, so normally nothing is added to the class and a plain redefine works. If a
transformer ever does add methods (a running JVM cannot), they are moved into generated `dev.zprestige.prestige.hooks.H*`
helper classes, call sites become `invokestatic`, and private member access goes through `Access` MethodHandles.
Finally the Prestige and ClickGUI entrypoints run on the client thread.
This repository contains the original CLI injector, native library with embedded payload and game
sources. The graphical launcher and runtime downloader are maintained in the separate Prestige
repository. There is no GUI or HTTP dependency in this injector and no edition build flag.
## Build
The payload jar is embedded with `include_bytes!`, so each target needs its own build. Both scripts below build for the host OS only and run
`gradlew remapJar`, `cargo build --release`, and copy the results to `dist/`.
Run `build-injector.ps1` on Windows or `build-injector.sh` on Linux/macOS. Both build the Fabric JAR,
then the native library and CLI, collecting the results in `dist/`. The native library always embeds
the exact remapped JAR. The loose JAR is provided for optional installation as a Fabric mod.
```powershell
.\build-injector.ps1 # Windows: dist\PrestigeInjector.exe + dist\prestige_native.dll
Run `build-release.bat` on Windows to build all platforms. `dist/release/` contains:
```text
openprestige-<version>-windows-x86_64.zip
openprestige-<version>-windows-aarch64.zip
openprestige-<version>-linux-x86_64.zip
openprestige-<version>-linux-aarch64.zip
openprestige-<version>-macos-universal.zip
prestige-<version>.jar
SHA256SUMS.txt
```
```sh
./build-injector.sh # Linux/macOS: dist/PrestigeInjector + dist/libprestige_native.{so,dylib}
```
To build release zips for every platform from Windows, run `build-release.bat`. It cross-compiles Linux (x86_64,
glibc 2.17+, so one build covers every mainstream distro) and macOS (universal x86_64 + arm64) with `cargo-zigbuild`, installing
zig and cargo-zigbuild on first run, and writes `dist\release\prestige-<ver>-{windows-x86_64,linux-x86_64,macos-universal}.zip`,
the bare mod jar and `SHA256SUMS.txt`.
Set `JAVA_HOME` beforehand to choose the JDK for Gradle (`build-injector.sh` honours it). The GitHub Actions workflow
`.github/workflows/injector.yml` builds and tests all four targets (Windows x86_64, Linux x86_64, macOS x86_64, macOS arm64)
and uploads them as artifacts.
Each ZIP contains `OpenPrestigeInjector` (or `.exe`), the native library, and a README.
The CI injector workflow builds only OpenPrestige. Build dependencies require internet access;
the resulting release bundle needs no runtime downloads.
## Use
Start a Fabric 1.21.11 instance, then run:
Extract the complete platform ZIP, start Minecraft, then run:
```sh
PrestigeInjector # interactive: pick the game from the list
PrestigeInjector <pid> [lib path] # inject into a specific pid, optionally with an explicit library path
OpenPrestigeInjector # Up/Down selects, Enter injects, Esc quits
OpenPrestigeInjector <pid> [lib path] # optional explicit library path
```
On Windows this is `PrestigeInjector.exe`. By default the library is looked up beside the injector.
Keep the native library beside the executable. The CLI uses that library and never looks in
Prestige's downloaded runtime cache. It has no update checks or `--download` command.
The library writes its embedded JAR locally so the JVM can load it. No external JAR is needed for
injection. Linux/macOS require a terminal, the same user as the game, and JVM attach enabled.
### Dawn and Lunar Client 1.21.11
## Platforms and requirements
Use a 1.21.11 Fabric profile in Dawn or enable Lunar Client's Fabric add-on for 1.21.11. The target
profile needs Fabric Loader 0.19.x and Fabric API. Wait for the title screen before selecting the game
in the injector. The default Prestige menu key is Right Shift, which may overlap with a launcher keybind.
Windows and Linux support x86_64 and ARM64. macOS supports Intel and Apple Silicon.
The injector, library and JVM architectures must match. ARM64 execution needs hardware testing.
The game code currently targets Minecraft 1.21.11 Fabric, Fabric Loader 0.19+ and Fabric API.
For Lunar, the native log should identify `GenesisClassLoader`. Check the game log for `hooks installed`
and `client initialised`. Hook counts refer to classes with changed bytecode. A skipped or failed hook
can leave its feature unavailable even if the menu opens.
Build tools require Rust, Python 3 and JDK 21. On Windows, the full release build also requires
MSVC build tools for x64 and ARM64. `build-release.bat` fetches pinned ImGui sources and builds
the small JNI libraries before building the remapped JAR. It installs Zig and cargo-zigbuild if
needed, then cross-compiles Linux x64/ARM64 and universal macOS.
An offline JVM replay accepted all 42 changed classes from Lunar's installed 1.21.11 cache after
recalculating stack and local limits on the cached classes. Live injection and Dawn's in-game profile
still need smoke testing.
Both repositories currently start from the same game sources and use the compatible `.openprestige`
configuration and log locations. They are independent repositories, without submodules, shared
working files or edition build flags. Game code fixes must be ported between repositories explicitly.
## Install as a mod instead
## User data
The payload jar is also a normal Fabric mod. Put `prestige-*.jar` (from `dist/` or the CI `payload-jar` artifact) in the
`mods/` folder of a Fabric Loader 0.19+ / Fabric API / Minecraft 1.21.11 instance; no injector is needed, on any OS.
Do not use both: if the mod is already loaded, the injector's bootstrap logs "already loaded as a Fabric mod" and skips.
| OS | Location |
| --- | --- |
| Windows | `%APPDATA%\.openprestige` |
| macOS | `~/Library/Application Support/.openprestige` |
| Linux | `$XDG_DATA_HOME/.openprestige` or `~/.local/share/.openprestige` |
## Requirements (Linux / macOS)
- Run the injector as the **same user** as the game.
- The attach mechanism must be enabled: the game must not be started with `-XX:+DisableAttachMechanism`.
- The JVM architecture must match the injector build. On Apple Silicon use an arm64 JVM, or use the x86_64 build for JVMs
running under Rosetta.
- Sandboxed launchers (Flatpak, Snap) hide the attach socket and are not supported.
## Known limits
- On Linux/macOS the library stays loaded after self-destruct: hooks are removed and natives unregistered, but the library is
not `dlclose`d (unmapping code the thread is still returning into would crash the JVM). On Windows the library is freed.
- Linux and macOS support is compile-checked in CI; test on a real host before relying on it.
## Log
`prestige-native.log` is written beside the loader library, plus `[Prestige-Inject]` lines in the game log.
Configs live in `configs/`, logs in `logs/`, and local runtime files in `runtime/`.