# AGENTS.md Deobfuscated source of the *Zen* Minecraft client. Target: **MC 1.20.1 + Forge 47.4.20, Java 17**. Background (Chinese): `README.md`. ## What this is — critical - **NOT a Forge mod.** Never test by dropping the jar in `.minecraft/mods/`. It ships as: 1. a **Java agent jar** (`-javaagent:` JVM arg), or 2. a **Windows injector EXE** (`OpenZenLoader.exe`) that maps a DLL into a running `javaw.exe`. - Entrypoints: - Agent: `asm.patchify.loader.PatchAgent` (`premain`; manifest Premain/Agent-Class) applies ASM patches registered in `PatchRegistry`. - Mod-side: `shit.zen.ZenClient` — `@Mod("hey")`; mod id is `hey`, jar is `build/libs/hey-1.0.jar`. - DLL path: `shit.zen.dll.DllBootstrap` / `GameLoaderBridge`, loaded by C++ under `native/`. - Layout: `asm.patchify.*` = agent bootstrap + patch annotations/transformer machinery; `shit.zen.**` = the client (modules/gui/commands/events/etc.); `native/` = CMake C++ (`native/dll` + `native/loader`); `mapping/zen.mapping` = mapping of the ORIGINAL obfuscated Zen jar. - Where code goes: vanilla-MC behavior changes live in `shit.zen.patch` (`*Patch.java` using `@Patch`/`@Inject`/`@Overwrite`/`@WrapInvoke` from `asm.patchify.annotation`, applied to mojmap names); client features go in `shit.zen.modules`/`gui`/`command` etc. ## Build-time class-name obfuscation - Every build renames all `shit.zen.*` / `asm.patchify.*` classes to random 16-char names in one random package (auto-runs after `reobfJar`; see `ext.obfuscateJar` in `build.gradle`). - **Class names only** — method/field names are intentionally preserved (JNI lookups, reflection, GSON `@SerializedName`). Don't "fix" this. - Never hardcode OpenZen class names across a build boundary. The manifest Premain-Class, `Class.forName` string literals, and the native side (`native/dll/src/generated_names.h`) are rewritten/propagated by the build automatically — route new bootstrap references through that mechanism. - `build/rename-mapping.txt` is the ONLY way to de-obfuscate runtime stack traces and differs every build. Not to be confused with `mapping/zen.mapping` (original Zen). - `native/dll/src/generated_names.h` is auto-generated and gitignored — never edit or commit it. - Because class names are random, logging relies on fixed message strings (`bootstrap.start`, `bridge.load`, `agent attached`), not logger/class names. Native log: `%TEMP%\openzen--.log` — one file per injection attempt (a shared `openzen.log` was broken: the first injected process held it open forever, so every later injection's `log::init` hit ERROR_SHARING_VIOLATION and logged nothing). ## Commands - JDK 17 required; `JAVA_HOME` must point at it. Run Gradle itself on JDK 17 — the buildscript's ASM 9.6 cannot read class files of newer JDKs (Java 21+). - `.\gradlew.bat jar` — agent jar at `build/libs/hey-1.0.jar` (reobf + class renaming run automatically). - `.\gradlew.bat runClient0` — builds the jar and launches a dev MC client with `-javaagent` wired up. This is the supported way to test in-dev. DevAuth is a `runtimeOnly` dep (Microsoft login in dev); working dir is `run/`. - `.\gradlew.bat dll` — `build/dist/OpenZenLoader.exe`. Requires MSVC (VS 2019/2022, C++ workload), CMake (auto-found via PATH/vswhere/standard paths), and `JAVA_HOME` = JDK 17 (jni.h/jvmti.h). Windows-only. `upxCompress` is optional; it skips with a warning if UPX is absent. - `.\gradlew.bat clean` also wipes `native/build/` and `native/zen.jar` (`cleanNative`). - `gradle.properties` sets `org.gradle.daemon=false` and a 3G heap (MC decompilation). First build downloads Forge mappings — expect minutes. - **No test suite, linter, or formatter exists.** Verification = `gradlew jar` compiling; behavior via `gradlew runClient0`. ## CI (`.github/workflows/build-loader.yml`) - Push to `master`, path-filtered (src/native/gradle files; docs-only changes skip). windows-2022 runner runs `clean dll upxCompress`. - Commit-message markers: `[Release]` (case-insensitive) cuts a GitHub Release `build-` with exe + jar + mapping; `[SKIP CI]` skips the run. - CI passes the resolved sha as `OPENZEN_BUILD_REVISION`. ## Local run helper - `launch-mc-agent.ps1` launches MC 1.20.1 Forge with the agent via `-javaagent` (offline auth). Paths inside are machine-specific hardcodes — edit before use elsewhere.