From b8e5df778e92a6d166041f4dcf44feea14152398 Mon Sep 17 00:00:00 2001 From: SashegDev Date: Sat, 17 Oct 2026 00:32:10 +0300 Subject: [PATCH] =?UTF-8?q?=D0=9C=D0=BE=D0=B4=D0=BB=D0=BE=D0=B0=D0=B4?= =?UTF-8?q?=D0=B5=D1=80=20RustexRemake:=20=D0=B0=D0=B3=D0=B5=D0=BD=D1=82,?= =?UTF-8?q?=20=D0=BF=D0=B0=D1=82=D1=87=20=D0=BB=D0=B0=D1=83=D0=BD=D1=87?= =?UTF-8?q?=D0=B5=D1=80=D0=B0,=20=D1=83=D1=81=D1=82=D0=B0=D0=BD=D0=BE?= =?UTF-8?q?=D0=B2=D1=89=D0=B8=D0=BA=20=D0=B8=20=D1=81=D0=B1=D0=BE=D1=80?= =?UTF-8?q?=D0=BA=D0=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Моды грузятся через -javaagent, game.jar не патчится, переживают ре-обфускацию. Что внутри: - агент rsx-bridge.jar: профиль сборки игры, патчи A2/A6, загрузка модов через родной загрузчик игры (ilxq -> special.Main) - патч лаунчера: окно выбора «С модами / Ванилла» по кнопке «Играть» и защита от автоапдейта лаунчера - install/uninstall: всё ставится в %LOCALAPPDATA%\rsx-mod, пути не хардкодятся - build: три готовых артефакта в dist, нужен только JDK - testserver: локальный сервер, принимает любой ник и токен Проверено на живом клиенте: мод грузится и выполняется в игровом потоке, в логе видно игрока и мир. --- .gitignore | 27 + LICENSE | 29 + README.md | 122 +++ bridge/build.gradle | 47 + bridge/settings.gradle | 1 + .../main/java/net/rustexremake/api/Rsx.java | 123 +++ .../java/net/rustexremake/api/RsxMod.java | 17 + bridge/src/main/java/rsx/Log.java | 62 ++ bridge/src/main/java/rsx/ModBridge.java | 250 ++++++ bridge/src/main/java/rsx/Profile.java | 110 +++ bridge/src/main/java/rsx/Resolver.java | 370 ++++++++ bridge/src/main/java/rsx/RsxAgent.java | 570 ++++++++++++ bridge/src/main/java/special/Main.java | 25 + bridge/src/test/fakeclient/FakeMain.java | 28 + bridge/src/test/fakeclient/ilxq.java | 79 ++ bridge/src/test/fakeclient/pvdafug.java | 31 + bridge/src/test/fakeclient/wwk.java | 26 + bridge/src/test/mod/ExampleMod.java | 34 + bridge/src/test/python/run_test.py | 186 ++++ build.cmd | 3 + install.cmd | 6 + launcher-patch/src/LauncherPatch.java | 843 ++++++++++++++++++ launcher-patch/src/ScanCalls.java | 150 ++++ launcher-patch/src/rsx/Choice.java | 418 +++++++++ launcher-patch/src/rsx/Patch.java | 84 ++ mod-template/build.gradle | 42 + mod-template/settings.gradle | 1 + .../src/main/java/example/ExampleMod.java | 39 + scripts/build.ps1 | 141 +++ scripts/install-hosts.ps1 | 28 + scripts/install.ps1 | 188 ++++ scripts/start-launcher.ps1 | 41 + scripts/uninstall-hosts.ps1 | 20 + start-launcher.cmd | 7 + testserver/selftest.py | 160 ++++ testserver/server.py | 416 +++++++++ third_party/asm/asm-9.7.jar | Bin 0 -> 125428 bytes third_party/asm/asm-commons-9.7.jar | Bin 0 -> 73426 bytes third_party/asm/asm-tree-9.7.jar | Bin 0 -> 51934 bytes uninstall.cmd | 6 + 40 files changed, 4730 insertions(+) create mode 100644 .gitignore create mode 100644 LICENSE create mode 100644 README.md create mode 100644 bridge/build.gradle create mode 100644 bridge/settings.gradle create mode 100644 bridge/src/main/java/net/rustexremake/api/Rsx.java create mode 100644 bridge/src/main/java/net/rustexremake/api/RsxMod.java create mode 100644 bridge/src/main/java/rsx/Log.java create mode 100644 bridge/src/main/java/rsx/ModBridge.java create mode 100644 bridge/src/main/java/rsx/Profile.java create mode 100644 bridge/src/main/java/rsx/Resolver.java create mode 100644 bridge/src/main/java/rsx/RsxAgent.java create mode 100644 bridge/src/main/java/special/Main.java create mode 100644 bridge/src/test/fakeclient/FakeMain.java create mode 100644 bridge/src/test/fakeclient/ilxq.java create mode 100644 bridge/src/test/fakeclient/pvdafug.java create mode 100644 bridge/src/test/fakeclient/wwk.java create mode 100644 bridge/src/test/mod/ExampleMod.java create mode 100644 bridge/src/test/python/run_test.py create mode 100644 build.cmd create mode 100644 install.cmd create mode 100644 launcher-patch/src/LauncherPatch.java create mode 100644 launcher-patch/src/ScanCalls.java create mode 100644 launcher-patch/src/rsx/Choice.java create mode 100644 launcher-patch/src/rsx/Patch.java create mode 100644 mod-template/build.gradle create mode 100644 mod-template/settings.gradle create mode 100644 mod-template/src/main/java/example/ExampleMod.java create mode 100644 scripts/build.ps1 create mode 100644 scripts/install-hosts.ps1 create mode 100644 scripts/install.ps1 create mode 100644 scripts/start-launcher.ps1 create mode 100644 scripts/uninstall-hosts.ps1 create mode 100644 start-launcher.cmd create mode 100644 testserver/selftest.py create mode 100644 testserver/server.py create mode 100644 third_party/asm/asm-9.7.jar create mode 100644 third_party/asm/asm-commons-9.7.jar create mode 100644 third_party/asm/asm-tree-9.7.jar create mode 100644 uninstall.cmd diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..aeb77f1 --- /dev/null +++ b/.gitignore @@ -0,0 +1,27 @@ +# Build output +build/ +dist/ +.gradle/ +*.class + +# IDE +.idea/ +*.iml +.vscode/ +.settings/ +.classpath +.project + +# OS +Thumbs.db +desktop.ini + +# Python +__pycache__/ +*.pyc + +# Nothing machine-specific belongs here: the profile is generated by +# prepare-build.cmd on the machine that has the game installed. +*.rsxp +hs_err_pid*.log +replay_pid*.log \ No newline at end of file diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..d9cb815 --- /dev/null +++ b/LICENSE @@ -0,0 +1,29 @@ +MIT License + +Copyright (c) 2026 rsx-modloader contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + +--- + +This project bundles ASM (third_party/asm), which is distributed under its own +BSD 3-Clause license: https://asm.ow2.io/license.html + +RustexRemake and the KJST Launcher are third-party products and are not part of +this project. This tool only attaches to the client on the user's own machine. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..8a8a4ba --- /dev/null +++ b/README.md @@ -0,0 +1,122 @@ +# rsx-modloader + +Модлоадер для RustexRemake: Java-моды в папке `mods`, подключаются через +`-javaagent`, `game.jar` не патчится. Один раз поставил — моды переживают +обновление игры. + +В лаунчере появляется выбор режима прямо на кнопке «Играть»: **с модами** или +**ванилла**. + +``` +mod-template\ пример мода, собирается один раз +bridge\ агент (-javaagent) и его исходники +launcher-patch\ патч лаунчера: окно выбора и защита от автоапдейта +testserver\ локальный сервер, принимает любой ник и токен +scripts\ сборка, установка, запуск, удаление +third_party\asm\ ASM (BSD-3), зашит внутрь rsx-launcher-patch.jar +``` + +## Установка + + build.cmd собрать dist\ (нужен только JDK) + install.cmd поставить модлоадер + start-launcher.cmd запускать лаунчер + uninstall.cmd вернуть всё как было + +`install.cmd` копирует рантайм в `%LOCALAPPDATA%\rsx-mod`, патчит `app.jar` +лаунчера и прописывает `-javaagent` в его конфиг. Пути можно переопределить: + + install.cmd --home D:\rsx-mod --game D:\RustexRemake + +**Лаунчер должен быть закрыт.** Если он запущен с правами администратора, +`app.jar` не перезаписать — установщик об этом скажет. + +Запускай лаунчер через `start-launcher.cmd`, а не ярлыком: `updater.exe` +сверяет хеш `app.jar` с манифестом и при патченом jar заново скачивает +официальный, стирая патч. + +## Как это работает + +* **Агент** (`rsx-bridge.jar`) подключается через `-javaagent` и в `premain` + читает профиль сборки игры (`profiles/latest.rsxp`): хеш jar, обфусцированные + имена нужных классов и полей. Ничего не хардкодится под конкретную сборку. +* **Патчи клиента** — A2 ставит `joml.fastmath` до загрузки JOML, A6 + подменяет таймер телеметрии на «глухой». Оба сделаны на живом клиенте: + первые версии A6 роняли игру с `NullPointerException` и + `Timer already cancelled`. +* **Моды** грузятся родным загрузчиком игры (`ilxq` → `special.Main`) — так же, + как моды с сервера, и выполняются в игровом потоке. +* **Переносимость модов.** Мод собирается один раз против стабильного API. + Мост сам переводит логические имена в имена текущей сборки, поэтому + ре-обфускация вендора не ломает уже собранные моды. + +## Патч лаунчера + +Лаунчер — сторонний продукт, и у него две особенности, которые мешают: + +* **Гонка за состоянием кнопки.** `xa.run()` вызывает `ha.y()` (ставит `PLAY`), + а `fa.loadedWeb()` позже ставит `ERROR`. Состояния — это индексы кнопок в + `web/launcher/main.html`, их шесть, поэтому `ERROR=6` скрывает все кнопки. + При медленной загрузке страницы `loadedWeb` затирает `PLAY` — кнопки просто + нет. Патч восстанавливает состояние после `loadedWeb`. +* **Автоапдейтер.** Патченый `app.jar` отличается от манифеста, и лаунчер + считает себя устаревшим в двух местах: `sb.q()` (размер и хеш файла) и + `ha` (хеш рабочего jar, отсюда «обновление найдено, перезапустите лаунчер»). + Оба закрыты через `rsx.Patch`, который действует только на файл с именем + `app.jar` и только при наличии маркера `.rsx-patched`. + +Возврат к обычному поведению: удалить `.rsx-patched` или запустить лаунчер с +`-Drsx.allowLauncherUpdate=true`. + +## Конфиг лаунчера — осторожно + +`launcher_config.properties` — это properties-файл: слэш экранирует следующий +символ, а `\r` читается как перевод строки. Значение `gamePath1=G:\rustexremake` +без экранирования превращается в `G:` + перевод строки + `ustexremake`, и +лаунчер перестаёт находить игру. Все правки идут через +`java.util.Properties` — в патчере есть команды `getprop` и `setprop`. + +## Тест-сервер + + testserver\start.cmd + +Локальный сервер: принимает любой ник и токен, отвечает на `/server-ping`, +слушает порты 25566–25573 и закидывает в пустой мир. Проверка без игры: + + python testserver\selftest.py + +Адрес сервера зашит в коде клиента, поэтому для полного захода в мир нужен +редирект (PowerShell **от администратора**): + + scripts\install-hosts.ps1 прописать 127.0.0.1 для адреса клиента + scripts\uninstall-hosts.ps1 откатить + +## Сборка + + build.cmd + +Нужен только JDK. ASM лежит в `third_party\asm` и зашивается внутрь +`rsx-launcher-patch.jar`, поэтому устанавливать модлоадер можно без Gradle и +без сети. + +Готовые файлы кладутся в `dist\`: + +| файл | что это | +|---|---| +| `rsx-bridge.jar` | агент, Java 8 | +| `rsx-api.jar` | API, против которого собирается мод | +| `rsx-launcher-patch.jar` | патчер лаунчера, всё внутри | +| `mod-template\` | заготовка мода | + +## Тесты + + python bridge\src\test\python\run_test.py + +Поднимает фейковый клиент, проверяет профиль, A2, A6, загрузку мода и то, что +мод выполняется в игровом потоке, а телеметрия не срабатывает. + +--- + +RustexRemake и KJST Launcher — сторонние продукты, они не входят в этот проект. +Инструмент работает только на машине пользователя. ASM распространяется по +лицензии BSD-3, см. `LICENSE`. \ No newline at end of file diff --git a/bridge/build.gradle b/bridge/build.gradle new file mode 100644 index 0000000..176cd5e --- /dev/null +++ b/bridge/build.gradle @@ -0,0 +1,47 @@ +// rsx-bridge: the mod loader that is attached to the client through -javaagent. +// +// Compiled for Java 8 because the client ships its own 8u51 runtime and nothing +// newer is available on that JVM. No external dependencies on purpose: the jar +// is loaded into a process we do not control, so every dependency is a risk. + +plugins { + id 'java' +} + +group = 'net.rustexremake' +version = '1.0.0' + +java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} + +tasks.withType(JavaCompile).configureEach { + options.encoding = 'UTF-8' + options.release = 8 +} + +jar { + archiveFileName = 'rsx-bridge.jar' + manifest { + attributes( + 'Premain-Class': 'rsx.RsxAgent', + 'Agent-Class': 'rsx.RsxAgent', + 'Can-Redefine-Classes': 'false', + 'Can-Retransform-Classes': 'false', + 'Implementation-Title': 'RustexRemake mod bridge', + 'Implementation-Version': project.version + ) + } +} + +// a copy of the profile for the build that is installed, so the installer only +// has to drop two files next to the jar +tasks.register('installLayout', Copy) { + from jar + from "${rootDir}/../rsx-map/profiles" { + include 'latest.rsxp' + rename { 'profile.rsxp' } + } + into "${rootDir}/build/install" +} \ No newline at end of file diff --git a/bridge/settings.gradle b/bridge/settings.gradle new file mode 100644 index 0000000..4a60c9d --- /dev/null +++ b/bridge/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'rsx-bridge' \ No newline at end of file diff --git a/bridge/src/main/java/net/rustexremake/api/Rsx.java b/bridge/src/main/java/net/rustexremake/api/Rsx.java new file mode 100644 index 0000000..ada92b7 --- /dev/null +++ b/bridge/src/main/java/net/rustexremake/api/Rsx.java @@ -0,0 +1,123 @@ +package net.rustexremake.api; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; + +import rsx.ModBridge; +import rsx.Resolver; + +/** + * Stable API for mods. + * + * Nothing in this class mentions an obfuscated name. A mod asks for + * "net.minecraft.client.Minecraft" and the bridge looks up what that class is + * called in the build that is currently installed, so a mod compiled once keeps + * working after the vendor renames everything again. + */ +public final class Rsx { + + private Rsx() { + } + + // ------------------------------------------------------------- identity + public static String buildId() { + return Resolver.profile() == null ? "unknown" + : Resolver.profile().buildId; + } + + public static String describe(String logical) { + return Resolver.profile() == null ? logical + : Resolver.profile().describe(logical); + } + + public static boolean ready() { + return Resolver.cls("net.minecraft.client.Minecraft") != null; + } + + // ------------------------------------------------------------- accessors + public static Object minecraft() { + return Resolver.get("net.minecraft.client.Minecraft", "instance"); + } + + public static Object player() { + return Resolver.get("net.minecraft.client.Minecraft", "player", minecraft()); + } + + public static Object world() { + return Resolver.get("net.minecraft.client.Minecraft", "world", minecraft()); + } + + public static Object currentScreen() { + return Resolver.get("net.minecraft.client.Minecraft", "currentScreen", minecraft()); + } + + public static Class classOf(String logical) { + return Resolver.cls(logical); + } + + public static Object get(String logicalClass, String member) { + return Resolver.get(logicalClass, member); + } + + public static Object get(String logicalClass, String member, Object instance) { + return Resolver.get(logicalClass, member, instance); + } + + public static void set(String logicalClass, String member, Object instance, + Object value) { + Resolver.set(logicalClass, member, instance, value); + } + + public static Object call(String logicalClass, String member, Object... args) { + return Resolver.call(logicalClass, member, args); + } + + public static Object call(String logicalClass, String member, Object instance, + Object... args) { + return Resolver.call(logicalClass, member, instance, args); + } + + /** + * Reflective escape hatch for members the profile does not carry yet. + * Mods should prefer the named accessors above. + */ + public static Field field(Class owner, String name) { + try { + Field f = owner.getDeclaredField(name); + f.setAccessible(true); + return f; + } catch (Throwable t) { + return null; + } + } + + public static Method method(Class owner, String name, Class... args) { + try { + Method m = owner.getDeclaredMethod(name, args); + m.setAccessible(true); + return m; + } catch (Throwable t) { + return null; + } + } + + // -------------------------------------------------------------- threading + /** Run a task on the game thread, on the next tick. */ + public static void onGameThread(Runnable task) { + ModBridge.post(task); + } + + /** Run a task repeatedly on the game thread. */ + public static void every(long millis, final Runnable task) { + ModBridge.schedule(millis, task); + } + + // ------------------------------------------------------------------ logs + public static void info(String msg) { + rsx.Log.info(msg); + } + + public static void warn(String msg) { + rsx.Log.warn(msg); + } +} \ No newline at end of file diff --git a/bridge/src/main/java/net/rustexremake/api/RsxMod.java b/bridge/src/main/java/net/rustexremake/api/RsxMod.java new file mode 100644 index 0000000..4ab58e8 --- /dev/null +++ b/bridge/src/main/java/net/rustexremake/api/RsxMod.java @@ -0,0 +1,17 @@ +package net.rustexremake.api; + +/** + * The whole contract a mod has to implement. + * + * onLoad runs once, on the thread that loads the mod jar. Anything scheduled + * through {@link Rsx#every} or {@link Rsx#onGameThread} runs later on the game's + * own thread, which is the only thread where touching game state is safe. + */ +public interface RsxMod { + + void onLoad(); + + /** optional */ + default void onUnload() { + } +} \ No newline at end of file diff --git a/bridge/src/main/java/rsx/Log.java b/bridge/src/main/java/rsx/Log.java new file mode 100644 index 0000000..f4fd9c5 --- /dev/null +++ b/bridge/src/main/java/rsx/Log.java @@ -0,0 +1,62 @@ +package rsx; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.PrintStream; +import java.text.SimpleDateFormat; +import java.util.Date; + +/** + * Bridge log. The game runs windowed with javaw.exe, so stdout is not visible to + * anybody: everything goes to a file next to the bridge, and that file is the + * primary way to verify a mod actually ran. + */ +public final class Log { + + private static PrintStream out; + private static final SimpleDateFormat FMT = + new SimpleDateFormat("HH:mm:ss.SSS"); + + public static synchronized void open(File file) { + try { + File dir = file.getParentFile(); + if (dir != null) { + dir.mkdirs(); + } + out = new PrintStream(new FileOutputStream(file, true), true, "UTF-8"); + info("--- rsx bridge log opened: " + file.getAbsolutePath()); + } catch (Throwable t) { + out = null; + System.err.println("[rsx] cannot open log: " + t); + } + } + + public static synchronized void info(String msg) { + write("INFO", msg); + } + + public static synchronized void warn(String msg) { + write("WARN", msg); + } + + public static synchronized void error(String msg, Throwable t) { + Throwable root = t; + while (root != null && root.getCause() != null && root.getCause() != root) { + root = root.getCause(); + } + write("ERROR", msg + (t == null ? "" : " :: " + root)); + if (t != null && out != null) { + java.io.StringWriter sw = new java.io.StringWriter(); + t.printStackTrace(new java.io.PrintWriter(sw)); + out.println(sw.toString()); + } + } + + private static void write(String level, String msg) { + String line = FMT.format(new Date()) + " [" + level + "] " + msg; + System.out.println("[rsx] " + line); + if (out != null) { + out.println(line); + } + } +} \ No newline at end of file diff --git a/bridge/src/main/java/rsx/ModBridge.java b/bridge/src/main/java/rsx/ModBridge.java new file mode 100644 index 0000000..122f5fa --- /dev/null +++ b/bridge/src/main/java/rsx/ModBridge.java @@ -0,0 +1,250 @@ +package rsx; + +import java.io.ByteArrayOutputStream; +import java.io.File; +import java.io.FileInputStream; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.zip.ZipEntry; +import java.util.zip.ZipFile; +import java.util.zip.ZipOutputStream; + +/** + * Loads mods through the client's own code loader. + * + * The client already ships a loader: it takes a jar, finds the entry class + * `special.Main`, calls its static main(String[]) and later invokes the static + * getRunnableList() from the game tick. That is the vendor's own supported way + * to run code, so reusing it means mods execute inside the game's class loader + * with full access - and nothing in the game jar has to change. + * + * A mod is a plain jar with a manifest entry + * Rsx-Mod-Entrypoint: com.example.MyMod + * whose class implements net.rustexremake.api.RsxMod. The bridge injects a + * generated `special.Main`, so mod authors never learn that contract: they just + * implement one interface. The entry point travels to the bridge through the + * argument array the loader passes through, so no manifest parsing is needed at + * runtime. + */ +public final class ModBridge { + + private static final Map NAMES = + new ConcurrentHashMap(); + private static final Map> QUEUE = + new ConcurrentHashMap>(); + private static final Map DRAIN = + new ConcurrentHashMap(); + private static final List LOADED = new ArrayList(); + + private static final java.util.concurrent.ScheduledExecutorService TIMER = + java.util.concurrent.Executors.newSingleThreadScheduledExecutor( + new java.util.concurrent.ThreadFactory() { + @Override + public Thread newThread(Runnable r) { + Thread t = new Thread(r, "rsx-mod-timer"); + t.setDaemon(true); + return t; + } + }); + + /** Invoked by the injected special.Main, during jar loading. */ + public static void launch(Class entry, String[] args) { + ClassLoader cl = entry.getClassLoader(); + String modName = args != null && args.length > 0 ? args[0] : "unknown"; + String entryName = args != null && args.length > 1 ? args[1] : null; + NAMES.put(cl, modName); + QUEUE.put(cl, new ArrayList()); + try { + if (entryName == null || entryName.isEmpty()) { + Log.warn("mod " + modName + ": no entry point"); + return; + } + Class api = cl.loadClass("net.rustexremake.api.RsxMod"); + Object impl = cl.loadClass(entryName).newInstance(); + if (!api.isInstance(impl)) { + Log.warn("mod " + modName + ": " + entryName + + " does not implement RsxMod"); + return; + } + api.getMethod("onLoad").invoke(impl); + LOADED.add(modName); + Log.info("mod loaded: " + modName + " (" + entryName + ")"); + } catch (Throwable t) { + Log.error("mod " + modName + " failed to start", t); + } + } + + /** Invoked by the injected special.Main, on the game thread. */ + public static List drain(Class entry) { + final ClassLoader cl = entry.getClassLoader(); + Runnable r = DRAIN.get(cl); + if (r == null) { + r = new Runnable() { + @Override + public void run() { + runPending(cl); + } + }; + DRAIN.put(cl, r); + } + List one = new ArrayList(1); + one.add(r); + return one; + } + + /** Queue a task to run on the game thread; callable from any thread. */ + public static void post(Runnable task) { + for (List q : QUEUE.values()) { + synchronized (q) { + // coalesce: a slow tick must not let a repeating task pile up + for (Runnable r : q) { + if (r == task) { + return; + } + } + q.add(task); + } + return; + } + } + + /** + * Repeating task on the game thread. A timer thread only ever *posts*, so + * the callback itself always runs where touching game state is legal. + */ + public static void schedule(long millis, final Runnable task) { + try { + TIMER.scheduleAtFixedRate(new Runnable() { + @Override + public void run() { + post(task); + } + }, millis, millis, java.util.concurrent.TimeUnit.MILLISECONDS); + } catch (Throwable t) { + Log.error("cannot schedule repeating task", t); + } + } + + public static List loaded() { + return LOADED; + } + + private static void runPending(ClassLoader cl) { + List q = QUEUE.get(cl); + if (q == null) { + return; + } + List copy; + synchronized (q) { + if (q.isEmpty()) { + return; + } + copy = new ArrayList(q); + q.clear(); + } + for (Runnable r : copy) { + try { + r.run(); + } catch (Throwable t) { + Log.error("mod task failed in " + NAMES.get(cl), t); + } + } + } + + /** + * Build the jar to hand to the client's loader: the mod jar plus a generated + * special/Main.class that forwards into this bridge. + */ + public static byte[] prepare(File mod, byte[] specialMain, + String entryPoint) throws Exception { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ZipOutputStream zos = new ZipOutputStream(bos); + ZipFile zf = new ZipFile(mod); + try { + java.util.Enumeration en = zf.entries(); + while (en.hasMoreElements()) { + ZipEntry e = en.nextElement(); + if (e.isDirectory()) { + continue; + } + String n = e.getName(); + if ("META-INF/MANIFEST.MF".equals(n) || "META-INF/INDEX.LIST".equals(n)) { + continue; + } + // our generated entry point always wins + if ("special/Main.class".equals(n)) { + continue; + } + zos.putNextEntry(new ZipEntry(n)); + InputStream in = zf.getInputStream(e); + copy(in, zos); + zos.closeEntry(); + } + } finally { + zf.close(); + } + zos.putNextEntry(new ZipEntry("META-INF/MANIFEST.MF")); + zos.write(("Manifest-Version: 1.0\r\n" + + "Rsx-Mod-Entrypoint: " + entryPoint + "\r\n\r\n") + .getBytes("UTF-8")); + zos.closeEntry(); + zos.putNextEntry(new ZipEntry("special/Main.class")); + zos.write(specialMain); + zos.closeEntry(); + zos.close(); + return bos.toByteArray(); + } + + /** Read the entry point a mod declares in its own manifest. */ + public static String entryPointOf(File mod) { + try { + ZipFile zf = new ZipFile(mod); + try { + ZipEntry me = zf.getEntry("META-INF/MANIFEST.MF"); + if (me == null) { + return null; + } + InputStream in = zf.getInputStream(me); + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + byte[] buf = new byte[4096]; + int n; + while ((n = in.read(buf)) > 0) { + bos.write(buf, 0, n); + } + in.close(); + // manifests are plain key/value lines; parsing them by hand + // avoids depending on java.util.jar, which is not reachable + // from every class loader the client may install + for (String line : new String(bos.toByteArray(), "UTF-8") + .split("\r?\n")) { + if (line.startsWith("Rsx-Mod-Entrypoint:")) { + return line.substring("Rsx-Mod-Entrypoint:".length()).trim(); + } + } + } finally { + zf.close(); + } + } catch (Throwable ignored) { + } + return null; + } + + private static void copy(InputStream in, java.io.OutputStream out) + throws Exception { + byte[] buf = new byte[8192]; + int n; + while ((n = in.read(buf)) > 0) { + out.write(buf, 0, n); + } + in.close(); + } + + public static byte[] readFile(File f) throws Exception { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + copy(new FileInputStream(f), bos); + return bos.toByteArray(); + } +} \ No newline at end of file diff --git a/bridge/src/main/java/rsx/Profile.java b/bridge/src/main/java/rsx/Profile.java new file mode 100644 index 0000000..30252f2 --- /dev/null +++ b/bridge/src/main/java/rsx/Profile.java @@ -0,0 +1,110 @@ +package rsx; + +/** + * Minimal reader for the compact .rsxp profile the pipeline generates. + * + * Format (tab or single-space separated, one record per line): + * rsxprofile 1 + * build + * loader + * patch.a2 + * patch.a6 + * class + * field + * method + */ +public final class Profile { + + public String buildId = ""; + public String gameJarSha256 = ""; + public long jarSize; + public long jarMtime; + public int namedClasses; + public int totalClasses; + + public String loaderClass; + public String loaderMethod; + public String loaderEntry; + + public String a2Class; + public String a2Property; + public String a6Class; +public String a6FieldName; + public String a6FieldObf; + public String serverOverrideField; + + /** logical name -> obfuscated class name */ + public final java.util.Map classes = + new java.util.HashMap(); + /** "class#member" -> [obfMember, descriptor, kind] */ + public final java.util.Map members = + new java.util.HashMap(); + + public static Profile load(String path) throws java.io.IOException { + Profile p = new Profile(); + java.io.BufferedReader r = new java.io.BufferedReader( + new java.io.InputStreamReader( + new java.io.FileInputStream(path), "UTF-8")); + try { + String line; + while ((line = r.readLine()) != null) { + line = line.trim(); + if (line.isEmpty() || line.startsWith("#")) { + continue; + } + String[] f = line.split("\\s+"); + String kind = f[0]; + if ("rsxprofile".equals(kind)) { + continue; + } else if ("build".equals(kind) && f.length >= 5) { + p.buildId = f[1]; + p.gameJarSha256 = f[2]; + p.namedClasses = Integer.parseInt(f[3]); + p.totalClasses = Integer.parseInt(f[4]); + if (f.length >= 7) { + // optional fast path: skip hashing a 56 MB jar on every + // launch when size and mtime already identify it + p.jarSize = Long.parseLong(f[5]); + p.jarMtime = Long.parseLong(f[6]); + } + } else if ("loader".equals(kind) && f.length >= 4) { + p.loaderClass = f[1]; + p.loaderMethod = f[2]; + p.loaderEntry = f[3]; + } else if ("patch.a2".equals(kind) && f.length >= 3) { + p.a2Class = f[1]; + p.a2Property = f[2]; + } else if ("patch.a6".equals(kind) && f.length >= 4) { + p.a6Class = f[1]; + p.a6FieldName = f[2]; + p.a6FieldObf = f[3]; + } else if ("class".equals(kind) && f.length >= 3) { + p.classes.put(f[1], f[2]); + } else if ("override.server".equals(kind) && f.length >= 2) { + p.serverOverrideField = f[1]; + } else if (("field".equals(kind) || "method".equals(kind)) + && f.length >= 5) { + p.members.put(f[1] + "#" + f[2], + new String[] {f[3], f[4], "field".equals(kind) ? "f" : "m"}); + } + } + } finally { + r.close(); + } + return p; + } + + public String obf(String logical) { + return classes.get(logical); + } + + public String[] member(String logical, String member) { + return members.get(logical + "#" + member); + } + + /** logical name -> readable name, for logging and mod diagnostics */ + public String describe(String logical) { + String o = classes.get(logical); + return logical + (o == null ? " (unmapped)" : " -> " + o); + } +} \ No newline at end of file diff --git a/bridge/src/main/java/rsx/Resolver.java b/bridge/src/main/java/rsx/Resolver.java new file mode 100644 index 0000000..a10b17e --- /dev/null +++ b/bridge/src/main/java/rsx/Resolver.java @@ -0,0 +1,370 @@ +package rsx; + +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +/** + * Turns stable logical names into the real, obfuscated members of whatever + * build is running. + * + * The vendor re-obfuscates every release, so nothing here may hard-code a name. + * The profile supplies the translation, and the class loader is discovered at + * runtime because the game may load its own classes either from the system + * class path or from a private loader it creates itself. + */ +public final class Resolver { + + private static Profile profile; + private static ClassLoader loader; + private static String loaderSource = "none"; + private static final Map> CLASSES = new HashMap>(); + private static final Map FIELDS = new HashMap(); + private static final Map METHODS = new HashMap(); + private static java.lang.instrument.Instrumentation inst; + private static Map> loaded; + private static long lastScan; + + public static void init(Profile p) { + profile = p; + } + + public static void setInstrumentation(java.lang.instrument.Instrumentation i) { + inst = i; + } + + /** + * Index of every class the VM has already loaded, by binary name. + * + * The client encrypts its classes, so they cannot simply be loaded from the + * system class path: the game builds its own loader and defines them + * through Unsafe, bypassing transformers. Instrumentation is the one view + * that sees those classes, so it is what we index - and it is exact, with + * no guessing about which loader the vendor installed. + */ + private static Map> loadedIndex(boolean force) { + long now = System.currentTimeMillis(); + if (loaded != null && !force && now - lastScan < 1000L) { + return loaded; + } + if (loaded != null && now - lastScan < 1000L) { + return loaded; + } + Map> next = new HashMap>(); + if (inst != null) { + try { + for (Class c : inst.getAllLoadedClasses()) { + if (c != null) { + next.put(c.getName(), c); + } + } + } catch (Throwable t) { + return loaded == null ? next : loaded; + } + } else { + return loaded == null ? next : loaded; + } + loaded = next; + lastScan = now; + return loaded; + } + + public static Class findLoaded(String binaryName) { + return loadedIndex(true).get(binaryName); + } + + /** every class currently in the VM, for instance hunting */ + public static Class[] allLoadedClasses() { + Map> idx = loadedIndex(true); + return idx.values().toArray(new Class[0]); + } + + public static Profile profile() { + return profile; + } + + public static String loaderSource() { + return loaderSource; + } + + /** + * Find a loader that can see the game's own classes. Candidates are tried in + * order and the first one that can resolve the Minecraft class wins. + */ + public static synchronized ClassLoader loader() { + if (loader != null) { + return loader; + } + if (profile == null) { + return null; + } + String mc = profile.obf("net.minecraft.client.Minecraft"); + if (mc == null) { + return null; + } + if (loader != null) { + return loader; + } + List candidates = new ArrayList(); + try { + ClassLoader t = Thread.currentThread().getContextClassLoader(); + if (t != null) { + candidates.add(t); + } + } catch (Throwable ignored) { + } + try { + candidates.add(ClassLoader.getSystemClassLoader()); + } catch (Throwable ignored) { + } + try { + // the game entry point lives in game.jar under its real name + Class entry = Class.forName("net.minecraft.client.main.RustexMain", + false, ClassLoader.getSystemClassLoader()); + if (entry != null) { + candidates.add(entry.getClassLoader()); + } + } catch (Throwable ignored) { + } + for (ClassLoader cl : candidates) { + try { + Class c = Class.forName(mc, false, cl); + if (c != null) { + loader = cl; + loaderSource = cl.getClass().getName() + "@" + + System.identityHashCode(cl); + Log.info("game class loader: " + loaderSource); + return loader; + } + } catch (Throwable ignored) { + } + } + return null; + } + + public static Class cls(String logical) { + Class c = CLASSES.get(logical); + if (c != null) { + return c; + } + if (profile == null) { + return null; + } + String obf = profile.obf(logical); + if (obf == null) { + return null; + } + // 1) the class is already in the VM (the game defines its own classes + // through Unsafe, so this is the only way that always works) + // the game loads its classes over time, so a miss must force a rescan; + // otherwise we would keep looking at the snapshot from before the game + // had even started and never notice the class arriving + Class known = loadedIndex(true).get(obf); + if (known != null) { + CLASSES.put(logical, known); + loader = known.getClassLoader(); + loaderSource = "instrumentation:" + describeLoader(loader); + return known; + } + // 2) not loaded yet: try the loaders we can see + ClassLoader cl = loader(); + if (cl == null) { + return null; + } + try { + c = Class.forName(obf, false, cl); + CLASSES.put(logical, c); + return c; + } catch (Throwable t) { + return null; + } + } + + private static String describeLoader(ClassLoader cl) { + if (cl == null) { + return "bootstrap"; + } + return cl.getClass().getName() + "@" + + System.identityHashCode(cl); + } + + private static Field field(String logical, String member, Class owner) { + String key = logical + "#" + member; + Field f = FIELDS.get(key); + if (f != null) { + return f; + } + String[] m = profile == null ? null : profile.member(logical, member); + if (m == null || owner == null) { + return null; + } + try { + f = owner.getDeclaredField(m[0]); + f.setAccessible(true); + } catch (Throwable t) { + Log.warn("field " + key + " -> " + m[0] + " not found on " + owner); + return null; + } + FIELDS.put(key, f); + return f; + } + + private static Method method(String logical, String member, Class owner) { + String key = logical + "#" + member; + Method cached = METHODS.get(key); + if (cached != null) { + return cached; + } + String[] m = profile == null ? null : profile.member(logical, member); + if (m == null || owner == null) { + return null; + } + try { + Method found = null; + for (Method cand : owner.getDeclaredMethods()) { + if (cand.getName().equals(m[0]) + && cand.getReturnType().getName() + .equals(typeOf(m[1]))) { + found = cand; + break; + } + } + if (found == null) { + for (Method cand : owner.getDeclaredMethods()) { + if (cand.getName().equals(m[0])) { + found = cand; + break; + } + } + } + if (found == null) { + return null; + } + found.setAccessible(true); + METHODS.put(key, found); + return found; + } catch (Throwable t) { + Log.warn("method " + key + " -> " + m[0] + " not found: " + t); + return null; + } + } + + private static String typeOf(String descriptor) { + String d = descriptor; + if (d.startsWith("(")) { + int i = d.lastIndexOf(')'); + d = i >= 0 ? d.substring(i + 1) : d; + } + while (d.startsWith("[")) { + d = d.substring(1); + } + if (d.startsWith("L") && d.endsWith(";")) { + return d.substring(1, d.length() - 1).replace('/', '.'); + } + switch (d) { + case "V": return "void"; + case "Z": return "boolean"; + case "B": return "byte"; + case "C": return "char"; + case "S": return "short"; + case "I": return "int"; + case "J": return "long"; + case "F": return "float"; + case "D": return "double"; + default: return d; + } + } + + // ------------------------------------------------------------- public API + public static Object get(String logical, String member) { + Class owner = cls(logical); + Field f = field(logical, member, owner); + if (f == null) { + return null; + } + try { + return f.get(null); + } catch (Throwable t) { + Log.warn("static read " + logical + "#" + member + " failed: " + t); + return null; + } + } + + public static Object get(String logical, String member, Object instance) { + Class owner = cls(logical); + Field f = field(logical, member, owner); + if (f == null) { + return null; + } + try { + return f.get(instance); + } catch (Throwable t) { + Log.warn("read " + logical + "#" + member + " failed: " + t); + return null; + } + } + + public static void set(String logical, String member, Object instance, + Object value) { + Class owner = cls(logical); + Field f = field(logical, member, owner); + if (f == null) { + return; + } + try { + f.set(instance, value); + } catch (Throwable t) { + Log.warn("write " + logical + "#" + member + " failed: " + t); + } + } + + /** Write a field addressed by its obfuscated name. */ + public static boolean setRaw(String logicalClass, String obfName, + Object instance, Object value) { + Class owner = cls(logicalClass); + if (owner == null) { + return false; + } + try { + Field f = owner.getDeclaredField(obfName); + f.setAccessible(true); + f.set(instance, value); + return true; + } catch (Throwable t) { + Log.warn("write " + logicalClass + "#" + obfName + " failed: " + t); + return false; + } + } + + public static Object call(String logical, String member, Object... args) { + Class owner = cls(logical); + Method mm = method(logical, member, owner); + if (mm == null) { + return null; + } + try { + return mm.invoke(null, args); + } catch (Throwable t) { + Log.warn("call " + logical + "#" + member + " failed: " + t); + return null; + } + } + + public static Object call(String logical, String member, Object instance, + Object... args) { + Class owner = cls(logical); + Method mm = method(logical, member, owner); + if (mm == null) { + return null; + } + try { + return mm.invoke(instance, args); + } catch (Throwable t) { + Log.warn("call " + logical + "#" + member + " failed: " + t); + return null; + } + } +} \ No newline at end of file diff --git a/bridge/src/main/java/rsx/RsxAgent.java b/bridge/src/main/java/rsx/RsxAgent.java new file mode 100644 index 0000000..9433c1e --- /dev/null +++ b/bridge/src/main/java/rsx/RsxAgent.java @@ -0,0 +1,570 @@ +package rsx; + +import java.io.File; +import java.io.InputStream; +import java.security.MessageDigest; +import java.util.ArrayList; +import java.util.List; +import java.util.zip.ZipFile; + +/** + * The agent. It is attached through the launcher setting `env`, so the vendor's + * jar and launcher stay untouched: no repack, no manifest hash breaks, and an + * update from the vendor cannot remove us. + * + * Jobs, in order: + * 1. read the profile for the build that is installed and verify it by hash + * 2. apply patch A2 (the client silently exits without -Djoml.fastmath) + * 3. wait for the game to come up, then apply patch A6 (Snooper telemetry) + * 4. load every jar from mods/ through the client's own code loader + */ +public final class RsxAgent { + + private static Profile profile; + private static File home; + private static byte[] specialMain; + + public static void premain(String args, java.lang.instrument.Instrumentation inst) { + try { + home = new File(RsxAgent.class.getProtectionDomain() + .getCodeSource().getLocation().toURI()).getParentFile(); + } catch (Throwable t) { + home = new File("."); + } + + File target = null; + try { + String dir = System.getProperty("minecraft.applet.TargetDirectory"); + if (dir != null) { + target = new File(dir); + } + } catch (Throwable ignored) { + } + File logFile = new File(target != null ? target : home, + target != null ? "rsx/bridge.log" : "rsx-bridge.log"); + Log.open(logFile); + + Resolver.setInstrumentation(inst); + Log.info("rsx bridge starting (home=" + home + ")"); + + String mode = readMode(); + if ("vanilla".equals(mode)) { + Log.info("mode is vanilla: no mods, no patches, agent does nothing"); + return; + } + if (mode != null) { + Log.info("mode: " + mode); + } + + File prof = pick(new File(home, "profiles/latest.rsxp"), + new File(home, "profile.rsxp")); + if (prof == null) { + fail("no profile found: expected profiles/latest.rsxp next to the " + + "bridge jar, run prepare-build.cmd first"); + return; + } + try { + profile = Profile.load(prof.getAbsolutePath()); + Resolver.init(profile); + } catch (Throwable t) { + fail("cannot read profile " + prof + ": " + t); + return; + } + Log.info("profile " + profile.buildId + " from " + prof.getName() + + " (named " + profile.namedClasses + "/" + profile.totalClasses + ")"); + Log.info("loader anchor: " + profile.describe( + "net.rustexremake.loader.RemoteClassLoader")); + + File game = findGameJar(); + if (game == null) { + fail("cannot locate the client jar on java.class.path"); + return; + } + String sha; + boolean fastPath = profile.jarSize > 0 + && game.length() == profile.jarSize + && game.lastModified() / 1000L == profile.jarMtime; + if (fastPath) { + Log.info("build signature matches (size+mtime), skipping hash"); + sha = profile.gameJarSha256; + } else { + try { + sha = sha256(game); + } catch (Throwable t) { + fail("cannot hash " + game + ": " + t); + return; + } + } + if (!sha.equals(profile.gameJarSha256)) { + fail("profile is for build " + profile.buildId + " but the installed " + + "jar hashes to " + sha.substring(0, 16) + + "; run prepare-build.cmd again"); + return; + } + Log.info("build verified: " + game.getName() + " sha256 ok"); + + applyA2(); + + try { + specialMain = readResource("special/Main.class"); + } catch (Throwable t) { + fail("cannot read the generated special.Main: " + t); + return; + } + + Thread boot = new Thread(new Runnable() { + @Override + public void run() { + bootSequence(); + } + }, "rsx-boot"); + boot.setDaemon(true); + boot.start(); + } + + // ------------------------------------------------------------------- boot + private static void bootSequence() { + // the game creates its own loader, so wait until the client is really up + Object mc = null; + for (int i = 0; i < 600; i++) { + try { + mc = Resolver.get("net.minecraft.client.Minecraft", "instance"); + if (mc != null) { + break; + } + } catch (Throwable ignored) { + } + sleep(500); + mc = null; + } + if (mc == null) { + Log.warn("the game did not come up within 5 minutes; mods not loaded"); + return; + } + Log.info("client is up, loader: " + Resolver.loaderSource()); + + applyServerOverride(); + applyA6(mc); + // the telemetry object is created later in the client's own start-up, + // so the patch is retried for a while instead of being given up on + Thread snooper = new Thread(new Runnable() { + @Override + public void run() { + for (int i = 0; i < 24; i++) { + sleep(5000); + Object c = Resolver.get("net.minecraft.client.Minecraft", + "instance"); + if (c == null) { + continue; + } + if (applyA6(c)) { + return; + } + } + Log.warn("A6: telemetry object never appeared within 2 minutes"); + } + }, "rsx-snooper-patch"); + snooper.setDaemon(true); + snooper.start(); + + loadMods(mc); + + Log.info("ready: " + ModBridge.loaded().size() + " mod(s) loaded"); + } + + // --------------------------------------------------------------- patches + private static void applyA2() { + String prop = profile.a2Property; + if (prop == null || prop.isEmpty()) { + Log.warn("A2: no property in the profile"); + return; + } + // the client reads this flag in a static initialiser and exits silently + // when it is absent; setting it before that class loads is enough + System.setProperty(prop, "true"); + Log.info("A2 applied: -D" + prop + "=true (class " + profile.a2Class + ")"); + } + + private static final java.util.Set patched = + java.util.Collections.newSetFromMap( + new java.util.WeakHashMap()); + + /** + * Read the mode switch that play.cmd writes next to the bridge jar. + * + * "vanilla" keeps the agent attached but does nothing at all, which makes it + * easy to switch between modded and clean runs without editing the launcher. + */ + private static String readMode() { + File f = new File(home, "mode.txt"); + if (!f.isFile()) { + return null; + } + java.io.BufferedReader r = null; + try { + r = new java.io.BufferedReader(new java.io.InputStreamReader( + new java.io.FileInputStream(f), "UTF-8")); + String line = r.readLine(); + return line == null ? null : line.trim().toLowerCase(); + } catch (Throwable t) { + return null; + } finally { + if (r != null) { + try { + r.close(); + } catch (Throwable ignored) { + } + } + } + } + + /** + * Repoint the client's server list. + * + * The vendor main accepts a --srvs option and then overwrites it with a + * hardcoded list of production addresses, so the only way to run against + * another server (a local one, a friend, a LAN) is to set the field + * ourselves before the client connects. + */ + private static void applyServerOverride() { + String servers = System.getProperty("rsx.server"); + if (servers == null || servers.isEmpty()) { + return; + } + String field = profile.serverOverrideField; + if (field == null) { + Log.warn("rsx.server set but the profile has no override.server"); + return; + } + if (Resolver.setRaw("net.minecraft.client.Minecraft", field, null, + servers)) { + Log.info("server list overridden: " + servers); + } else { + Log.warn("could not override the server list with: " + servers); + } + } + + private static boolean applyA6(Object mc) { + Class sc = resolveClass(profile.a6Class); + if (sc == null) { + Log.warn("A6: snooper class not resolvable"); + return false; + } + // The profile's field hint turned out to be unreliable: the declared + // field stays null in practice, and the object may live in a static + // somewhere else entirely. So look for live instances instead of + // trusting one name. + java.util.List live = findInstances(mc, sc); + if (live.isEmpty()) { + return false; + } + int stopped = 0; + for (Object o : live) { + if (patched.contains(o)) { + continue; + } + if (killTimers(o)) { + stopped++; + patched.add(o); + } + } + if (stopped > 0) { + Log.info("A6 applied: telemetry timers replaced in " + + stopped + " object(s), " + live.size() + " found"); + } + return true; + } + + private static Class resolveClass(String obf) { + if (obf == null) { + return null; + } + try { + Class known = Resolver.findLoaded(obf); + if (known != null) { + return known; + } + ClassLoader cl = Resolver.loader(); + return cl == null ? null : Class.forName(obf, false, cl); + } catch (Throwable t) { + return null; + } + } + + /** Live instances of a class, in the client instance and in static fields. */ + private static java.util.List findInstances(Object mc, Class type) { + java.util.List found = new java.util.ArrayList(); + try { + for (java.lang.reflect.Field f : mc.getClass().getDeclaredFields()) { + f.setAccessible(true); + Object v = f.get(mc); + if (v != null && type.isInstance(v)) { + found.add(v); + } + } + } catch (Throwable ignored) { + } + try { + Class[] all = Resolver.allLoadedClasses(); + for (Class c : all) { + java.lang.reflect.Field[] fs; + try { + fs = c.getDeclaredFields(); + } catch (Throwable ignored) { + continue; + } + for (java.lang.reflect.Field f : fs) { + if (!java.lang.reflect.Modifier.isStatic(f.getModifiers())) { + continue; + } + if (!type.isAssignableFrom(f.getType())) { + continue; + } + try { + f.setAccessible(true); + Object v = f.get(null); + if (v != null && !found.contains(v)) { + found.add(v); + } + } catch (Throwable ignored) { + } + } + } + } catch (Throwable ignored) { + } + return found; + } + + /** + * Stops the telemetry object's timers without breaking the client. + * + * Two earlier attempts were caught by the real client: + * - nulling the field crashed it with a NullPointerException, because the + * telemetry code dereferences it; + * - cancelling the Timer crashed it with "Timer already cancelled", + * because the client reschedules that Timer later during startup. + * + * So the Timer is kept valid but replaced by one that accepts every + * reschedule and silently drops the work, and the tasks already queued in + * the old Timer are cancelled individually. + */ + private static boolean killTimers(Object o) { + boolean stopped = false; + for (java.lang.reflect.Field f : o.getClass().getDeclaredFields()) { + Object v; + try { + f.setAccessible(true); + v = f.get(o); + } catch (Throwable ignored) { + continue; + } + if (v instanceof java.util.Timer) { + java.util.Timer old = (java.util.Timer) v; + try { + // Swap first: the field must never be null, and the client + // reschedules through whatever object is in there. + f.set(o, new SilentTimer()); + // Only now is the old timer unreachable, so cancelling it is + // safe and drops whatever it had already queued. + old.cancel(); + stopped = true; + } catch (Throwable t) { + Log.warn("A6: could not swap the telemetry timer: " + t); + } + } else if (v instanceof java.util.TimerTask) { + ((java.util.TimerTask) v).cancel(); + stopped = true; + } else if (v instanceof java.util.concurrent.ScheduledExecutorService) { + ((java.util.concurrent.ScheduledExecutorService) v).shutdownNow(); + stopped = true; + } + } + return stopped; + } + + /** A Timer that swallows every schedule request instead of running it. */ + private static final class SilentTimer extends java.util.Timer { + SilentTimer() { + super(true); + } + + private static void drop(java.util.TimerTask task) { + if (task != null) { + task.cancel(); + } + } + + @Override + public void schedule(java.util.TimerTask task, long delay) { + drop(task); + } + + @Override + public void schedule(java.util.TimerTask task, java.util.Date when) { + drop(task); + } + + @Override + public void schedule(java.util.TimerTask task, long delay, long period) { + drop(task); + } + + @Override + public void schedule(java.util.TimerTask task, java.util.Date first, + long period) { + drop(task); + } + + @Override + public void scheduleAtFixedRate(java.util.TimerTask task, long delay, + long period) { + drop(task); + } + + @Override + public void scheduleAtFixedRate(java.util.TimerTask task, + java.util.Date first, long period) { + drop(task); + } + } + + // ------------------------------------------------------------------ mods + private static void loadMods(Object mc) { + File modsDir = null; + try { + String dir = System.getProperty("minecraft.applet.TargetDirectory"); + if (dir != null) { + modsDir = new File(dir, "mods"); + } + } catch (Throwable ignored) { + } + if (modsDir == null) { + modsDir = new File(home, "mods"); + } + if (!modsDir.isDirectory()) { + Log.info("no mods directory at " + modsDir); + return; + } + File[] files = modsDir.listFiles(); + if (files == null || files.length == 0) { + Log.info("mods directory is empty: " + modsDir); + return; + } + List jars = new ArrayList(); + for (File f : files) { + if (f.isFile() && f.getName().toLowerCase().endsWith(".jar")) { + jars.add(f); + } + } + Log.info("found " + jars.size() + " mod jar(s) in " + modsDir); + + Class loaderCls; + java.lang.reflect.Method load; + try { + loaderCls = Class.forName(profile.loaderClass, false, Resolver.loader()); + load = loaderCls.getDeclaredMethod(profile.loaderMethod, + byte[].class, String[].class); + load.setAccessible(true); + } catch (Throwable t) { + fail("cannot bind the client loader (" + profile.loaderClass + "." + + profile.loaderMethod + "): " + t); + return; + } + + for (File jar : jars) { + String name = jar.getName(); + try { + String entry = ModBridge.entryPointOf(jar); + if (entry == null) { + Log.warn(name + ": no Rsx-Mod-Entrypoint in the manifest, skipped"); + continue; + } + byte[] bytes = ModBridge.prepare(jar, specialMain, entry); + load.invoke(null, bytes, new String[] {name, entry}); + } catch (Throwable t) { + Log.error("mod " + name + " failed to load", t); + } + } + } + + // ----------------------------------------------------------------- utils + private static File findGameJar() { + String loader = profile.loaderClass; + if (loader == null) { + return null; + } + String cp = System.getProperty("java.class.path", ""); + for (String part : cp.split(File.pathSeparator)) { + if (!part.toLowerCase().endsWith(".jar")) { + continue; + } + try { + ZipFile z = new ZipFile(part); + try { + if (z.getEntry(loader + ".class") != null) { + return new File(part); + } + } finally { + z.close(); + } + } catch (Throwable ignored) { + } + } + return null; + } + + private static String sha256(File f) throws Exception { + MessageDigest md = MessageDigest.getInstance("SHA-256"); + java.io.FileInputStream in = new java.io.FileInputStream(f); + try { + byte[] buf = new byte[1 << 20]; + int n; + while ((n = in.read(buf)) > 0) { + md.update(buf, 0, n); + } + } finally { + in.close(); + } + StringBuilder sb = new StringBuilder(); + for (byte b : md.digest()) { + sb.append(String.format("%02x", b)); + } + return sb.toString(); + } + + private static byte[] readResource(String name) throws Exception { + InputStream in = RsxAgent.class.getClassLoader().getResourceAsStream(name); + if (in == null) { + throw new IllegalStateException("resource not found: " + name); + } + java.io.ByteArrayOutputStream bos = new java.io.ByteArrayOutputStream(); + byte[] buf = new byte[4096]; + int n; + while ((n = in.read(buf)) > 0) { + bos.write(buf, 0, n); + } + in.close(); + return bos.toByteArray(); + } + + private static File pick(File... files) { + for (File f : files) { + if (f.isFile()) { + return f; + } + } + return null; + } + + private static void fail(String msg) { + Log.error(msg, null); + System.err.println("[rsx] " + msg); + } + + private static void sleep(long ms) { + try { + Thread.sleep(ms); + } catch (InterruptedException ignored) { + } + } +} \ No newline at end of file diff --git a/bridge/src/main/java/special/Main.java b/bridge/src/main/java/special/Main.java new file mode 100644 index 0000000..48241a3 --- /dev/null +++ b/bridge/src/main/java/special/Main.java @@ -0,0 +1,25 @@ +package special; + +import java.util.List; + +/** + * Generated entry point injected into every mod jar. + * + * The client's loader hard-codes this class name: it calls the static main and + * later the static getRunnableList from the game tick. Both methods forward to + * the bridge, which is visible to the loader because a -javaagent jar is + * appended to the system class path. + */ +public final class Main { + + private Main() { + } + + public static void main(String[] args) { + rsx.ModBridge.launch(Main.class, args); + } + + public static List getRunnableList() { + return rsx.ModBridge.drain(Main.class); + } +} \ No newline at end of file diff --git a/bridge/src/test/fakeclient/FakeMain.java b/bridge/src/test/fakeclient/FakeMain.java new file mode 100644 index 0000000..a6c7886 --- /dev/null +++ b/bridge/src/test/fakeclient/FakeMain.java @@ -0,0 +1,28 @@ +// Drives the fake client the way the game would, so the bridge can be tested +// end to end: bring the client up, hand the mods to the vendor loader, then tick. + +public class FakeMain { + + public static void main(String[] args) throws Exception { + System.out.println("[fake] class loader: " + FakeMain.class.getClassLoader()); + System.out.println("[fake] joml.fastmath = " + System.getProperty("joml.fastmath")); + + wwk client = new wwk(); + wwk.WA = client; + client.zb = "PLAYER"; + client.ta = "WORLD"; + client.S = null; + client.Zb = "TIMER"; + client.jC = "RENDER"; + client.pC = new pvdafug("http://snoop.minecraft.net/report"); + System.out.println("[fake] client up, telemetry scheduled"); + + Thread.sleep(2500); + System.out.println("[fake] ticking 5 times"); + for (int i = 0; i < 5; i++) { + client.tick(); + Thread.sleep(200); + } + System.out.println("[fake] done"); + } +} \ No newline at end of file diff --git a/bridge/src/test/fakeclient/ilxq.java b/bridge/src/test/fakeclient/ilxq.java new file mode 100644 index 0000000..62913c1 --- /dev/null +++ b/bridge/src/test/fakeclient/ilxq.java @@ -0,0 +1,79 @@ +// Test stand-in for the client's code loader. +// +// The real client exposes a static method that takes a jar and the arguments, +// loads the entry class `special.Main`, calls its main(String[]) and later +// invokes its static getRunnableList() from the game tick. This stand-in has the +// same shape so the bridge can be exercised without launching the game. + +import java.lang.reflect.Method; + +public class ilxq { + + private static Method runnableList; + + /** mirrors the vendor signature: static, (byte[], String[]) -> boolean */ + public static boolean loadJar(byte[] jar, String[] args) throws Exception { + System.out.println("[fake] loading mod jar, " + jar.length + " bytes, args=" + + java.util.Arrays.toString(args)); + jarLoader(jar); + Class main = loader.loadClass("special.Main"); + Method m = main.getDeclaredMethod("main", String[].class); + m.setAccessible(true); + m.invoke(null, (Object) args); + runnableList = main.getDeclaredMethod("getRunnableList"); + runnableList.setAccessible(true); + return true; + } + + /** mirrors the vendor tick hook */ + public static void tickDrain() { + if (runnableList == null) { + return; + } + try { + Object res = runnableList.invoke(null); + if (res instanceof java.util.List) { + for (Object r : (java.util.List) res) { + ((Runnable) r).run(); + } + } + } catch (Throwable t) { + t.printStackTrace(); + } + } + + static MemLoader loader = new MemLoader(ilxq.class.getClassLoader()); + + static void jarLoader(byte[] jar) throws Exception { + java.util.zip.ZipInputStream zin = + new java.util.zip.ZipInputStream(new java.io.ByteArrayInputStream(jar)); + java.util.zip.ZipEntry e; + while ((e = zin.getNextEntry()) != null) { + if (e.isDirectory()) { + continue; + } + java.io.ByteArrayOutputStream bos = new java.io.ByteArrayOutputStream(); + byte[] buf = new byte[8192]; + int n; + while ((n = zin.read(buf)) > 0) { + bos.write(buf, 0, n); + } + loader.define(e.getName(), bos.toByteArray()); + } + zin.close(); + } + + static class MemLoader extends ClassLoader { + MemLoader(ClassLoader parent) { + super(parent); + } + + void define(String name, byte[] bytes) { + if (name.endsWith(".class")) { + // defineClass wants the internal name: dots, not slashes + defineClass(name.substring(0, name.length() - 6) + .replace('/', '.'), bytes, 0, bytes.length); + } + } + } +} \ No newline at end of file diff --git a/bridge/src/test/fakeclient/pvdafug.java b/bridge/src/test/fakeclient/pvdafug.java new file mode 100644 index 0000000..898602b --- /dev/null +++ b/bridge/src/test/fakeclient/pvdafug.java @@ -0,0 +1,31 @@ +// Test stand-in for the telemetry class (patch A6 target): owns a Timer that, +// in the real client, posts the machine's OS, JVM arguments and GL limits. + +import java.util.Timer; +import java.util.TimerTask; + +public class pvdafug { + + private final Timer do_ = new Timer("Snooper Timer", true); + private final String url; + + public pvdafug(String url) { + this.url = url; + do_.schedule(new TimerTask0(), 1000L); + } + + public String url() { + return url; + } + + private void post() { + System.out.println("[fake-snooper] posting to " + url); + } + + private class TimerTask0 extends TimerTask { + @Override + public void run() { + post(); + } + } +} \ No newline at end of file diff --git a/bridge/src/test/fakeclient/wwk.java b/bridge/src/test/fakeclient/wwk.java new file mode 100644 index 0000000..b4e6fd6 --- /dev/null +++ b/bridge/src/test/fakeclient/wwk.java @@ -0,0 +1,26 @@ +// Test stand-in for the client entry point. +// +// Field and method names are deliberately identical to the ones in the real +// profile (player is "zb", world is "ta", timer is "Zb" - one capital apart), so +// the bridge exercises the same exact-match lookups it will do on the game. + +public class wwk { + + public static wwk WA; // field_71432_P, the client instance + + public Object zb; // field_71439_g player + public Object ta; // field_71441_e world + public Object S; // field_71462_r currentScreen + public Object Zb; // field_71428_T timer + public Object jC; // field_71438_f renderGlobal + public pvdafug pC; // vendor field holding the telemetry object + + public static wwk getMinecraftStatic() { // func_71410_x + return WA; + } + + /** the vendor tick: drains mod tasks on this thread */ + public void tick() { + ilxq.tickDrain(); + } +} \ No newline at end of file diff --git a/bridge/src/test/mod/ExampleMod.java b/bridge/src/test/mod/ExampleMod.java new file mode 100644 index 0000000..e50402e --- /dev/null +++ b/bridge/src/test/mod/ExampleMod.java @@ -0,0 +1,34 @@ +package example; + +import net.rustexremake.api.Rsx; +import net.rustexremake.api.RsxMod; + +/** + * Example mod. It is compiled against the stable API only, so it does not have + * to be rebuilt when the vendor re-obfuscates the client. + */ +public class ExampleMod implements RsxMod { + + private int ticks; + + @Override + public void onLoad() { + Rsx.info("ExampleMod: loaded on build " + Rsx.buildId()); + Rsx.info("ExampleMod: Minecraft is " + Rsx.describe("net.minecraft.client.Minecraft")); + + // a repeating task runs on the game thread, driven by the client's own + // tick, so touching game state here is safe + Rsx.every(200L, new Runnable() { + @Override + public void run() { + ticks++; + Object mc = Rsx.minecraft(); + Object player = Rsx.player(); + Rsx.info("ExampleMod tick " + ticks + + " client=" + (mc != null) + + " player=" + player + + " world=" + Rsx.world()); + } + }); + } +} \ No newline at end of file diff --git a/bridge/src/test/python/run_test.py b/bridge/src/test/python/run_test.py new file mode 100644 index 0000000..532a6cc --- /dev/null +++ b/bridge/src/test/python/run_test.py @@ -0,0 +1,186 @@ +#!/usr/bin/env python +""" +rsx-run-test — end-to-end test of the bridge against a stand-in client. + +The real client cannot be launched from a test (it needs auth, a window and a +GPU), so this builds a tiny client with the *same shape*: a code loader that +takes a jar, calls `special.Main.main(String[])`, and drains +`special.Main.getRunnableList()` from its tick - plus a client class whose +field names are the ones the real profile uses. + +It verifies, in one run: + * the profile is found and the build hash matches + * patch A2 sets joml.fastmath before anything reads it + * patch A6 cancels the telemetry timer (the stand-in prints if it fires) + * a mod jar is handed to the client's own loader + * the mod's onLoad runs and its repeating task runs on the game thread + +Usage: python run_test.py [--keep] +""" +import os +import shutil +import subprocess +import sys +import zipfile + +HERE = os.path.dirname(os.path.abspath(__file__)) +BRIDGE_JAR = os.path.join(os.path.dirname(HERE), "build", "libs", "rsx-bridge.jar") +SRC = os.path.join(HERE, "fakeclient") +MOD_SRC = os.path.join(HERE, "mod") +RUN = os.path.join(HERE, "run") + + +def sh(*args, **kw): + return subprocess.run(args, capture_output=True, text=True, **kw) + + +# The client ships its own Java 8. Run the stand on that same JRE: patch A6 +# reaches into java.util.Timer's internals, which the module system blocks on +# modern JDKs but allows on 8 - the runtime the agent actually meets in game. +CLIENT_JRE = r"G:\rustexremake\rustexremake\gamefiles\java\bin\java.exe" + + +def java(): + override = os.environ.get("RSX_TEST_JAVA") + if override: + return override + if os.path.exists(CLIENT_JRE): + return CLIENT_JRE + return "java" + + +def javac(sources, out, cp=None): + os.makedirs(out, exist_ok=True) + # class files must stay loadable by the client's Java 8 + cmd = ["javac", "-nowarn", "--release", "8", "-d", out] + if cp: + cmd += ["-cp", cp] + r = subprocess.run(cmd + sources, capture_output=True, text=True) + if r.returncode != 0: + print(r.stdout) + print(r.stderr) + raise SystemExit("javac failed") + + +def zip_dir(src, jar): + if os.path.exists(jar): + os.remove(jar) + with zipfile.ZipFile(jar, "w", zipfile.ZIP_DEFLATED) as z: + for dp, _dn, fns in os.walk(src): + for fn in fns: + if fn.endswith(".class"): + full = os.path.join(dp, fn) + rel = os.path.relpath(full, src).replace("\\", "/") + z.write(full, rel) + + +def main(): + if not os.path.exists(BRIDGE_JAR): + raise SystemExit("bridge jar not built: " + BRIDGE_JAR) + + classes = os.path.join(RUN, "fakeclasses") + modclasses = os.path.join(RUN, "modclasses") + for d in (classes, modclasses): + shutil.rmtree(d, ignore_errors=True) + os.makedirs(classes, exist_ok=True) + os.makedirs(modclasses, exist_ok=True) + + print("== compiling the stand-in client ==") + javac([os.path.join(SRC, f) for f in os.listdir(SRC) if f.endswith(".java")], + classes) + + print("== compiling the example mod ==") + javac([os.path.join(MOD_SRC, f) for f in os.listdir(MOD_SRC) + if f.endswith(".java")], modclasses, cp=BRIDGE_JAR) + + game = os.path.join(RUN, "game.jar") + zip_dir(classes, game) + + mods = os.path.join(RUN, "mods") + os.makedirs(mods, exist_ok=True) + modjar = os.path.join(mods, "example-mod.jar") + if os.path.exists(modjar): + os.remove(modjar) + with zipfile.ZipFile(modjar, "w", zipfile.ZIP_DEFLATED) as z: + z.writestr("META-INF/MANIFEST.MF", + "Manifest-Version: 1.0\r\n" + "Rsx-Mod-Entrypoint: example.ExampleMod\r\n\r\n") + for dp, _dn, fns in os.walk(modclasses): + for fn in fns: + if fn.endswith(".class"): + full = os.path.join(dp, fn) + z.write(full, os.path.relpath(full, modclasses) + .replace("\\", "/")) + + import hashlib + h = hashlib.sha256() + with open(game, "rb") as fh: + for chunk in iter(lambda: fh.read(1 << 20), b""): + h.update(chunk) + sha = h.hexdigest() + + bridge = os.path.join(RUN, "bridge") + os.makedirs(os.path.join(bridge, "profiles"), exist_ok=True) + shutil.copy(BRIDGE_JAR, os.path.join(bridge, "rsx-bridge.jar")) + profile = "\n".join([ + "rsxprofile 1", + "build %s %s 1 1" % (sha[:16], sha), + "loader ilxq loadJar special.Main", + "patch.a2 wsygzaib joml.fastmath", + "patch.a6 pvdafug snooper pC", + "class net.minecraft.client.Minecraft wwk", + "field net.minecraft.client.Minecraft player zb Lwpqgx;", + "field net.minecraft.client.Minecraft world ta Lwwhgz;", + "field net.minecraft.client.Minecraft currentScreen S Lbsh;", + "field net.minecraft.client.Minecraft timer Zb Lmlyn;", + "field net.minecraft.client.Minecraft instance WA Lwwk;", + "field net.minecraft.client.Minecraft renderGlobal jC Ldqtrv;", + "field net.minecraft.client.Minecraft snooper pC Lpvdafug;", + "method net.minecraft.client.Minecraft getMinecraft getMinecraftStatic ()Lwwk;", + ]) + "\n" + with open(os.path.join(bridge, "profiles", "latest.rsxp"), "w", + encoding="utf-8") as fh: + fh.write(profile) + + log = os.path.join(RUN, "rsx", "bridge.log") + if os.path.exists(log): + os.remove(log) + + print("== running with the agent attached ==") + cmd = [java(), + "-javaagent:" + os.path.join(bridge, "rsx-bridge.jar"), + "-Dminecraft.applet.TargetDirectory=" + RUN, + "-cp", os.path.join(bridge, "rsx-bridge.jar") + ";" + game, + "FakeMain"] + r = subprocess.run(cmd, capture_output=True, text=True, timeout=180) + out = r.stdout + r.stderr + for line in out.splitlines(): + print(" " + line) + + print() + print("== verdict ==") + checks = [ + ("profile loaded", "profile " in out and "from latest.rsxp" in out), + ("build hash verified", "build verified" in out), + ("A2 applied", "A2 applied" in out and "joml.fastmath = true" in out), + ("A6 disabled the telemetry", + "A6 applied: telemetry timers replaced in 1 object(s)" in out), + ("mod handed to the client loader", "loading mod jar" in out), + ("mod loaded", "mod loaded: example-mod.jar" in out), + ("mod task ran on the game thread", "ExampleMod tick 1" in out), + ("telemetry never fired", "[fake-snooper] posting" not in out), + ] + bad = 0 + for label, ok in checks: + print(" %-38s %s" % (label, "OK" if ok else "FAIL")) + if not ok: + bad += 1 + if bad: + print(" %d check(s) failed" % bad) + return 1 + print(" all checks passed") + return 0 + + +if __name__ == "__main__": + sys.exit(main()) \ No newline at end of file diff --git a/build.cmd b/build.cmd new file mode 100644 index 0000000..bd0d941 --- /dev/null +++ b/build.cmd @@ -0,0 +1,3 @@ +@echo off +chcp 65001 >nul +powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0build.ps1" diff --git a/install.cmd b/install.cmd new file mode 100644 index 0000000..7a942ad --- /dev/null +++ b/install.cmd @@ -0,0 +1,6 @@ +@echo off +rem Installs the modloader into this machine. Run as administrator if the +rem launcher refuses to close or you want it to work from an elevated session. +chcp 65001 >nul +powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0scripts\install.ps1" %* +pause diff --git a/launcher-patch/src/LauncherPatch.java b/launcher-patch/src/LauncherPatch.java new file mode 100644 index 0000000..f49e574 --- /dev/null +++ b/launcher-patch/src/LauncherPatch.java @@ -0,0 +1,843 @@ +import java.io.File; +import java.io.InputStream; +import java.io.OutputStream; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.security.MessageDigest; +import java.util.ArrayList; +import java.util.Enumeration; +import java.util.List; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; +import java.util.jar.JarOutputStream; +import java.util.zip.ZipEntry; + +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassWriter; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.AbstractInsnNode; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.FieldInsnNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.JumpInsnNode; +import org.objectweb.asm.tree.LdcInsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.VarInsnNode; + +/** + * Puts the launch choice inside the launcher: injects a call to + * rsx.Choice.pick() at the start of the Play handler and records which + * obfuscated config field carries the agent argument. + * + * usage: LauncherPatch inspect|patch [] + */ +public final class LauncherPatch { + + private static final String TARGET_CLASS = "fa"; +private static final String UPDATER_CLASS = "sb"; + private static final String SELF_UPDATE_CLASS = "ha"; + private static final String GUARD = "rsx/Patch"; + private static final String PLAY_ID = "clickPlay"; + private static final String CHOICE = "rsx/Choice"; + private static final String CHOICE_RESOURCE = "rsx/env-field.txt"; + private static final byte[] MARKER = + "rsx-choice-patch".getBytes(StandardCharsets.UTF_8); + +public static void main(String[] args) throws Exception { + String mode = args.length > 0 ? args[0] : "inspect"; + Path jar = Paths.get(args[1]); + if ("inspect".equals(mode)) { + inspect(jar); + return; + } + if ("verify".equals(mode)) { + verify(jar); + return; + } + if ("check".equals(mode)) { + System.out.println(check(jar) ? "all classes verify" + : "VERIFICATION FAILED"); + return; + } + if ("dump".equals(mode)) { + dump(jar); + return; + } + if ("showenv".equals(mode)) { + showEnv(jar); + return; + } + if ("getprop".equals(mode)) { + System.out.println(" " + getProp(jar, + args.length > 2 ? args[2] : "")); + return; + } + if ("setenv".equals(mode)) { + setEnv(jar, args.length > 2 ? args[2] : ""); + return; + } + if ("setprop".equals(mode)) { + setProp(jar, args[2], args[3]); + return; + } + // patch [envFieldSpec] + Path home = Paths.get(args[2]); + String envMeta = args.length > 3 ? args[3].replace(",", "\n") : "wa\nALLATORIxDEMO"; + patch(jar, home, envMeta); + } + + /** + * Write a launcher config value with java.util.Properties. + * + * launcher_config.properties is a properties file: a backslash is an escape + * character, so writing the line by hand turns G:\rsx-mod into G:... and a + * following \r into a line break. Loading and storing instead guarantees the + * round trip, and the value is read back to prove it. + */ + private static void setEnv(Path config, String value) throws Exception { + setProp(config, "env", value); + String readBack = getProp(config, "env"); + if (!value.equals(readBack)) { + System.out.println(" ERROR: value did not survive the write"); + System.exit(3); + } + if (!value.isEmpty()) { + String jar = value.replaceFirst("^-javaagent:", "").replace("\"", ""); + System.out.println(" agent jar: " + jar + + " exists=" + new File(jar).isFile()); + } + } + + /** Write any launcher config value through java.util.Properties. */ + private static void setProp(Path config, String key, String value) + throws Exception { + java.util.Properties props = new java.util.Properties(); + try (java.io.Reader in = new java.io.InputStreamReader( + java.nio.file.Files.newInputStream(config), "ISO-8859-1")) { + props.load(in); + } + if (value.isEmpty()) { + props.remove(key); + } else { + props.setProperty(key, value); + } + try (java.io.Writer out = new java.io.OutputStreamWriter( + java.nio.file.Files.newOutputStream(config), "ISO-8859-1")) { + props.store(out, "rsx modloader"); + } + String readBack = getProp(config, key); + System.out.println(" " + key + " now: " + + readBack.replace("\r", "").replace("\n", "")); + if (!value.equals(readBack)) { + System.out.println(" ERROR: " + key + + " did not survive the write"); + System.exit(3); + } + } + + private static String getProp(Path config, String key) throws Exception { + java.util.Properties props = new java.util.Properties(); + try (java.io.Reader in = new java.io.InputStreamReader( + java.nio.file.Files.newInputStream(config), "ISO-8859-1")) { + props.load(in); + } + return props.getProperty(key, ""); + } + + /** + * Print how the launcher itself will read a config value. + * + * Used by the installer to prove the path survived the properties escaping. + */ + private static void showEnv(Path config) throws Exception { + java.util.Properties props = new java.util.Properties(); + try (java.io.Reader in = new java.io.InputStreamReader( + java.nio.file.Files.newInputStream(config), "ISO-8859-1")) { + props.load(in); + } + String env = props.getProperty("env", ""); + System.out.println(" env as java reads it: " + env); + if (env.startsWith("-javaagent:")) { + String jar = env.substring("-javaagent:".length()).replace("\"", ""); + File file = new File(jar); + System.out.println(" agent jar: " + jar); + System.out.println(" exists: " + file.isFile()); + if (!file.isFile()) { + System.exit(2); + } + } + System.out.println(" gamePath1: " + props.getProperty("gamePath1", "")); + } + + private static ClassNode readClass(JarFile jar, String name) throws Exception { + JarEntry entry = jar.getJarEntry(name + ".class"); + if (entry == null) { + throw new IllegalStateException("no class " + name + " in the jar"); + } + InputStream in = jar.getInputStream(entry); + try { + ClassNode node = new ClassNode(); + new ClassReader(in).accept(node, 0); + return node; + } finally { + in.close(); + } + } + + private static void inspect(Path jarPath) throws Exception { + JarFile jar = new JarFile(jarPath.toFile()); + try { + ClassNode cls = readClass(jar, TARGET_CLASS); + System.out.println("class " + cls.name.replace('/', '.') + ", methods " + + cls.methods.size()); + for (MethodNode m : cls.methods) { + String play = findPlayBranch(m); + if (play != null) { + System.out.println(" clickPlay handler: " + m.name + + m.desc + " (" + play + ")"); + } + String env = findEnvField(m); + if (env != null) { + System.out.println(" env argument in: " + m.name + + m.desc + " -> " + env); + } + } + } finally { + jar.close(); + } + } + + /** Returns a short description when the method dispatches "clickPlay". */ + private static String findPlayBranch(MethodNode m) { + InsnList insns = m.instructions; + for (int i = 0; i < insns.size(); i++) { + AbstractInsnNode insn = insns.get(i); + if (!(insn instanceof LdcInsnNode)) { + continue; + } + if (!PLAY_ID.equals(((LdcInsnNode) insn).cst)) { + continue; + } + for (int j = i + 1; j < Math.min(i + 4, insns.size()); j++) { + AbstractInsnNode next = insns.get(j); + if (next instanceof MethodInsnNode + && "equals".equals(((MethodInsnNode) next).name)) { + AbstractInsnNode after = insns.get(j + 1); + if (after instanceof JumpInsnNode) { + return "ldc+equals+" + after.getOpcode(); + } + } + } + } + return null; + } + + /** + * The agent argument reaches the command line as the value of a config + * field, guarded by an isEmpty() check right before List.add. + */ + private static String findEnvField(MethodNode m) { + AbstractInsnNode[] insns = m.instructions.toArray(); + for (int i = 0; i < insns.length; i++) { + AbstractInsnNode insn = insns[i]; + if (!(insn instanceof MethodInsnNode)) { + continue; + } + MethodInsnNode call = (MethodInsnNode) insn; + if (!"add".equals(call.name)) { + continue; + } + if (!call.owner.replace('/', '.').startsWith("java.util")) { + continue; + } + for (int j = i - 1; j >= 0 && i - j < 14; j--) { + AbstractInsnNode prev = insns[j]; + if (!(prev instanceof FieldInsnNode)) { + continue; + } + FieldInsnNode f = (FieldInsnNode) prev; + if (f.getOpcode() == Opcodes.GETFIELD + && f.desc.startsWith("Ljava/lang/String;") + && !TARGET_CLASS.equals(f.owner)) { + return f.owner.replace('/', '.') + "#" + f.name + ":" + f.desc; + } + } + } + return null; + } + +/** Show the code around the injected call so its placement can be checked. */ + private static void verify(Path jarPath) throws Exception { + JarFile jar = new JarFile(jarPath.toFile()); + try { + ClassNode sb = readClass(jar, UPDATER_CLASS); + boolean guard = false; + for (MethodNode m : sb.methods) { + if (hasGuardCall(m)) { + guard = true; + AbstractInsnNode[] insns = m.instructions.toArray(); + for (int i = 0; i < insns.length; i++) { + AbstractInsnNode insn = insns[i]; + if (insn instanceof MethodInsnNode + && GUARD.equals(((MethodInsnNode) insn).owner)) { + System.out.println("updater guard in " + + UPDATER_CLASS + "." + m.name + m.desc + + " at instruction " + i + " of " + + insns.length); + for (int j = Math.max(0, i - 1); + j < Math.min(insns.length, i + 5); j++) { + System.out.println(" " + j + ": " + + describe(insns[j])); + } + } + } + } + } + System.out.println(guard ? "updater guard present" + : "updater guard MISSING"); + + ClassNode cls = readClass(jar, TARGET_CLASS); + boolean found = false; + for (MethodNode m : cls.methods) { + AbstractInsnNode[] insns = m.instructions.toArray(); + for (int i = 0; i < insns.length; i++) { + AbstractInsnNode insn = insns[i]; + if (!(insn instanceof MethodInsnNode)) { + continue; + } + MethodInsnNode call = (MethodInsnNode) insn; + if (!CHOICE.equals(call.owner) || !"pick".equals(call.name)) { + continue; + } + found = true; + System.out.println("call in " + m.name + m.desc + + " at instruction " + i + " of " + insns.length); + for (int j = Math.max(0, i - 7); + j < Math.min(insns.length, i + 4); j++) { + System.out.println(" " + j + ": " + describe(insns[j])); + } + } + } + System.out.println(found ? "patch present" : "no patch found"); + } finally { + jar.close(); + } + } + + /** Print the code around the "clickPlay" test so the branch shape is clear. */ + private static void dump(Path jarPath) throws Exception { + JarFile jar = new JarFile(jarPath.toFile()); + try { + ClassNode cls = readClass(jar, TARGET_CLASS); + for (MethodNode m : cls.methods) { + AbstractInsnNode[] insns = m.instructions.toArray(); + for (int i = 0; i < insns.length; i++) { + if (!(insns[i] instanceof LdcInsnNode)) { + continue; + } + if (!PLAY_ID.equals(((LdcInsnNode) insns[i]).cst)) { + continue; + } + System.out.println("--- " + m.name + m.desc + + ", clickPlay at " + i); + for (int j = Math.max(0, i - 4); + j < Math.min(insns.length, i + 26); j++) { + System.out.println(" " + j + ": " + describe(insns[j])); + } + } + } + } finally { + jar.close(); + } + } + + /** + * Load the classes we touched so the JVM verifier has the last word. + * + * Repackaging alone does not prove anything: a missing stackmap frame only + * shows up when the class is linked, which is why a bad patch turns into an + * endless update check instead of an obvious failure. + */ +private static boolean check(Path jarPath) throws Exception { + ClassLoader loader = new java.net.URLClassLoader( + new java.net.URL[] {jarPath.toUri().toURL()}, + ClassLoader.getSystemClassLoader().getParent()); + ClassLoader base = javafxLoader(); + if (base != null) { + // JavaFX on the parent so its classes resolve for fa + loader = new java.net.URLClassLoader( + new java.net.URL[] {jarPath.toUri().toURL()}, base); + } +boolean ok = true; + for (String name : new String[] {TARGET_CLASS, UPDATER_CLASS, + SELF_UPDATE_CLASS, "rsx.Patch"}) { + try { + Class.forName(name, true, loader); + System.out.println(" " + name + " verifies"); + } catch (Throwable t) { + Throwable cause = t; + while (cause.getCause() != null) { + cause = cause.getCause(); + } + ok = false; + System.out.println(" " + name + " FAILED: " + cause); + } + } + return ok; + } + +/** + * The launcher runs with JavaFX on the module path; fa references javafx.stage + * directly, so verification of that class needs those modules present. + */ + private static ClassLoader javafxLoader() { + String home = System.getenv("APPDATA"); + if (home == null) { + return null; + } + java.nio.file.Path lib = java.nio.file.Paths.get(home, "kjstudio", + "launcher", "runtime", "javafx", "lib"); + if (!java.nio.file.Files.isDirectory(lib)) { + return null; + } + java.util.List urls = new java.util.ArrayList(); + try (java.util.stream.Stream files = + java.nio.file.Files.list(lib)) { + for (java.nio.file.Path p : (Iterable) files::iterator) { + if (p.toString().endsWith(".jar")) { + urls.add(p.toUri().toURL()); + } + } + } catch (Exception e) { + return null; + } + if (urls.isEmpty()) { + return null; + } + return new java.net.URLClassLoader(urls.toArray(new java.net.URL[0]), + ClassLoader.getSystemClassLoader().getParent()); + } + + private static String describe(AbstractInsnNode insn) { + if (insn instanceof org.objectweb.asm.tree.LabelNode) { + return "LABEL " + ((org.objectweb.asm.tree.LabelNode) insn).toString(); + } + String text = insn.getClass().getSimpleName() + .replace("InsnNode", "") + " op=" + insn.getOpcode(); + if (insn instanceof LdcInsnNode) { + text += " cst=\"" + ((LdcInsnNode) insn).cst + "\""; + } else if (insn instanceof MethodInsnNode) { + MethodInsnNode call = (MethodInsnNode) insn; + text += " " + call.owner.replace('/', '.') + "." + call.name; + } else if (insn instanceof JumpInsnNode) { + text += " -> " + ((JumpInsnNode) insn).label; + } else if (insn instanceof VarInsnNode) { + text += " var" + ((VarInsnNode) insn).var; + } else if (insn instanceof FieldInsnNode) { + text += " " + ((FieldInsnNode) insn).owner.replace('/', '.') + + "." + ((FieldInsnNode) insn).name; + } + return text; + } + +private static void patch(Path jarPath, Path home, String envMeta) + throws Exception { + JarFile jar = new JarFile(jarPath.toFile()); + ClassNode cls = readClass(jar, TARGET_CLASS); + + MethodNode play = null; + boolean alreadyPatched = false; + for (MethodNode m : cls.methods) { + if (hasChoiceCall(m)) { + alreadyPatched = true; + } + if (findPlayBranch(m) != null) { + play = m; + } + } + if (alreadyPatched) { + System.out.println("already patched, nothing to do"); + jar.close(); + return; + } + if (play == null) { + throw new IllegalStateException( + "no Play handler found in " + TARGET_CLASS); + } +injectPlayChoice(play); + + // fa.loadedWeb() sets the button state to ERROR, which hides every + // button, and it can run after ha.y() already picked PLAY. Restore it. + boolean startButtonPatched = false; + for (MethodNode m : cls.methods) { + if (!m.name.equals("loadedWeb") || !m.desc.equals("()V") + || hasStartButtonCall(m)) { + continue; + } + InsnList code = new InsnList(); + code.add(new VarInsnNode(Opcodes.ALOAD, 0)); + code.add(new MethodInsnNode(Opcodes.INVOKESTATIC, CHOICE, + "restoreStartButton", "(Ljava/lang/Object;)V", false)); + m.instructions.insert(code); + startButtonPatched = true; + System.out.println("injected start-button restore into " + + TARGET_CLASS + ".loadedWeb()"); + break; + } + if (!startButtonPatched) { + System.out.println("WARNING: " + TARGET_CLASS + + ".loadedWeb() not found or already guarded"); + } + + // Two separate checks look at app.jar. sb.q() compares size and hash + // against the manifest; ha.ALLATORIxDEMO()Z hashes the running jar and + // reports "update found, restart the launcher". Both must be covered, + // otherwise the launcher still nags about an update it would undo. + ClassNode sb = readClass(jar, UPDATER_CLASS); + for (MethodNode m : sb.methods) { + if (m.name.equals("q") && m.desc.startsWith("(Ljava/nio/file/Path;L") + && m.desc.endsWith(")Z") && !hasGuardCall(m)) { + injectGuard(m); + System.out.println("guarded " + UPDATER_CLASS + "." + m.name + + m.desc + " against re-download"); + break; + } + } + ClassWriter sbWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS); + sb.accept(sbWriter); + byte[] sbBytes = sbWriter.toByteArray(); + + ClassNode ha = readClass(jar, SELF_UPDATE_CLASS); + boolean selfGuarded = false; + for (MethodNode m : ha.methods) { + if (!hasAppJarCheck(m) || hasSelfGuard(m)) { + continue; + } + injectSelfGuard(m); + selfGuarded = true; + System.out.println("guarded " + SELF_UPDATE_CLASS + "." + m.name + + m.desc + " against the restart notice"); + break; + } + if (!selfGuarded) { + System.out.println("WARNING: " + SELF_UPDATE_CLASS + + " update check was not found or already guarded"); + } + ClassWriter haWriter = new ClassWriter(ClassWriter.COMPUTE_MAXS); + ha.accept(haWriter); + byte[] haBytes = haWriter.toByteArray(); + +ClassWriter writer = new ClassWriter(ClassWriter.COMPUTE_MAXS); + cls.accept(writer); + writer.getClass(); + + byte[] envBytes = envMeta == null + ? "# not found\n#\n".getBytes(StandardCharsets.UTF_8) + : (envMeta + "\n" + "#\n").getBytes(StandardCharsets.UTF_8); + + Path backup = jarPath.resolveSibling(jarPath.getFileName() + ".orig"); + if (!Files.exists(backup)) { + Files.copy(jarPath, backup, StandardCopyOption.COPY_ATTRIBUTES); + System.out.println("backup: " + backup); + } + + Path tmp = jarPath.resolveSibling(jarPath.getFileName() + ".new"); + OutputStream out = Files.newOutputStream(tmp); + JarOutputStream outJar = new JarOutputStream(out); + try { + Enumeration entries = jar.entries(); + while (entries.hasMoreElements()) { + JarEntry entry = entries.nextElement(); +String name = entry.getName(); + if (name.equals(TARGET_CLASS + ".class") + || name.equals(UPDATER_CLASS + ".class") + || name.equals(SELF_UPDATE_CLASS + ".class")) { + continue; + } + if (name.startsWith("rsx/") || name.equals(CHOICE_RESOURCE)) { + continue; + } + JarEntry copy = new JarEntry(name); + outJar.putNextEntry(copy); + InputStream in = jar.getInputStream(entry); + try { + copyStream(in, outJar); + } finally { + in.close(); + } + outJar.closeEntry(); + } + outJar.putNextEntry(new JarEntry(TARGET_CLASS + ".class")); + outJar.write(writer.toByteArray()); + outJar.closeEntry(); + +outJar.putNextEntry(new JarEntry(UPDATER_CLASS + ".class")); + outJar.write(sbBytes); + outJar.closeEntry(); + + outJar.putNextEntry(new JarEntry(SELF_UPDATE_CLASS + ".class")); + outJar.write(haBytes); + outJar.closeEntry(); + +// rsx/ classes come from this patcher's own jar, which keeps the + // installer free of build directories: Choice$1 and Choice$2 have + // to travel along or loading Choice fails with NoClassDefFoundError + Path self = Paths.get(LauncherPatch.class.getProtectionDomain() + .getCodeSource().getLocation().toURI()); + int copied = 0; + try (JarFile own = new JarFile(self.toFile())) { + Enumeration mine = own.entries(); + while (mine.hasMoreElements()) { + JarEntry e = mine.nextElement(); + if (!e.getName().startsWith("rsx/") || e.isDirectory()) { + continue; + } + outJar.putNextEntry(new JarEntry(e.getName())); + InputStream in = own.getInputStream(e); + try { + copyStream(in, outJar); + } finally { + in.close(); + } + outJar.closeEntry(); + copied++; + System.out.println(" + " + e.getName()); + } + } + if (copied == 0) { + throw new IllegalStateException( + "no rsx/ classes inside the patcher jar"); + } + + outJar.putNextEntry(new JarEntry(CHOICE_RESOURCE)); + outJar.write(envBytes); + outJar.closeEntry(); + + // the runtime location, so the launcher-side code finds the agent + // on whatever machine this gets installed on + outJar.putNextEntry(new JarEntry("rsx/home.txt")); + outJar.write((home.toAbsolutePath().toString() + "\n") + .getBytes(StandardCharsets.UTF_8)); + outJar.closeEntry(); + System.out.println(" modloader home: " + home.toAbsolutePath()); + + outJar.putNextEntry(new JarEntry("rsx/patch.marker")); + outJar.write(MARKER); + outJar.closeEntry(); + } finally { + outJar.close(); + jar.close(); + } + + replace(tmp, jarPath); + System.out.println("patched " + jarPath + " (" + + Files.size(jarPath) + " bytes)"); + + String hash = sha256(jarPath); + Path json = jarPath.resolveSibling("app.jar.json"); + if (Files.isRegularFile(json)) { + Files.write(json, ("{\"hash\": \"" + hash + "\"}") + .getBytes(StandardCharsets.UTF_8)); + System.out.println("app.jar.json updated with " + hash); + } + } + +private static boolean hasChoiceCall(MethodNode m) { + for (AbstractInsnNode insn = m.instructions.getFirst(); insn != null; + insn = insn.getNext()) { + if (insn instanceof MethodInsnNode + && CHOICE.equals(((MethodInsnNode) insn).owner)) { + return true; + } + } + return false; + } + + private static boolean hasGuardCall(MethodNode m) { + for (AbstractInsnNode insn = m.instructions.getFirst(); insn != null; + insn = insn.getNext()) { + if (insn instanceof MethodInsnNode + && GUARD.equals(((MethodInsnNode) insn).owner)) { + return true; + } + } + return false; + } + + /** + * Put the patched jar in place. + * + * Antivirus and the shell indexer routinely hold app.jar for a moment, so this + * retries and falls back through delete+move and plain copy instead of failing + * on a transient lock. + */ +private static void replace(Path tmp, Path target) throws Exception { + Exception last = null; + for (int attempt = 0; attempt < 12; attempt++) { + try { + Files.move(tmp, target, StandardCopyOption.REPLACE_EXISTING); + return; + } catch (Exception e) { + last = e; + Thread.sleep(750L); + } + } + try { + Files.deleteIfExists(target); + Files.move(tmp, target, StandardCopyOption.REPLACE_EXISTING); + return; + } catch (Exception e) { + last = e; + } + Files.copy(tmp, target, StandardCopyOption.REPLACE_EXISTING); + Files.deleteIfExists(tmp); + System.out.println(" (replaced by copy, move stayed locked)"); + if (last != null) { + System.out.println(" lock detail: " + last.getMessage()); + } + } + + private static boolean hasStartButtonCall(MethodNode m) { + for (AbstractInsnNode insn = m.instructions.getFirst(); insn != null; + insn = insn.getNext()) { + if (insn instanceof MethodInsnNode + && "restoreStartButton".equals(((MethodInsnNode) insn).name)) { + return true; + } + } + return false; + } + + private static boolean hasSelfGuard(MethodNode m) { + for (AbstractInsnNode insn = m.instructions.getFirst(); insn != null; + insn = insn.getNext()) { + if (insn instanceof MethodInsnNode) { + MethodInsnNode call = (MethodInsnNode) insn; + if (GUARD.equals(call.owner) && "skipSelfUpdate".equals(call.name)) { + return true; + } + } + } + return false; + } + + /** The method that hashes the running jar mentions the "app.jar" literal. */ + private static boolean hasAppJarCheck(MethodNode m) { + if (!m.desc.endsWith(")Z")) { + return false; + } + for (AbstractInsnNode insn = m.instructions.getFirst(); insn != null; + insn = insn.getNext()) { + if (insn instanceof LdcInsnNode + && "app.jar".equals(((LdcInsnNode) insn).cst)) { + return true; + } + } + return false; + } + + /** + * Guard the check that hashes the jar in use: report "no update" so the + * launcher stops showing the restart notice. + * + * The method is an instance method whose slot 0 is the launcher itself, not a + * directory, so the guard is handed the working directory as a String: the same + * directory the check compares its jar against. + */ + private static void injectSelfGuard(MethodNode m) { + org.objectweb.asm.tree.LabelNode body = new org.objectweb.asm.tree.LabelNode(); + InsnList code = new InsnList(); + code.add(new org.objectweb.asm.tree.LdcInsnNode("user.dir")); + code.add(new MethodInsnNode(Opcodes.INVOKESTATIC, GUARD, + "skipSelfUpdate", "(Ljava/lang/String;)Z", false)); + code.add(new JumpInsnNode(Opcodes.IFNE, body)); + code.add(new org.objectweb.asm.tree.InsnNode(Opcodes.ICONST_0)); + code.add(new org.objectweb.asm.tree.InsnNode(Opcodes.IRETURN)); + code.add(new org.objectweb.asm.tree.FrameNode(Opcodes.F_SAME, 0, null, 0, null)); + code.add(body); + m.instructions.insert(code); + System.out.println("injected self-update guard into " + m.name + m.desc); + } + + /** Put rsx.Choice.pick() at the first instruction of the clickPlay block. */ + private static void injectPlayChoice(MethodNode play) { + MethodInsnNode call = new MethodInsnNode(Opcodes.INVOKESTATIC, + CHOICE, "pick", "()V", false); + InsnList insns = play.instructions; + for (AbstractInsnNode insn = insns.getFirst(); insn != null; ) { + AbstractInsnNode next = insn.getNext(); + if (insn instanceof LdcInsnNode + && PLAY_ID.equals(((LdcInsnNode) insn).cst)) { + AbstractInsnNode eq = insn.getNext(); + AbstractInsnNode jump = eq == null ? null : eq.getNext(); + if (eq instanceof MethodInsnNode && jump instanceof JumpInsnNode + && "equals".equals(((MethodInsnNode) eq).name)) { + // javac emits "IFNE end" here, so the block that handles + // clickPlay starts on the fall-through, right after the jump + insns.insert(jump, call); + System.out.println("injected rsx.Choice.pick() into " + + play.name + play.desc); + return; + } + } + insn = next; + } + throw new IllegalStateException("could not place the Play dialog call"); + } + + /** + * Guard the "needs downloading" test: if rsx.Patch claims the file, report + * it as current so the launcher does not overwrite its own patched jar. + */ + private static void injectGuard(MethodNode m) { + org.objectweb.asm.tree.LabelNode skip = + new org.objectweb.asm.tree.LabelNode(); + InsnList code = new InsnList(); + code.add(new VarInsnNode(Opcodes.ALOAD, 0)); + code.add(new MethodInsnNode(Opcodes.INVOKESTATIC, GUARD, + "skipDownload", "(Ljava/nio/file/Path;)Z", false)); + code.add(new JumpInsnNode(Opcodes.IFEQ, skip)); + code.add(new org.objectweb.asm.tree.InsnNode(Opcodes.ICONST_0)); + code.add(new org.objectweb.asm.tree.InsnNode(Opcodes.IRETURN)); + // the branch introduces a new frame: at this point the operand stack is + // empty again and the locals are untouched, which is a SAME frame. + // COMPUTE_MAXS does not rebuild frames, so without it the JVM refuses + // the class with "Expecting a stackmap frame at branch target". + code.add(new org.objectweb.asm.tree.FrameNode(Opcodes.F_SAME, 0, null, 0, null)); + code.add(skip); + m.instructions.insert(code); + System.out.println("injected guard into " + m.name + m.desc); + } + + private static void copyStream(InputStream in, OutputStream out) + throws Exception { + byte[] buffer = new byte[1 << 16]; + int read; + while ((read = in.read(buffer)) > 0) { + out.write(buffer, 0, read); + } + } + + private static String sha256(Path file) throws Exception { + MessageDigest digest = MessageDigest.getInstance("SHA-256"); + InputStream in = Files.newInputStream(file); + try { + byte[] buffer = new byte[1 << 20]; + int read; + while ((read = in.read(buffer)) > 0) { + digest.update(buffer, 0, read); + } + } finally { + in.close(); + } + StringBuilder sb = new StringBuilder(); + for (byte b : digest.digest()) { + sb.append(String.format("%02x", b)); + } + return sb.toString(); + } +} \ No newline at end of file diff --git a/launcher-patch/src/ScanCalls.java b/launcher-patch/src/ScanCalls.java new file mode 100644 index 0000000..bc9f62f --- /dev/null +++ b/launcher-patch/src/ScanCalls.java @@ -0,0 +1,150 @@ +import java.io.InputStream; +import java.util.Enumeration; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +import org.objectweb.asm.ClassReader; +import org.objectweb.asm.ClassVisitor; +import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Opcodes; + +/** + * Finds who calls a given method inside the launcher jar. + * + * usage: java -Dscan.owner=ha -Dscan.name=y -Dscan.desc=()V ScanCalls app.jar + * + * The launcher is only partially decompiled, so the caller of the start-up + * routine is looked up in the bytecode directly. + */ +public final class ScanCalls { + + private static int hits; + private static String owner; + private static String name; + private static String desc; + + public static void main(String[] args) throws Exception { + String jarPath = args.length > 0 ? args[0] + : System.getProperty("scan.jar", "app.jar"); + owner = System.getProperty("scan.owner", ""); + name = System.getProperty("scan.name", ""); + desc = System.getProperty("scan.desc", ""); + String dump = System.getProperty("scan.dump", ""); + + JarFile jar = new JarFile(jarPath); + try { + Enumeration entries = jar.entries(); + while (entries.hasMoreElements()) { + JarEntry entry = entries.nextElement(); + if (!entry.getName().endsWith(".class")) { + continue; + } + InputStream in = jar.getInputStream(entry); + try { + new ClassReader(in).accept( + dump.isEmpty() ? new CallerVisitor() : new Dumper(dump), 0); + } finally { + in.close(); + } + } + } finally { + jar.close(); + } + if (dump.isEmpty()) { + System.out.println(" calls of " + owner + "." + name + desc + ": " + hits); + } + } + + /** Prints the instructions of one method, e.g. scan.dump=xa.run()V */ + private static final class Dumper extends ClassVisitor { + + private final String target; + private String cls; + private String method; + + Dumper(String target) { + super(Opcodes.ASM9); + this.target = target; + } + + @Override + public void visit(int version, int access, String className, + String signature, String superName, String[] interfaces) { + this.cls = className.replace('/', '.'); + } + + @Override + public MethodVisitor visitMethod(int access, String methodName, + String descriptor, String signature, String[] exceptions) { + this.method = methodName + descriptor; + boolean wanted = (cls + "." + method).equals(target); + if (!wanted) { + return null; + } + System.out.println("--- " + cls + "." + method); + return new MethodVisitor(Opcodes.ASM9) { + private int index; + + @Override + public void visitMethodInsn(int opcode, String o, String n, + String d, boolean itf) { + System.out.println(" " + (index++) + ": invoke " + + o.replace('/', '.') + "." + n + d); + } + + @Override + public void visitFieldInsn(int opcode, String o, String n, String d) { + System.out.println(" " + (index++) + ": field " + + o.replace('/', '.') + "." + n); + } + + @Override + public void visitLdcInsn(Object value) { + System.out.println(" " + (index++) + ": ldc \"" + value + "\""); + } + + @Override + public void visitInsn(int opcode) { + if (opcode >= Opcodes.IRETURN && opcode <= Opcodes.RETURN) { + System.out.println(" " + (index++) + ": return"); + } + } + }; + } + } + + private static final class CallerVisitor extends ClassVisitor { + + private String cls; + private String method; + + CallerVisitor() { + super(Opcodes.ASM9); + } + + @Override + public void visit(int version, int access, String className, + String signature, String superName, String[] interfaces) { + this.cls = className.replace('/', '.'); + } + + @Override + public MethodVisitor visitMethod(int access, String methodName, + String descriptor, String signature, String[] exceptions) { + this.method = methodName + descriptor; + return new MethodVisitor(Opcodes.ASM9) { + @Override + public void visitMethodInsn(int opcode, String calledOwner, + String calledName, String calledDesc, boolean itf) { + if (calledOwner.equals(owner) + && calledName.equals(name) + && calledDesc.equals(desc)) { + hits++; + System.out.println(" " + cls + "." + method + + " -> " + owner + "." + name + desc); + } + } + }; + } + } +} \ No newline at end of file diff --git a/launcher-patch/src/rsx/Choice.java b/launcher-patch/src/rsx/Choice.java new file mode 100644 index 0000000..944d530 --- /dev/null +++ b/launcher-patch/src/rsx/Choice.java @@ -0,0 +1,418 @@ +package rsx; + +import java.io.File; +import java.lang.reflect.Field; +import java.lang.reflect.Method; +import java.nio.charset.Charset; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.nio.file.StandardOpenOption; + +import javafx.application.Platform; +import javafx.scene.control.Alert; +import javafx.scene.control.ButtonBar.ButtonData; +import javafx.scene.control.ButtonType; + +/** + * Asks which way to launch, right when Play is pressed inside the launcher. + * + * Injected into the launcher's Play handler, so the answer steers this very + * launch: the dialog runs before the game process is built, and the env + * argument the launcher passes to the JVM is adjusted in memory (the launcher + * keeps its config in memory, so editing the file would not be enough). + * + * The dialog is a JavaFX Alert on purpose. A Swing modal opened from the + * JavaFX application thread deadlocks the launcher - it showed a frozen window + * and never returned. + */ +public final class Choice { + + private static final String TITLE = "RustexRemake"; + private static final String MODS = "mods"; + private static final String VANILLA = "vanilla"; + + private Choice() { + } + + /** + * Puts the start button back after the page has loaded. + * + * The launcher has a race of its own: xa.run() calls ha.y(), which sets the + * state to PLAY and then blocks, while fa.loadedWeb() later sets it to ERROR + * when the WebView finishes - and the ERROR state hides every button. With a + * fast page load loadedWeb wins the race backwards and the Play button is + * simply not there. Re-applying the state once, after loadedWeb has run, keeps + * the button on screen no matter which order the two happen in. + */ + public static void restoreStartButton(final Object app) { + try { + javafx.application.Platform.runLater(new Runnable() { + @Override + public void run() { + try { + applyStartState(app); + } catch (Throwable t) { + log("could not restore the start button: " + t); + } + } + }); + } catch (Throwable t) { + log("could not schedule the start button fix: " + t); + } + } + + private static void applyStartState(Object app) throws Exception { + Class states = Class.forName("z"); + Object[] values = (Object[]) states.getMethod("values").invoke(null); + Field func = app.getClass().getDeclaredField("func"); + func.setAccessible(true); + Object ui = func.get(app); + Method setter = func.getType().getMethod("setStartButton", states); + int play = 0; + int download = 2; + boolean installed = gameJar(); + setter.invoke(ui, values[installed ? play : download]); + log("start button restored: " + + (installed ? "PLAY" : "DOWNLOAD")); + } + +/** + * Whether the game looks installed, which decides between the PLAY and the + * DOWNLOAD button. ha.u is only filled in when a launch starts, so at start-up + * the install path comes from the launcher config instead. + */ + private static boolean gameJar() { + if (jarUnder(System.getProperty("rsx.gamefiles"))) { + return true; + } + try { + Class ha = Class.forName("ha"); + if (jarUnder((String) ha.getField("u").get(null))) { + return true; + } + } catch (Throwable ignored) { + } + try { + java.util.Properties props = new java.util.Properties(); + Path config = launcherConfig(); + try (java.io.Reader in = new java.io.InputStreamReader( + Files.newInputStream(config), Charset.forName("ISO-8859-1"))) { + props.load(in); + } + String base = props.getProperty("gamePath1", ""); + if (!base.isEmpty() + && jarUnder(new File(base, "rustexremake/gamefiles").getPath())) { + return true; + } + } catch (Throwable ignored) { + } + return false; + } + + private static boolean jarUnder(String dir) { + return dir != null && !dir.isEmpty() + && new File(dir, "game.jar").isFile(); + } + + public static void pick() { + try { + String current = readMode(); + String chosen = ask(current); + if (chosen == null) { + log("kept " + describe(current)); + return; + } + writeMode(chosen); + updateConfigFile(chosen); + applyToRunningConfig(chosen); + log("mode: " + chosen); + } catch (Throwable t) { + log("choice failed, keeping the current mode: " + t); + } + } + + private static String ask(final String current) { + String scripted = System.getProperty("rsx.choice"); + if (scripted != null && !scripted.isEmpty()) { + return scripted; + } + try { + Class.forName("javafx.application.Platform"); + } catch (Throwable t) { + log("JavaFX not reachable, keeping " + describe(current)); + return null; + } + if (!Platform.isFxApplicationThread()) { + final String[] result = new String[1]; + final java.util.concurrent.CountDownLatch done = + new java.util.concurrent.CountDownLatch(1); + Platform.runLater(new Runnable() { + @Override + public void run() { + try { + result[0] = askOnFxThread(current); + } finally { + done.countDown(); + } + } + }); + try { + done.await(2, java.util.concurrent.TimeUnit.MINUTES); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + } + return result[0]; + } + return askOnFxThread(current); + } + + private static String askOnFxThread(String current) { + Alert alert = new Alert(Alert.AlertType.NONE); + alert.setTitle(TITLE); + alert.setHeaderText("Как запустить игру?"); + alert.setContentText( + "С модами — обычный режим. Включится модлоадер, загрузятся моды " + + "из папки mods, а встроенная телеметрия игры будет отключена. " + + "Выбирайте, если играете с модами или пишете свой мод.\n\n" + + "Ванилла — игра запустится вообще без модлоадера: ни модов, ни " + + "патчей, ровно как в оригинале. Выбирайте, чтобы проверить, " + + "что игра сама по себе работает нормально.\n\n" + + "Оставить как есть — больше не спрашивать и запустить в том же " + + "режиме, что и в прошлый раз (" + describe(current) + ").\n\n" + + "Режим можно сменить в любой момент: снова нажмите «Играть»."); + + ButtonType mods = new ButtonType("С модами", ButtonData.YES); + ButtonType vanilla = new ButtonType("Ванилла", ButtonData.NO); + ButtonType keep = new ButtonType("Оставить как есть", ButtonData.CANCEL_CLOSE); + alert.getButtonTypes().setAll(mods, vanilla, keep); + + ButtonType answer = alert.showAndWait().orElse(keep); + if (answer == mods) { + return MODS; + } + if (answer == vanilla) { + return VANILLA; + } + return null; + } + + private static String describe(String mode) { + return VANILLA.equals(mode) ? "ванилла" : "с модами"; + } + +/** + * Where the modloader runtime lives. + * + * The patcher writes this path into the launcher jar at install time, so the + * same build works on any machine: nothing here is tied to one install dir. + */ + private static File home() { + String override = System.getProperty("rsx.home"); + if (override != null && !override.isEmpty()) { + return new File(override); + } + try (java.util.Scanner s = new java.util.Scanner( + Choice.class.getResourceAsStream("home.txt"), "UTF-8")) { + if (s.hasNextLine()) { + String path = s.nextLine().trim(); + if (!path.isEmpty()) { + return new File(path); + } + } + } catch (Throwable ignored) { + // fall through to the old default + } + return new File("G:\\rsx-mod\\bridge"); + } + + private static String agentArg() { + String override = System.getProperty("rsx.agent"); + if (override != null && !override.isEmpty()) { + return override; + } + return "-javaagent:\"" + new File(home(), "rsx-bridge.jar").getPath() + "\""; + } + + private static String readMode() { + File f = new File(home(), "mode.txt"); + if (!f.isFile()) { + return MODS; + } + try { + String text = new String(Files.readAllBytes(f.toPath()), + Charset.forName("UTF-8")).trim(); + return VANILLA.equalsIgnoreCase(text) ? VANILLA : MODS; + } catch (Throwable t) { + return MODS; + } + } + + private static void writeMode(String mode) { + try { + Files.write(new File(home(), "mode.txt").toPath(), + mode.getBytes(Charset.forName("UTF-8"))); + } catch (Throwable t) { + log("cannot write mode.txt: " + t); + } + } + + /** + * Keep launcher_config.properties in step so a fresh launcher agrees. + * + * Written through java.util.Properties on purpose: this file is a properties + * file, and writing lines by hand breaks as soon as a value contains + * backslashes or a colon - it escaped them as \ and \: and the launcher then + * handed the JVM a mangled -javaagent path, which stopped the game from + * starting at all. + */ + private static void updateConfigFile(String mode) { + Path config = launcherConfig(); + if (config == null || !Files.isRegularFile(config)) { + return; + } + java.util.Properties props = new java.util.Properties(); + try (java.io.Reader in = new java.io.InputStreamReader( + Files.newInputStream(config), Charset.forName("ISO-8859-1"))) { + props.load(in); + } catch (Throwable t) { + log("cannot read the launcher config: " + t); + return; + } + try { + Files.copy(config, config.resolveSibling( + config.getFileName().toString() + ".rsxbak"), + StandardCopyOption.REPLACE_EXISTING); + if (MODS.equals(mode)) { + props.setProperty("env", agentArg()); + } else { + props.remove("env"); + } + try (java.io.Writer out = new java.io.OutputStreamWriter( + Files.newOutputStream(config), + Charset.forName("ISO-8859-1"))) { + props.store(out, "rsx modloader"); + } + log("launcher config file updated"); + } catch (Throwable t) { + log("cannot update the launcher config: " + t); + } + } + + /** + * The launcher keeps its config in memory, so the file is not enough for + * the launch that is about to start. The patcher records which obfuscated + * config field carries the env argument; here it is set on the live object, + * which is reached through the launcher's own singleton rather than by + * calling arbitrary statics. + */ + private static void applyToRunningConfig(String mode) { + String[] meta = envField(); + if (meta == null) { + return; + } + try { + Class configClass = Class.forName(meta[0]); + Object config = liveConfig(configClass); + if (config == null) { + log("launcher config object not found, file only"); + return; + } + Field f = configClass.getDeclaredField(meta[1]); + f.setAccessible(true); + f.set(config, MODS.equals(mode) ? agentArg() : ""); + log("launcher env argument set in memory"); + } catch (Throwable t) { + log("cannot set the env argument in memory: " + t); + } + } + +/** + * Reach the launcher's live config object. + * + * jb.ALLATORIxDEMO() is an instance method in this build, so invoking it with a + * null receiver throws. The singleton itself sits in a static field of its own + * class, which is what gets read here. + */ + private static Object liveConfig(Class configClass) throws Exception { + Class launcher = Class.forName("jb"); + Object app = null; + for (Field f : launcher.getDeclaredFields()) { + if (!java.lang.reflect.Modifier.isStatic(f.getModifiers()) + || !launcher.isAssignableFrom(f.getType())) { + continue; + } + f.setAccessible(true); + Object value = f.get(null); + if (value != null) { + app = value; + break; + } + } + if (app == null) { + java.lang.reflect.Method accessor = + launcher.getMethod("ALLATORIxDEMO"); + if (!java.lang.reflect.Modifier.isStatic( + accessor.getModifiers())) { + log("jb.ALLATORIxDEMO is not static, cannot reach the launcher"); + return null; + } + app = accessor.invoke(null); + } + if (app == null) { + return null; + } + for (Field f : launcher.getDeclaredFields()) { + f.setAccessible(true); + Object candidate; + try { + candidate = f.get(app); + } catch (Throwable t) { + continue; + } + if (configClass.isInstance(candidate)) { + return candidate; + } + } + return null; + } + + private static String[] envField() { + try (java.util.Scanner s = new java.util.Scanner( + Choice.class.getResourceAsStream("env-field.txt"), "UTF-8")) { + if (!s.hasNextLine()) { + return null; + } + String owner = s.nextLine().trim(); + String field = s.nextLine().trim(); + return owner.isEmpty() ? null : new String[] {owner, field}; + } catch (Throwable t) { + return null; + } + } + + private static Path launcherConfig() { + String appdata = System.getenv("APPDATA"); + if (appdata == null) { + return null; + } + return Paths.get(appdata, "kjstudio", "launcher", + "launcher_config.properties"); + } + + private static void log(String message) { + try { + String appdata = System.getenv("APPDATA"); + Path dir = Paths.get(appdata == null ? "." : appdata, "kjstudio", + "rsx-launcher"); + Files.createDirectories(dir); + Files.write(dir.resolve("choice.log"), + (message + System.lineSeparator()).getBytes( + Charset.forName("UTF-8")), + StandardOpenOption.CREATE, StandardOpenOption.APPEND); + } catch (Throwable ignored) { + // logging is best effort + } + } +} \ No newline at end of file diff --git a/launcher-patch/src/rsx/Patch.java b/launcher-patch/src/rsx/Patch.java new file mode 100644 index 0000000..10dcbe4 --- /dev/null +++ b/launcher-patch/src/rsx/Patch.java @@ -0,0 +1,84 @@ +package rsx; + +import java.io.File; + +/** + * Lets the patched launcher survive its own updater. + * + * The download engine compares every manifest entry with the file on disk and + * flags app.jar as outdated because the patch changes its size, so the launcher + * keeps offering to re-download itself and would overwrite the patch. The guard + * is skipped for every other file, so game updates keep working. + * + * Removing the marker file .rsx-patched next to app.jar, or starting the + * launcher with -Drsx.allowLauncherUpdate=true, restores the normal behaviour. + */ +public final class Patch { + + private Patch() { + } + + /** True when this file must not be treated as outdated. */ + public static boolean skipDownload(java.nio.file.Path path) { + try { + if (path == null) { + return false; + } + java.nio.file.Path name = path.getFileName(); + if (name == null || !"app.jar".equalsIgnoreCase(name.toString())) { + return false; + } + log("skip: " + path); + if ("true".equalsIgnoreCase( + System.getProperty("rsx.allowLauncherUpdate"))) { + return false; + } + File dir = path.toAbsolutePath().getParent() == null + ? new File(".") + : path.toAbsolutePath().getParent().toFile(); + boolean on = new File(dir, ".rsx-patched").isFile(); + log("skipDownload(" + path + ") -> " + on); + return on; + } catch (Throwable t) { + log("guard error: " + t); + return false; + } + } + + /** + * Same question for the second check, the one that hashes the running jar + * itself and then reports "update found, restart the launcher". + */ + public static boolean skipSelfUpdate(String launcherDir) { + try { + if (launcherDir == null || launcherDir.isEmpty()) { + return false; + } + if ("true".equalsIgnoreCase( + System.getProperty("rsx.allowLauncherUpdate"))) { + return false; + } + boolean on = new File(launcherDir, ".rsx-patched").isFile(); + log("skipSelfUpdate(" + launcherDir + ") -> " + on); + return on; + } catch (Throwable t) { + log("guard error: " + t); + return false; + } + } + + private static void log(String message) { + try { + String appdata = System.getenv("APPDATA"); + java.nio.file.Path dir = java.nio.file.Paths.get( + appdata == null ? "." : appdata, "kjstudio", "rsx-launcher"); + java.nio.file.Files.createDirectories(dir); + java.nio.file.Files.write(dir.resolve("updater-guard.log"), + (message + System.lineSeparator()).getBytes("UTF-8"), + java.nio.file.StandardOpenOption.CREATE, + java.nio.file.StandardOpenOption.APPEND); + } catch (Throwable ignored) { + // best effort + } + } +} \ No newline at end of file diff --git a/mod-template/build.gradle b/mod-template/build.gradle new file mode 100644 index 0000000..7601ee5 --- /dev/null +++ b/mod-template/build.gradle @@ -0,0 +1,42 @@ +// Build settings for a RustexRemake mod. +// +// A mod is compiled ONCE against the stable API and never rebuilt: the bridge +// resolves every logical name against whatever build is installed, so a vendor +// re-obfuscation does not invalidate anything that was already built. + +plugins { + id 'java' +} + +group = 'com.example' +version = '1.0.0' + +java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} + +dependencies { + // the only thing a mod ever compiles against + compileOnly files('libs/rsx-api.jar') +} + +tasks.withType(JavaCompile).configureEach { + options.encoding = 'UTF-8' + options.release = 8 +} + +jar { + archiveFileName = "${project.name}.jar" + manifest { + // the bridge reads this to find the class to instantiate + attributes('Rsx-Mod-Entrypoint': 'com.example.ExampleMod') + } +} + +// convenience: drop the built mod straight into the client's mods folder +tasks.register('installMod', Copy) { + dependsOn 'jar' + from jar + into "${projectDir}/../../rsx-mod/mods" +} \ No newline at end of file diff --git a/mod-template/settings.gradle b/mod-template/settings.gradle new file mode 100644 index 0000000..2fecac1 --- /dev/null +++ b/mod-template/settings.gradle @@ -0,0 +1 @@ +rootProject.name = 'example-mod' diff --git a/mod-template/src/main/java/example/ExampleMod.java b/mod-template/src/main/java/example/ExampleMod.java new file mode 100644 index 0000000..2e6301c --- /dev/null +++ b/mod-template/src/main/java/example/ExampleMod.java @@ -0,0 +1,39 @@ +package com.example; + +import net.rustexremake.api.Rsx; +import net.rustexremake.api.RsxMod; + +/** + * Example mod. + * + * Note what is NOT here: no obfuscated class name, no field name, no reflection. + * The mod asks for logical names, and the bridge maps them onto the build that + * is installed. Build this once - it keeps working across vendor updates. + */ +public class ExampleMod implements RsxMod { + + private int ticks; + + @Override + public void onLoad() { + Rsx.info("ExampleMod загружен, билд " + Rsx.buildId()); + + // Repeating task. It is queued by a timer thread but always executed by + // the game's own tick, so touching game state here is safe. + Rsx.every(1000L, new Runnable() { + @Override + public void run() { + ticks++; + Rsx.info("tick " + ticks + + " | игрок: " + Rsx.player() + + " | мир: " + Rsx.world() + + " | экран: " + Rsx.currentScreen()); + } + }); + } + + @Override + public void onUnload() { + Rsx.info("ExampleMod выгружен"); + } +} \ No newline at end of file diff --git a/scripts/build.ps1 b/scripts/build.ps1 new file mode 100644 index 0000000..ff046ab --- /dev/null +++ b/scripts/build.ps1 @@ -0,0 +1,141 @@ +# Builds everything the installer needs, into dist\: +# +# dist\rsx-bridge.jar the agent (-javaagent), Java 8 +# dist\rsx-api.jar API a mod compiles against +# dist\rsx-launcher-patch.jar launcher patcher with ASM inside +# dist\mod-template\ ready-to-edit mod project +# +# Only a JDK is required: ASM is vendored under third_party\asm so the build +# works offline and the patcher jar is self-contained. + +$ErrorActionPreference = 'Stop' +$Repo = Split-Path -Parent $PSScriptRoot +if (-not $Repo) { $Repo = $PSCommandPath | Split-Path -Parent | Split-Path -Parent } +$Dist = Join-Path $Repo 'dist' +$Out = Join-Path $Repo 'build' +$Asm = @(Get-ChildItem (Join-Path $Repo 'third_party\asm') -Filter '*.jar' | + ForEach-Object { $_.FullName }) + +function Say($text) { Write-Host " $text" } + +if (-not (Get-Command javac -ErrorAction SilentlyContinue)) { + Write-Host ' Нужен JDK (javac) в PATH.' -ForegroundColor Red + exit 1 +} +if ($Asm.Count -lt 2) { + Write-Host ' Не найдены jar-ки ASM в third_party\asm.' -ForegroundColor Red + exit 1 +} + +New-Item -ItemType Directory -Force -Path $Dist, $Out | Out-Null + +# ---------------------------------------------------------------- agent +$agentSrc = Join-Path $Repo 'bridge\src\main\java' +$agentOut = Join-Path $Out 'agent' +Remove-Item $agentOut -Recurse -Force -ErrorAction SilentlyContinue +New-Item -ItemType Directory -Force -Path $agentOut | Out-Null +$agentFiles = Get-ChildItem $agentSrc -Recurse -Filter '*.java' | ForEach-Object { $_.FullName } +& javac -encoding UTF-8 --release 8 -nowarn -d $agentOut $agentFiles +if ($LASTEXITCODE -ne 0) { Write-Host ' Агент не собрался.' -ForegroundColor Red; exit 1 } +Say "агент скомпилирован ($($agentFiles.Count) файлов)" + +$manifest = Join-Path $Out 'agent-manifest.txt' +@" +Manifest-Version: 1.0 +Premain-Class: rsx.RsxAgent +Can-Redefine-Classes: false +Can-Retransform-Classes: true + +"@ | Set-Content -LiteralPath $manifest -Encoding ASCII + +Push-Location $agentOut +& jar cfm (Join-Path $Dist 'rsx-bridge.jar') $manifest -C $agentOut . +Pop-Location +Say "rsx-bridge.jar ($((Get-Item (Join-Path $Dist 'rsx-bridge.jar')).Length) байт)" + +# ---------------------------------------------------------------- api +$apiOut = Join-Path $Out 'api' +Remove-Item $apiOut -Recurse -Force -ErrorAction SilentlyContinue +New-Item -ItemType Directory -Force -Path $apiOut | Out-Null +$apiFiles = Get-ChildItem (Join-Path $Repo 'bridge\src\main\java\net') -Recurse -Filter '*.java' | + ForEach-Object { $_.FullName } +# the API delegates to the agent internals, so they have to be on the +# classpath; only net/ classes end up in the published jar +& javac -encoding UTF-8 --release 8 -nowarn -cp $agentOut -d $apiOut $apiFiles +if ($LASTEXITCODE -ne 0) { Write-Host ' API не собрался.' -ForegroundColor Red; exit 1 } +Push-Location $apiOut +& jar cf (Join-Path $Dist 'rsx-api.jar') . +Pop-Location +Say "rsx-api.jar ($((Get-Item (Join-Path $Dist 'rsx-api.jar')).Length) байт)" + +# ---------------------------------------------------------------- patcher +$patchOut = Join-Path $Out 'patcher' +Remove-Item $patchOut -Recurse -Force -ErrorAction SilentlyContinue +New-Item -ItemType Directory -Force -Path $patchOut | Out-Null +$patchSrc = Join-Path $Repo 'launcher-patch\src' +# Choice needs JavaFX, which only the launcher ships; it is compiled separately +# below with those jars on the classpath +$patchFiles = Get-ChildItem $patchSrc -Recurse -Filter '*.java' | + Where-Object { $_.Name -ne 'Choice.java' } | + ForEach-Object { $_.FullName } +& javac -encoding UTF-8 --release 8 -nowarn -cp ($Asm -join ';') -d $patchOut $patchFiles +if ($LASTEXITCODE -ne 0) { Write-Host ' Патчер не собрался.' -ForegroundColor Red; exit 1 } + +# Choice talks to JavaFX, so the launcher's own runtime provides those classes +$javafx = Join-Path $env:APPDATA 'kjstudio\launcher\runtime\javafx\lib' +if (Test-Path $javafx) { + $fx = @(Get-ChildItem $javafx -Filter '*.jar' | ForEach-Object { $_.FullName }) + & javac -encoding UTF-8 --release 8 -nowarn -cp ($fx -join ';') -d $patchOut ` + (Join-Path $patchSrc 'rsx\Choice.java') + if ($LASTEXITCODE -ne 0) { + Write-Host ' Choice не собрался: нужны JavaFX-jar-ки лаунчера.' -ForegroundColor Red + exit 1 + } +} else { + Say 'ВНИМАНИЕ: JavaFX лаунчера не найден, Choice собран вслепую' +} + +# shade ASM so the jar runs on any machine +$shade = $patchOut +foreach ($jar in $Asm) { + Push-Location $shade + & jar xf $jar + Pop-Location +} +Remove-Item (Join-Path $shade 'META-INF\MANIFEST.MF') -Force -ErrorAction SilentlyContinue +Remove-Item (Join-Path $shade 'META-INF\versions') -Recurse -Force -ErrorAction SilentlyContinue + +$patchManifest = Join-Path $Out 'patcher-manifest.txt' +@" +Manifest-Version: 1.0 +Main-Class: LauncherPatch + +"@ | Set-Content -LiteralPath $patchManifest -Encoding ASCII +Push-Location $shade +& jar cfm (Join-Path $Dist 'rsx-launcher-patch.jar') $patchManifest -C $shade . +Pop-Location +Say "rsx-launcher-patch.jar ($((Get-Item (Join-Path $Dist 'rsx-launcher-patch.jar')).Length) байт)" + +# ---------------------------------------------------------------- mod template +$tpl = Join-Path $Dist 'mod-template' +Remove-Item $tpl -Recurse -Force -ErrorAction SilentlyContinue +New-Item -ItemType Directory -Force -Path "$tpl\libs", "$tpl\src\main\java\example" | Out-Null +Copy-Item (Join-Path $Repo 'mod-template\build.gradle') $tpl -Force +Copy-Item (Join-Path $Repo 'mod-template\settings.gradle') $tpl -Force +Copy-Item (Join-Path $Repo 'mod-template\src\main\java\example\ExampleMod.java') ` + "$tpl\src\main\java\example\" -Force +Copy-Item (Join-Path $Dist 'rsx-api.jar') "$tpl\libs\" -Force +@' +@echo off +rem Builds this mod and drops the jar into the client's mods folder. +cd /d "%~dp0" +call gradle jar +if errorlevel 1 exit /b 1 +echo. +echo Скопируй build\libs\example-mod.jar в working_dir\mods +'@ | Set-Content -LiteralPath (Join-Path $tpl 'build.cmd') -Encoding ASCII +Say 'mod-template готов' + +Write-Host '' +Write-Host ' Готово:' -ForegroundColor Green +Get-ChildItem $Dist -File | ForEach-Object { Write-Host " $($_.Name)" } \ No newline at end of file diff --git a/scripts/install-hosts.ps1 b/scripts/install-hosts.ps1 new file mode 100644 index 0000000..ebc66e9 --- /dev/null +++ b/scripts/install-hosts.ps1 @@ -0,0 +1,28 @@ +# Points the vendor's hardcoded server address at this machine so the client +# reaches the local stand-in server instead of the real one. +# +# The client keeps 185.207.214.85 inside its own code (both the /server-ping +# URL and the connect target), so there is no in-game switch for it - the only +# way is a hosts entry. Run this once from an elevated prompt. + +$ErrorActionPreference = 'Stop' +$hosts = Join-Path $env:SystemRoot 'System32\drivers\etc\hosts' +$marker = '# rsx modloader test server' +$line = '127.0.0.1 185.207.214.85' + +$id = [Security.Principal.WindowsIdentity]::GetCurrent() +$isAdmin = (New-Object Security.Principal.WindowsPrincipal($id)).IsInRole( + [Security.Principal.WindowsBuiltInRole]::Administrator) +if (-not $isAdmin) { + Write-Host ' Нужны права администратора: запусти PowerShell от администратора.' -ForegroundColor Red + exit 1 +} + +$content = @(Get-Content -LiteralPath $hosts | + Where-Object { $_ -notmatch [regex]::Escape($marker) -and + $_ -notmatch '^\s*127\.0\.0\.1\s+185\.207\.214\.85' }) + +Set-Content -LiteralPath $hosts -Encoding ASCII -Value ($content + "$line $marker") +Write-Host ' Готово: 185.207.214.85 теперь указывает на 127.0.0.1.' -ForegroundColor Green +Write-Host ' Запусти testserver\start.cmd, потом play.cmd -> 1 (с модами).' +Write-Host ' Обратно: uninstall-hosts.ps1 (или netsh int ip reset).' \ No newline at end of file diff --git a/scripts/install.ps1 b/scripts/install.ps1 new file mode 100644 index 0000000..195d3da --- /dev/null +++ b/scripts/install.ps1 @@ -0,0 +1,188 @@ +# Installs the modloader: copies the runtime files, patches the launcher and +# wires the agent into the launcher config. +# +# install.cmd normal install +# install.cmd --uninstall put everything back +# install.cmd --home install the runtime somewhere else +# install.cmd --game point at a specific game installation + +$ErrorActionPreference = 'Stop' +$Repo = Split-Path -Parent $PSScriptRoot +if (-not $Repo) { $Repo = $PSCommandPath | Split-Path -Parent | Split-Path -Parent } + +$LauncherHome = Join-Path $env:APPDATA 'kjstudio\launcher' +$Config = Join-Path $LauncherHome 'launcher_config.properties' +$AppJar = Join-Path $LauncherHome 'app.jar' +$Marker = Join-Path $LauncherHome '.rsx-patched' +$Dist = Join-Path $Repo 'dist' +$ModHome = Join-Path $env:LOCALAPPDATA 'rsx-mod' +$GamePath = $null +$Uninstall = $false + +for ($i = 0; $i -lt $args.Count; $i++) { + switch ($args[$i]) { + '--uninstall' { $Uninstall = $true } + '--home' { $ModHome = $args[++$i] } + '--game' { $GamePath = $args[++$i] } + default { } + } +} + +function Say($text, $color) { + if ($color) { Write-Host " $text" -ForegroundColor $color } else { Write-Host " $text" } +} +function Die($text) { Say $text Red; exit 1 } + +# --------------------------------------------------------------- launcher must be closed +function Get-LauncherRunning { + Get-Process -ErrorAction SilentlyContinue | Where-Object { + $_.MainWindowTitle -like '*Koptojop*' -or + ($_.Path -and $_.Path -like "$LauncherHome*") + } +} + +$running = Get-LauncherRunning +if ($running) { + Die 'Лаунчер запущен - закрой его (крестик) и запусти установщик снова.' +} + +# --------------------------------------------------------------- java and patcher +$FindPatcher = Join-Path $Dist 'rsx-launcher-patch.jar' + +function Find-Java { + $candidates = @( + (Join-Path $LauncherHome 'runtime\java\bin\java.exe') + ) + foreach ($c in $candidates) { + if (Test-Path $c) { return $c } + } + $cmd = Get-Command java -ErrorAction SilentlyContinue + if ($cmd) { return $cmd.Source } + return $null +} + +# --------------------------------------------------------------- read the config safely +# Handing the config to java.util.Properties is the only safe way to read it: it +# is a properties file, where a backslash escapes the next character. +function Read-GamePath($java, $path, $patcher) { + if (-not (Test-Path $path)) { return $null } + $prev = $ErrorActionPreference + $ErrorActionPreference = 'Continue' + $raw = & $java -jar $patcher getprop $path gamePath1 2>$null + $ErrorActionPreference = $prev + if ($raw) { + $value = ($raw | Select-Object -First 1) -replace '^\s+', '' + if ($value) { return $value } + } + return $null +} + +if (-not (Test-Path $Config)) { + Die "Не найден конфиг лаунчера: $Config" +} + +$game = Read-GamePath (Find-Java) $Config $FindPatcher +if ($GamePath) { $game = $GamePath } + +# --------------------------------------------------------------- uninstall +if ($Uninstall) { + Say 'Удаляю модлоадер...' + $backup = "$AppJar.orig" + if (Test-Path $backup) { + Copy-Item $backup $AppJar -Force + Say 'app.jar восстановлен из резервной копии' + } else { + Say 'резервной копии нет, лаунчер не трогаю' + } + $ErrorActionPreference = 'Continue' + & $java -jar $FindPatcher setenv $Config '' 2>&1 | + ForEach-Object { Say $_ } + $ErrorActionPreference = 'Stop' + Say 'env убран из конфига лаунчера' + Remove-Item $Marker -Force -ErrorAction SilentlyContinue + Say 'маркер удалён' + Say 'Готово. Лаунчер снова запускается как обычно.' Green + exit 0 +} + +# --------------------------------------------------------------- checks +if (-not (Test-Path $Dist)) { Die "Нет каталога dist: $Dist (собери через build.cmd)" } +foreach ($f in 'rsx-bridge.jar', 'rsx-launcher-patch.jar', 'rsx-api.jar') { + if (-not (Test-Path (Join-Path $Dist $f))) { Die "Нет dist\$f - запусти build.cmd" } +} +$java = Find-Java +if (-not $java) { Die 'Не найден java (нужен лаунчерный runtime или java в PATH)' } + +# a clean base to patch: re-patching an already patched jar is a no-op +if (Test-Path "$AppJar.orig") { + Copy-Item "$AppJar.orig" $AppJar -Force + Say 'восстановлен оригинальный app.jar перед патчем' +} + +Say "Лаунчер: $LauncherHome" +Say "Игра: $(if ($game) { $game } else { 'не указан в gamePath1' })" +Say "Модлоадер: $ModHome" +Say '' + +# --------------------------------------------------------------- copy the runtime +New-Item -ItemType Directory -Force -Path (Join-Path $ModHome 'bridge\profiles') | Out-Null +New-Item -ItemType Directory -Force -Path (Join-Path $ModHome 'mods') | Out-Null +Copy-Item (Join-Path $Dist 'rsx-bridge.jar') (Join-Path $ModHome 'bridge') -Force +Say 'скопирован rsx-bridge.jar' + +$existingProfile = Join-Path $ModHome 'bridge\profiles\latest.rsxp' +$oldProfile = 'G:\rsx-mod\bridge\profiles\latest.rsxp' +if (-not (Test-Path $existingProfile) -and (Test-Path $oldProfile)) { + Copy-Item $oldProfile (Split-Path $existingProfile) -Force + Say 'перенесён профиль сборки игры (latest.rsxp)' +} elseif (Test-Path $existingProfile) { + Say 'профиль уже на месте, оставляю как есть' +} else { + Say 'профиля нет - запусти prepare-build.cmd после первой установки', Yellow +} + +# --------------------------------------------------------------- patch the launcher +Say '' +Say 'Патчу лаунчер...' +$patcher = Join-Path $Dist 'rsx-launcher-patch.jar' +$meta = "wa`nALLATORIxDEMO" +# native stderr must not be treated as a PowerShell error here +$prev = $ErrorActionPreference +$ErrorActionPreference = 'Continue' +$out = & $java -jar $patcher patch $AppJar $ModHome $meta 2>&1 +$code = $LASTEXITCODE +$ErrorActionPreference = $prev +$out | ForEach-Object { Say $_ } +if ($code -ne 0) { + Die "Патч не удался (код $code). Если лаунчер запущен с правами администратора - закрой его и повтори." +} + +Set-Content -LiteralPath $Marker -Value 'patched app.jar: rsx modloader' -Encoding ASCII +Say 'маркер .rsx-patched создан' + +# --------------------------------------------------------------- wire the agent +$agentArg = "-javaagent:`"$ModHome\bridge\rsx-bridge.jar`"" +$ErrorActionPreference = 'Continue' +$out = & $java -jar $patcher setenv $Config $agentArg 2>&1 +$code = $LASTEXITCODE +$ErrorActionPreference = $prev +$out | ForEach-Object { Say $_ } +if ($code -ne 0) { + Die "Не удалось записать env в конфиг лаунчера (код $code)" +} + +Say '' +Say 'Проверяю, что путь читается как надо...' +$ErrorActionPreference = 'Continue' +$check = & $java -jar $patcher showenv $Config 2>&1 +$ErrorActionPreference = $prev +$check | ForEach-Object { Say $_ } + +Say '' +Say 'Готово.' Green +Say '' +Say 'Дальше:' +Say ' 1. запускай лаунчер через start-launcher.cmd, а не ярлыком -' +Say ' updater.exe перекачает app.jar и сотрёт патч' +Say ' 2. жми «Играть» - появится выбор «С модами / Ванилла»' +Say " 3. моды клади в $ModHome\mods" \ No newline at end of file diff --git a/scripts/start-launcher.ps1 b/scripts/start-launcher.ps1 new file mode 100644 index 0000000..14680e7 --- /dev/null +++ b/scripts/start-launcher.ps1 @@ -0,0 +1,41 @@ +# Starts the patched launcher directly, without updater.exe. +# +# updater.exe re-downloads app.jar whenever its hash differs from the +# manifest, which is exactly what a patched jar looks like - so launching +# through the desktop shortcut silently undoes the patch. This runs the +# launcher itself, with the JavaFX runtime that ships next to it. + +$ErrorActionPreference = 'Stop' +$LauncherHome = Join-Path $env:APPDATA 'kjstudio\launcher' +$Java = Join-Path $LauncherHome 'runtime\java\bin\javaw.exe' +$Jar = Join-Path $LauncherHome 'app.jar' +$FxLib = Join-Path $LauncherHome 'runtime\javafx\lib' +$FxBin = Join-Path $LauncherHome 'runtime\javafx\bin' + +if (-not (Test-Path $Java) -or -not (Test-Path $Jar)) { + Write-Host " Нет лаунчера: $Jar" -ForegroundColor Red + exit 1 +} + +Remove-Item (Join-Path $LauncherHome 'app.lock') -Force -ErrorAction SilentlyContinue + +$env:JAVA_TOOL_OPTIONS = '' +Write-Host ' Запускаю лаунчер напрямую (без updater.exe)...' +Start-Process -FilePath $Java -ArgumentList @( + '--module-path', "`"$FxLib`"", + '--add-modules', 'ALL-MODULE-PATH', + "-Djava.library.path=`"$FxBin`"", + '-Dprism.order=sw', + '-cp', "`"$Jar`"", + 'application.Main' +) -WorkingDirectory $LauncherHome | Out-Null + +Start-Sleep -Seconds 12 +$up = Get-Process -ErrorAction SilentlyContinue | + Where-Object { $_.MainWindowTitle -like '*Koptojop*' } +if ($up) { + Write-Host ' Лаунчер запущен, окно должно появиться.' -ForegroundColor Green +} else { + Write-Host ' Лаунчер не поднялся, смотри logs в папке лаунчера.' -ForegroundColor Yellow + exit 1 +} \ No newline at end of file diff --git a/scripts/uninstall-hosts.ps1 b/scripts/uninstall-hosts.ps1 new file mode 100644 index 0000000..cf61e00 --- /dev/null +++ b/scripts/uninstall-hosts.ps1 @@ -0,0 +1,20 @@ +# Removes the hosts entry added by install-hosts.ps1. + +$ErrorActionPreference = 'Stop' +$hosts = Join-Path $env:SystemRoot 'System32\drivers\etc\hosts' +$marker = '# rsx modloader test server' + +$id = [Security.Principal.WindowsIdentity]::GetCurrent() +$isAdmin = (New-Object Security.Principal.WindowsPrincipal($id)).IsInRole( + [Security.Principal.WindowsBuiltInRole]::Administrator) +if (-not $isAdmin) { + Write-Host ' Нужны права администратора: запусти PowerShell от администратора.' -ForegroundColor Red + exit 1 +} + +$content = @(Get-Content -LiteralPath $hosts | + Where-Object { $_ -notmatch [regex]::Escape($marker) -and + $_ -notmatch '^\s*127\.0\.0\.1\s+185\.207\.214\.85' }) + +Set-Content -LiteralPath $hosts -Encoding ASCII -Value $content +Write-Host ' Запись удалена, клиент снова ходит на официальный сервер.' -ForegroundColor Green \ No newline at end of file diff --git a/start-launcher.cmd b/start-launcher.cmd new file mode 100644 index 0000000..de3a35f --- /dev/null +++ b/start-launcher.cmd @@ -0,0 +1,7 @@ +@echo off +rem Starts the patched launcher directly. +rem updater.exe re-downloads app.jar whenever its hash differs from the +rem manifest, which is exactly what a patched jar looks like. +chcp 65001 >nul +powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0scripts\start-launcher.ps1" +pause diff --git a/testserver/selftest.py b/testserver/selftest.py new file mode 100644 index 0000000..9a34d5b --- /dev/null +++ b/testserver/selftest.py @@ -0,0 +1,160 @@ +#!/usr/bin/env python3 +"""Self-test for server.py: runs the stand-in server on a spare port and talks +to it with a hand-rolled 1.12.2 client, checking handshake, login and the +play-state packets the game needs to reach a world.""" + +import socket +import struct +import sys +import threading +import time +import uuid + +sys.path.insert(0, r"G:\rsx-mod\testserver") + +import server as srv # noqa: E402 + + +def read_varint(sock): + value = 0 + for shift in range(0, 35, 7): + chunk = sock.recv(1) + if not chunk: + raise AssertionError("closed") + byte = chunk[0] + value |= (byte & 0x7F) << shift + if not byte & 0x80: + return value + raise AssertionError("varint too long") + + +def read_packet(sock): + length = read_varint(sock) + data = b"" + while len(data) < length: + chunk = sock.recv(length - len(data)) + if not chunk: + raise AssertionError("closed mid packet") + data += chunk + pid_val = 0 + shift = 0 + pos = 0 + while True: + byte = data[pos] + pos += 1 + pid_val |= (byte & 0x7F) << shift + if not byte & 0x80: + break + shift += 7 + return pid_val, data[pos:] + + +def send_packet(sock, pid, payload=b""): + body = srv.varint(pid) + payload + sock.sendall(srv.varint(len(body)) + body) + + +def drain(sock, wanted, budget=8.0): + seen = {} + deadline = time.time() + budget + while time.time() < deadline and not wanted.issubset(seen): + try: + pid, payload = read_packet(sock) + except (socket.timeout, TimeoutError, AssertionError, OSError): + break + seen.setdefault(pid, payload) + return seen + + +def main(): + port = 25599 + listener = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + listener.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + listener.bind(("127.0.0.1", port)) + listener.listen(4) + + def accept_loop(): + try: + sock, peer = listener.accept() + srv.handle(srv.Conn(sock, "%s:%s" % peer)) + except Exception: + pass + + threading.Thread(target=accept_loop, daemon=True).start() + + sock = socket.create_connection(("127.0.0.1", port), timeout=10) + sock.settimeout(10) + results = [] + + handshake = (srv.varint(srv.PROTOCOL) + srv.mc_string("127.0.0.1") + + struct.pack(">H", port) + srv.varint(2)) + send_packet(sock, 0x00, handshake) + results.append(("handshake sent", True)) + + send_packet(sock, 0x00, + srv.mc_string("TestPilot") + + srv.mc_string("00000000-0000-0000-0000-000000000000")) + pid, payload = read_packet(sock) + cursor = srv.Cursor(payload) + uuid_txt = cursor.string() + nick = cursor.string() + results.append(("login success", pid == 0x02 and nick == "TestPilot")) + uuid_ok = len(uuid_txt) in (32, 36) + try: + uuid.UUID(uuid_txt) + except (ValueError, AttributeError): + uuid_ok = False + results.append(("uuid parseable (%d chars)" % len(uuid_txt), uuid_ok)) + + send_packet(sock, 0x03, b"") + seen = drain(sock, {0x01, 0x08, 0x23}) + results.append(("join game received", 0x01 in seen)) + results.append(("spawn position received", 0x08 in seen)) + results.append(("brand received", 0x23 in seen)) + + if 0x01 in seen: + cur = srv.Cursor(seen[0x01]) + entity = struct.unpack(">i", cur.take(4))[0] + gamemode = cur.ubyte() + dimension = struct.unpack(">i", cur.take(4))[0] + cur.ubyte() + cur.ubyte() + level = cur.string() + results.append(("join game parses (entity=%d gm=%d dim=%d %s)" + % (entity, gamemode, dimension, level), + level == srv.WORLD_NAME)) + + if 0x08 in seen: + cur = srv.Cursor(seen[0x08]) + x = struct.unpack(">d", cur.take(8))[0] + y = struct.unpack(">d", cur.take(8))[0] + z = struct.unpack(">d", cur.take(8))[0] + cur.take(8) + cur.ubyte() + tid = cur.varint() + results.append(("spawn parses (%.1f/%.1f/%.1f tid=%d)" + % (x, y, z, tid), y == 64.0 and tid == 0)) + + send_packet(sock, 0x00, srv.varint(0x1234)) + send_packet(sock, 0x03, srv.mc_string("ru_ru") + bytes([8]) + + srv.varint(0) + b"\x01" + bytes([2]) + bytes([127]) + + srv.varint(1)) + send_packet(sock, 0x07, + struct.pack(">dddff?", 0.5, 64.0, 0.5, 0.0, 0.0, True)) + alive = drain(sock, {0x00}, budget=18.0) + results.append(("keep alive flow", 0x00 in alive)) + + sock.close() + listener.close() + + print("== self-test ==") + failed = 0 + for label, ok in results: + print(" %-40s %s" % (label, "OK" if ok else "FAIL")) + failed += 0 if ok else 1 + print(" %d check(s) failed" % failed) + return 1 if failed else 0 + + +if __name__ == "__main__": + sys.exit(main()) \ No newline at end of file diff --git a/testserver/server.py b/testserver/server.py new file mode 100644 index 0000000..3fe436e --- /dev/null +++ b/testserver/server.py @@ -0,0 +1,416 @@ +#!/usr/bin/env python3 +"""Offline stand-in for the RustexRemake server: accepts any nickname and +token and drops the client into an empty world, so the modloader can be +verified end to end without the live server. + +Protocol: Minecraft 1.12.2 (340), no compression, no encryption. +Run: python server.py [--port 25566] [--host 0.0.0.0] +""" + +import argparse +import hashlib +import select +import socket +import struct +import sys +import threading +import time +import uuid as uuidlib + +PROTOCOL = 340 +GAMEMODE_SURVIVAL = 0 +DIMENSION_OVERWORLD = 0 +DIFFICULTY_NORMAL = 1 +WORLD_NAME = "flat" + +CLIENTBOUND_PLAY = { + 0x00: "KEEP_ALIVE", + 0x01: "JOIN_GAME", + 0x06: "SPAWN_POSITION", + 0x08: "PLAYER_POS_LOOK", + 0x23: "PLUGIN_MESSAGE", +} +SERVERBOUND_PLAY = { + 0x00: "KEEP_ALIVE", + 0x01: "CHAT", + 0x02: "CLIENT_STATUS", + 0x03: "CLIENT_SETTINGS", + 0x04: "PLUGIN_MESSAGE", + 0x06: "POSITION", + 0x07: "POSITION_LOOK", + 0x1A: "TELEPORT_CONFIRM", +} + + +class ProtocolError(Exception): + pass + + +class Conn: + def __init__(self, sock, peer): + self.sock = sock + self.peer = peer + self.buf = b"" + + def close(self): + try: + self.sock.close() + except OSError: + pass + + def _fill(self, n): + while len(self.buf) < n: + chunk = self.sock.recv(65536) + if not chunk: + raise ProtocolError("closed by peer") + self.buf += chunk + + def read_exact(self, n): + self._fill(n) + out, self.buf = self.buf[:n], self.buf[n:] + return out + + def read_varint(self): + value = 0 + for shift in range(0, 35, 7): + byte = self.read_exact(1)[0] + value |= (byte & 0x7F) << shift + if not byte & 0x80: + return value + raise ProtocolError("varint too long") + + def read_string(self): + return self.read_exact(self.read_varint()).decode("utf-8", "replace") + + def read_ushort(self): + return struct.unpack(">H", self.read_exact(2))[0] + + def read_packet(self): + length = self.read_varint() + if length <= 0 or length > 2_000_000: + raise ProtocolError("bad packet length %d" % length) + pid = self.read_varint() + payload = self.read_exact(length - varint_size(pid)) + return pid, payload + + def send(self, pid, payload=b""): + body = varint(pid) + payload + self.sock.sendall(varint(len(body)) + body) + + +def varint(value): + out = b"" + while True: + byte = value & 0x7F + value >>= 7 + out += bytes([byte | (0x80 if value else 0)]) + if not value: + return out + + +def varint_size(value): + size = 1 + while value >= 0x80: + value >>= 7 + size += 1 + return size + + +def mc_string(text): + raw = text.encode("utf-8") + return varint(len(raw)) + raw + + +def mc_bool(value): + return b"\x01" if value else b"\x00" + + +def offline_uuid(name): + return uuidlib.uuid3(uuidlib.NAMESPACE_DNS, "OfflinePlayer." + name) + + +def log(name, fmt, *args): + stamp = time.strftime("%H:%M:%S") + sys.stdout.write("[%s] %-12s %s\n" % (stamp, name, fmt % args if args else fmt)) + sys.stdout.flush() + + +def send_status(conn): + payload = ( + mc_string(json_status()) + ) + conn.send(0x00, payload) + + +def json_status(): + return ( + '{"version":{"name":"RustexRemake","protocol":%d},' + '"players":{"max":20,"online":1},' + '"description":{"text":"rsx modloader test server"}}' % PROTOCOL + ) + + +def send_keep_alive(conn, ident): + conn.send(0x00, varint(ident & 0x7FFFFFFF)) + + +def send_join_game(conn, entity_id): + payload = b"".join([ + struct.pack(">i", entity_id), + bytes([GAMEMODE_SURVIVAL]), + struct.pack(">i", DIMENSION_OVERWORLD), + bytes([DIFFICULTY_NORMAL]), + bytes([20]), + mc_string(WORLD_NAME), + mc_bool(False), + ]) + conn.send(0x01, payload) + + +def send_spawn_position(conn, x=0.5, y=64.0, z=0.5): + payload = struct.pack(">ddd", x, y, z) + conn.send(0x06, payload) + + +def send_pos_look(conn, x, y, z, yaw, pitch, teleport_id): + payload = b"".join([ + struct.pack(">ddd", x, y, z), + struct.pack(">ff", yaw, pitch), + bytes([0]), + varint(teleport_id), + ]) + conn.send(0x08, payload) + + +def send_brand(conn, brand): + inner = mc_string(brand) + conn.send(0x23, mc_string("MC|Brand") + varint(len(inner)) + inner) + + +def handle(conn): + name = None + entity_id = None + teleport_id = 0 + keepalive_id = 0x1234 + last_keepalive = 0.0 + try: + pid, payload = conn.read_packet() + if pid != 0x00: + raise ProtocolError("expected handshake, got %d" % pid) + cursor = Cursor(payload) + protocol = cursor.varint() + host = cursor.string() + port = cursor.ushort() + next_state = cursor.varint() + log("handshake", "protocol=%d host=%s port=%d next_state=%d", + protocol, host, port, next_state) + + if next_state == 1: + pid, _ = conn.read_packet() + send_status(conn) + log("status", "ping answered") + return + if next_state != 2: + raise ProtocolError("unsupported next_state %d" % next_state) + + pid, payload = conn.read_packet() + if pid != 0x00: + raise ProtocolError("expected login start, got %d" % pid) + cursor = Cursor(payload) + name = cursor.string() + profile_id = None + if cursor.remaining() > 0: + try: + profile_id = cursor.string() + except ProtocolError: + pass + if name is None: + raise ProtocolError("no nickname") + profile_id = profile_id or str(offline_uuid(name)).replace("-", "") + log("login", "nick=%r token-ignored uuid=%s", name, profile_id) + + conn.send(0x02, mc_string(profile_id) + mc_string(name)) + log("login", "login success sent, any token accepted") + + deadline = time.time() + 20 + while time.time() < deadline: + pid, payload = conn.read_packet() + if pid == 0x03: + log("login", "client acknowledged") + break + if pid == 0x00: + continue + log("login", "unexpected packet 0x%02X before play" % pid) + else: + raise ProtocolError("no login acknowledgement") + + entity_id = int.from_bytes(hashlib.sha256(name.encode()).digest()[:4], + "big") & 0x7FFFFFFF + send_brand(conn, "rsx-testserver") + send_join_game(conn, entity_id) + send_pos_look(conn, 0.5, 64.0, 0.5, 0.0, 0.0, teleport_id) + log("play", "join game sent, entity=%d, spawn sent" % entity_id) + + while True: + if time.time() - last_keepalive > 15: + last_keepalive = time.time() + keepalive_id = (keepalive_id + 1) & 0x7FFFFFFF + send_keep_alive(conn, keepalive_id) + + pid, payload = conn.read_packet() + label = SERVERBOUND_PLAY.get(pid, "0x%02X" % pid) + if pid == 0x00: + send_keep_alive(conn, keepalive_id) + log("play", "keep alive") + elif pid == 0x1A: + log("play", "teleport confirmed") + teleport_id += 1 + send_pos_look(conn, 0.5, 64.0, 0.5, 0.0, 0.0, teleport_id) + log("play", "position sent after teleport confirm") + elif pid == 0x02: + log("play", "client status (respawn?): %s", payload.hex()) + elif pid == 0x07: + log("play", "player position+look received") + else: + log("play", "%s (%d bytes)", label, len(payload)) + + except ProtocolError as exc: + log("close", "%s: %s", conn.peer, exc) + except OSError as exc: + log("close", "%s: %s", conn.peer, exc) + except Exception as exc: # noqa: BLE001 - stand-in server, log and move on + log("error", "%s: %r", conn.peer, exc) + finally: + if name: + log("bye", "nick=%r entity=%s", name, entity_id) + conn.close() + + +class Cursor: + def __init__(self, data): + self.data = data + self.pos = 0 + + def remaining(self): + return len(self.data) - self.pos + + def take(self, n): + if self.pos + n > len(self.data): + raise ProtocolError("packet truncated") + out = self.data[self.pos:self.pos + n] + self.pos += n + return out + + def byte(self): + return self.take(1)[0] + + def ubyte(self): + return self.byte() + + def ushort(self): + return struct.unpack(">H", self.take(2))[0] + + def varint(self): + value = 0 + for shift in range(0, 35, 7): + byte = self.byte() + value |= (byte & 0x7F) << shift + if not byte & 0x80: + return value + raise ProtocolError("varint too long") + + def string(self): + return self.take(self.varint()).decode("utf-8", "replace") + + +def parse_ports(spec): + ports = [] + for chunk in spec.split(","): + chunk = chunk.strip() + if "-" in chunk: + first, last = chunk.split("-", 1) + ports.extend(range(int(first), int(last) + 1)) + elif chunk: + ports.append(int(chunk)) + return ports + + +def serve_ping(ports, host): + """The client asks http:///server-ping for its server list and reads + lines of port~mode~x~y. 'Offline' skips the per-server ping, which is what + we want: the stand-in has nothing to measure.""" + body = "".join("%d~Offline~0~0\n" % port for port in ports) + try: + from http.server import BaseHTTPRequestHandler, HTTPServer + except ImportError: + log("ping", "http.server unavailable, ping endpoint disabled") + return None + + class Handler(BaseHTTPRequestHandler): + def do_GET(self): # noqa: N802 - required by BaseHTTPRequestHandler + payload = body.encode("utf-8") + self.send_response(200) + self.send_header("Content-Type", "text/plain; charset=utf-8") + self.send_header("Content-Length", str(len(payload))) + self.end_headers() + self.wfile.write(payload) + + def log_message(self, fmt, *args): + log("ping", self.path) + + try: + httpd = HTTPServer((host, 80), Handler) + except OSError as exc: + log("ping", "cannot listen on port 80 (%s); list will stay empty" % exc) + return None + threading.Thread(target=httpd.serve_forever, daemon=True).start() + log("ping", "serving /server-ping on %s:80 with %d server(s)" + % (host, len(ports))) + return httpd + + +def main(): + parser = argparse.ArgumentParser(description=__doc__) + parser.add_argument("--host", default="0.0.0.0") + parser.add_argument("--ports", default="25566", + help="ports or ranges, e.g. 25566-25573") + parser.add_argument("--no-http", action="store_true", + help="do not answer the client server-ping request") + args = parser.parse_args() + + ports = parse_ports(args.ports) + listeners = [] + for port in ports: + sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + sock.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1) + try: + sock.bind((args.host, port)) + except OSError as exc: + log("server", "cannot bind %s:%d (%s)" % (args.host, port, exc)) + sock.close() + continue + sock.listen(8) + listeners.append(sock) + log("server", "listening on %s:%d, any nick/token accepted", + args.host, port) + + if not args.no_http: + serve_ping(ports, args.host) + + try: + while True: + ready, _, _ = select.select(listeners, [], [], 1.0) + for listener in ready: + sock, peer = listener.accept() + conn = Conn(sock, "%s:%s" % peer) + threading.Thread(target=handle, args=(conn,), + daemon=True).start() + except KeyboardInterrupt: + log("server", "interrupted") + finally: + for listener in listeners: + listener.close() + + +if __name__ == "__main__": + main() \ No newline at end of file diff --git a/third_party/asm/asm-9.7.jar b/third_party/asm/asm-9.7.jar new file mode 100644 index 0000000000000000000000000000000000000000..fee9b028a3364169c659f6072ed53f9f09cb524d GIT binary patch literal 125428 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 XdO}IU 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 literal 0 HcmV?d00001 diff --git a/third_party/asm/asm-commons-9.7.jar b/third_party/asm/asm-commons-9.7.jar new file mode 100644 index 0000000000000000000000000000000000000000..6a7d3a1083c46f9135c70208ea18423dbd2d19eb GIT binary patch literal 73426 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 +powershell -NoProfile -ExecutionPolicy Bypass -File "%~dp0scripts\install.ps1" --uninstall %* +pause