diff --git a/game-fork/patches/decompiler-fixes.txt b/game-fork/patches/decompiler-fixes.txt index 6463d64..11cf703 100644 --- a/game-fork/patches/decompiler-fixes.txt +++ b/game-fork/patches/decompiler-fixes.txt @@ -1039,15 +1039,6 @@ public void sendChatMessage(String s, boolean flag) { this.mc.player.sendChatMessage(s); } -=== FILE net/minecraft/client/entity/EntityPlayerSP.java ---- BEFORE -public void onLivingUpdate() { - ++this.sprintingTicksLeft; ---- AFTER -public void onLivingUpdate() { - net.rustnotmc.client.RsxDebug.movement(this); - ++this.sprintingTicksLeft; - === FILE net/minecraft/entity/Entity.java --- BEFORE this.collidedHorizontally = d7 != d0 || d9 != d2; @@ -1098,25 +1089,4 @@ boolean flag = this.onGround || d1 != d1 && d1 < 0.0D; --- AFTER boolean flag = this.onGround || d8 != d1 && d8 < 0.0D; -=== FILE net/minecraft/client/audio/SoundHandler.java ---- BEFORE -Map map = this.getSoundMap(iresource.getInputStream()); ---- AFTER -Map map = this.getSoundMap(iresource.getInputStream()); - net.rustnotmc.client.RsxDebug.sound("parsed=" + (map == null ? "null" : String.valueOf(map.size()))); -=== FILE net/minecraft/client/audio/SoundHandler.java ---- BEFORE -List list = iresourcemanager.getAllResources(new ResourceLocation(s, "sounds.json")); ---- AFTER -List list = iresourcemanager.getAllResources(new ResourceLocation(s, "sounds.json")); - net.rustnotmc.client.RsxDebug.sound("domain=" + s + " resources=" + list.size()); - -=== FILE net/minecraft/client/audio/SoundHandler.java ---- BEFORE -this.soundRegistry.clearMap(); - Iterator iterator = iresourcemanager.getResourceDomains().iterator(); ---- AFTER -this.soundRegistry.clearMap(); - net.rustnotmc.client.RsxDebug.sound("domains=" + iresourcemanager.getResourceDomains()); - Iterator iterator = iresourcemanager.getResourceDomains().iterator(); diff --git a/game-fork/src-overlay/net/rustnotmc/client/RsxDebug.java b/game-fork/src-overlay/net/rustnotmc/client/RsxDebug.java deleted file mode 100644 index c4baa8b..0000000 --- a/game-fork/src-overlay/net/rustnotmc/client/RsxDebug.java +++ /dev/null @@ -1,72 +0,0 @@ -package net.rustnotmc.client; - -import net.rustnotmc.loader.Log; - -/** - * Temporary diagnostics, added to work out why jumping and flight misbehave. - * - * Static analysis kept producing confident and wrong answers about this path, so - * the state is measured instead. Delete this file and its patch entry once the - * movement bugs are closed. - */ -public final class RsxDebug { - - private static int ticks; - - private RsxDebug() { - } - - /** One-off trace for the empty sound registry. */ - public static void sound(String message) { - Log.info("DBG snd " + message); - } - - /** Called from EntityPlayerSP.onLivingUpdate, once a second. */ - public static void movement(Object self) { - if (++ticks % 20 != 0) { - return; - } - Log.info("DBG sp onGround=" + read(self, "onGround") - + " inJump=" + read(self, "movementInput") - + " isJumping=" + read(self, "isJumping") - + " riding=" + read(self, "isRiding") - + " srvWorld=" + read(self, "isServerWorld") - + " allowFly=" + read(self, "allowFlying") - + " flying=" + read(self, "isFlying") - + " mY=" + read(self, "motionY") - + " y=" + read(self, "posY")); - } - - /** - * Reads a field by name. - * - * Deliberately reflective and deliberately forgiving: a diagnostic that - * throws when a field is renamed is worse than one that prints null. - */ - private static String read(Object target, String field) { - if (target == null) { - return "?"; - } - try { - java.lang.reflect.Field f = findField(target.getClass(), field); - if (f == null) { - return "?"; - } - f.setAccessible(true); - return String.valueOf(f.get(target)); - } catch (Throwable t) { - return "!"; - } - } - - private static java.lang.reflect.Field findField(Class type, String name) { - while (type != null) { - try { - return type.getDeclaredField(name); - } catch (NoSuchFieldException e) { - type = type.getSuperclass(); - } - } - return null; - } -} \ No newline at end of file diff --git a/rsx-client/scripts/run-game.ps1 b/rsx-client/scripts/run-game.ps1 index a9c006f..ef826d9 100644 --- a/rsx-client/scripts/run-game.ps1 +++ b/rsx-client/scripts/run-game.ps1 @@ -28,7 +28,16 @@ if (-not $Java) { } if (-not $Java) { throw 'no Java 17 found' } -$assets = "$env:APPDATA\AstralRinthApp\meta\assets" +# The launcher's asset store is index-based: indexes/1.12.json pointing at +# objects//. A 1.12.2 client wants /minecraft/ and +# will not look in either of those. Pointing --assetsDir at the store root +# leaves the game running and looking correct, because language and textures +# come from the jar, while every sound is silently missing. +$store = "$env:APPDATA\AstralRinthApp\meta\assets" +$assets = Join-Path $Run 'assets' +& python (Join-Path $root 'rsx-client\tools\materialize_assets.py') $store $assets --index 1.12 +if ($LASTEXITCODE -ne 0) { throw 'asset materialisation failed' } + $cp = (Get-Content (Join-Path $Run 'classpath.txt') -Raw).Trim() $natives = Join-Path $Run 'natives' @@ -46,7 +55,6 @@ $javaArgs += '--username'; $javaArgs += 'Player' $javaArgs += '--version'; $javaArgs += '1.12.2' $javaArgs += '--gameDir'; $javaArgs += $Run $javaArgs += '--assetsDir'; $javaArgs += $assets -$javaArgs += '--assetIndex'; $javaArgs += '1.12' $javaArgs += '--uuid'; $javaArgs += '00000000000000000000000000000000' $javaArgs += '--accessToken'; $javaArgs += '0' $javaArgs += '--userType'; $javaArgs += 'legacy' diff --git a/rsx-client/tools/materialize_assets.py b/rsx-client/tools/materialize_assets.py new file mode 100644 index 0000000..d18995a --- /dev/null +++ b/rsx-client/tools/materialize_assets.py @@ -0,0 +1,90 @@ +#!/usr/bin/env python3 +"""Materialise a 1.12 asset tree out of a hash-addressed asset store. + +Minecraft 1.12.2 does not read an index plus an object store. It reads +``/minecraft/`` directly. A launcher such as AstralRinth keeps +assets the modern way, as ``indexes/1.12.json`` pointing at +``objects//``, and a launcher that wants them for an old client is +responsible for laying them out. + +Passing the store root as ``--assetsDir`` does not fail loudly. Texts and +textures still appear, because those live inside the client jar, so the game +looks correct while every sound is silently absent: nothing requested is ever +found on disk. + +Usage: + materialize_assets.py [--index 1.12] + +Hard links are used where the filesystem allows it, so the materialised tree +costs almost nothing and repeated runs are cheap. +""" + +import argparse +import json +import os +import sys + + +def human(count): + return "{:,}".format(count).replace(",", " ") + + +def main(argv): + ap = argparse.ArgumentParser(description=__doc__, + formatter_class=argparse.RawDescriptionHelpFormatter) + ap.add_argument("meta_assets", help="store root holding indexes/ and objects/") + ap.add_argument("out", help="assets dir to create for the client") + ap.add_argument("--index", default="1.12", help="index file name (default: 1.12)") + args = ap.parse_args(argv) + + meta = args.meta_assets + index_path = os.path.join(meta, "indexes", args.index + ".json") + if not os.path.isfile(index_path): + sys.exit("no asset index at " + index_path) + + with open(index_path, "r", encoding="utf-8") as fh: + objects = json.load(fh)["objects"] + + out = args.out + linked = copied = reused = 0 + missing = [] + + for name, info in sorted(objects.items()): + digest = info["hash"] + src = os.path.join(meta, "objects", digest[:2], digest) + dst = os.path.join(out, *name.split("/")) + + if os.path.isfile(src) and os.path.getsize(src) == info["size"]: + if os.path.exists(dst) and os.path.getsize(dst) == info["size"]: + reused += 1 + continue + os.makedirs(os.path.dirname(dst), exist_ok=True) + if os.path.exists(dst): + os.remove(dst) + try: + os.link(src, dst) + linked += 1 + except OSError: + with open(src, "rb") as r, open(dst, "wb") as w: + w.write(r.read()) + copied += 1 + else: + missing.append(name) + + sounds = sum(1 for n in objects if n.endswith(".ogg")) + print("index : {} ({} objects, {} ogg)".format( + os.path.join("indexes", args.index + ".json"), human(len(objects)), human(sounds))) + print("output : {}".format(out)) + print("hardlink: {} copy: {} reused: {}".format( + human(linked), human(copied), human(reused))) + if missing: + print("MISSING : {} object(s) not in the store".format(human(len(missing)))) + for name in missing[:10]: + print(" " + name) + return 1 + print("ok : every indexed object is present") + return 0 + + +if __name__ == "__main__": + raise SystemExit(main(sys.argv[1:])) \ No newline at end of file