#!/usr/bin/env python3
"""Dump the raw Odin SerializedBytes for the two LootTablesConfig assets, and do a
first-pass analysis: hexdump head, and list ASCII strings (>=3 chars) found."""
import os, sys, json, re, UnityPy
from UnityPy.helpers.TypeTreeGenerator import TypeTreeGenerator

GAME = "/mnt/d/SteamLibrary/steamapps/common/Sand Playtest"
BD = os.path.join(GAME, "Sand_Data/StreamingAssets/aa/StandaloneWindows64")
META = os.path.join(GAME, "Sand_Data/il2cpp_data/Metadata/global-metadata.dat")
DLL = os.path.join(GAME, "GameAssembly.dll")
OUT = "/home/downloadpizza/sand_tools/extracted"

gen = TypeTreeGenerator("6000.0.40f1")
gen.load_il2cpp(open(DLL, "rb").read(), open(META, "rb").read())
env = UnityPy.load(os.path.join(BD, "configuration_assets_all.bundle"),
                   os.path.join(BD, "sand_monoscripts.bundle"))

for o in env.objects:
    if o.type.name != "MonoBehaviour":
        continue
    try:
        d = o.read(); nm = getattr(d, "m_Name", "") or ""
    except Exception:
        continue
    if "LootTables" not in nm:
        continue
    script = d.m_Script.read()
    full = (script.m_Namespace + "." if script.m_Namespace else "") + script.m_ClassName
    nodes = json.loads(gen.get_nodes_as_json(script.m_AssemblyName, full))
    tree = o.read_typetree(nodes)
    sb = tree["serializationData"]["SerializedBytes"]
    data = bytes(sb)
    out_bin = os.path.join(OUT, f"{nm}.odin.bin")
    open(out_bin, "wb").write(data)
    print(f"\n=== {nm}: {len(data)} bytes -> {out_bin}")
    print("head hex:", data[:64].hex())
    # ascii strings
    strings = re.findall(rb"[\x20-\x7e]{3,}", data)
    uniq = []
    seen = set()
    for s in strings:
        t = s.decode()
        if t not in seen:
            seen.add(t); uniq.append(t)
    print(f"{len(strings)} ascii runs, {len(uniq)} unique. First 60 unique:")
    for t in uniq[:60]:
        print("   ", repr(t))
