4.3 KiB
4.3 KiB
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:- a Java agent jar (
-javaagent:JVM arg), or - a Windows injector EXE (
OpenZenLoader.exe) that maps a DLL into a runningjavaw.exe.
- a Java agent jar (
- Entrypoints:
- Agent:
asm.patchify.loader.PatchAgent(premain; manifest Premain/Agent-Class) applies ASM patches registered inPatchRegistry. - Mod-side:
shit.zen.ZenClient—@Mod("hey"); mod id ishey, jar isbuild/libs/hey-1.0.jar. - DLL path:
shit.zen.dll.DllBootstrap/GameLoaderBridge, loaded by C++ undernative/.
- Agent:
- 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.javausing@Patch/@Inject/@Overwrite/@WrapInvokefromasm.patchify.annotation, applied to mojmap names); client features go inshit.zen.modules/gui/commandetc.
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 afterreobfJar; seeext.obfuscateJarinbuild.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.forNamestring 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.txtis the ONLY way to de-obfuscate runtime stack traces and differs every build. Not to be confused withmapping/zen.mapping(original Zen).native/dll/src/generated_names.his 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-<pid>-<ticks>.log— one file per injection attempt (a sharedopenzen.logwas broken: the first injected process held it open forever, so every later injection'slog::inithit ERROR_SHARING_VIOLATION and logged nothing).
Commands
- JDK 17 required;
JAVA_HOMEmust 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 atbuild/libs/hey-1.0.jar(reobf + class renaming run automatically)..\gradlew.bat runClient0— builds the jar and launches a dev MC client with-javaagentwired up. This is the supported way to test in-dev. DevAuth is aruntimeOnlydep (Microsoft login in dev); working dir isrun/..\gradlew.bat dll—build/dist/OpenZenLoader.exe. Requires MSVC (VS 2019/2022, C++ workload), CMake (auto-found via PATH/vswhere/standard paths), andJAVA_HOME= JDK 17 (jni.h/jvmti.h). Windows-only.upxCompressis optional; it skips with a warning if UPX is absent..\gradlew.bat cleanalso wipesnative/build/andnative/zen.jar(cleanNative).gradle.propertiessetsorg.gradle.daemon=falseand a 3G heap (MC decompilation). First build downloads Forge mappings — expect minutes.- No test suite, linter, or formatter exists. Verification =
gradlew jarcompiling; behavior viagradlew runClient0.
CI (.github/workflows/build-loader.yml)
- Push to
master, path-filtered (src/native/gradle files; docs-only changes skip). windows-2022 runner runsclean dll upxCompress. - Commit-message markers:
[Release](case-insensitive) cuts a GitHub Releasebuild-<sha>with exe + jar + mapping;[SKIP CI]skips the run. - CI passes the resolved sha as
OPENZEN_BUILD_REVISION.
Local run helper
launch-mc-agent.ps1launches MC 1.20.1 Forge with the agent via-javaagent(offline auth). Paths inside are machine-specific hardcodes — edit before use elsewhere.