#!/usr/bin/env python3 """Set the emulated console's language by editing canary's own persisted XConfig. There is no `--user_language` flag in this tree: the cvar is DECLARE_int32 at four call sites with no DEFINE, and it is absent from xenia-canary.config.toml. ⚠ Do NOT pass it anyway -- xenia calls ShowSimpleMessageBox from ParseLaunchArguments BEFORE logging starts, so an unknown flag blocks forever with an empty log (see run-canary's header). The supported route is the file. kernel_state.cc builds XConfig over `/xconfig.settings`; SetDefaults() hard-codes language = kEnglish, and whatever is in the file wins. The offset is NOT hard-coded here -- it is located from struct landmarks every run, so this keeps working if the layout moves: music_volume = 0.7f at User+449 -> gives the User base language = u32 at User+44 -> must currently read a valid XLanguage country = u8 at User+64 -> sanity check set_console_language.py ja # or: en, or a raw integer set_console_language.py --restore # put back the .bak this wrote XLanguage (xbox.h): 1 en, 2 ja, 3 de, 4 fr, 5 es, 6 it, 7 ko, 8 zh-TW, 9 pt. Restore when you are done: other captures in this corpus assume English. """ import struct, sys, shutil, pathlib PATH = pathlib.Path("/sylph-home/re/.local/share/Xenia/xconfig.settings") BAK = PATH.with_suffix(".settings.agent-bak") LANGS = {"en": 1, "ja": 2, "de": 3, "fr": 4, "es": 5, "it": 6, "ko": 7, "zh": 8, "pt": 9} def find_language_offset(d): """User base from the music_volume landmark; language sits 405 bytes before.""" for o in range(len(d) - 4): if abs(struct.unpack_from(">f", d, o)[0] - 0.7) < 1e-6: user = o - 449 if user < 0: continue lang = user + 44 cur = struct.unpack_from(">I", d, lang)[0] if 1 <= cur <= 12: # a plausible XLanguage return lang, cur, d[user + 64] raise SystemExit("could not locate the User block -- layout changed?") def main(): arg = sys.argv[1] if len(sys.argv) > 1 else "--show" if arg == "--restore": if not BAK.exists(): raise SystemExit("no backup to restore") shutil.copy2(BAK, PATH) d = PATH.read_bytes() off, cur, _ = find_language_offset(d) print(f"restored; language at 0x{off:x} is now {cur}") return d = bytearray(PATH.read_bytes()) off, cur, country = find_language_offset(bytes(d)) print(f"language at 0x{off:x} = {cur} (country byte = {country})") if arg == "--show": return want = LANGS.get(arg, None) if want is None: want = int(arg) if not BAK.exists(): shutil.copy2(PATH, BAK) print(f"backed up -> {BAK}") struct.pack_into(">I", d, off, want) PATH.write_bytes(bytes(d)) print(f"language {cur} -> {want}") if __name__ == "__main__": main()