tools: SAND .wbt + game-data extraction scripts
Python tooling for decoding walker saves and mining game data: sand.py / build_wbt.py / walker_hashes.py / harvest_hashes.py (.wbt codec + hashes), extract_*/loot_probe/odin_read/unitybundle (asset parsing), make_*_wiki + render_wiki (wiki generation), recover_key. Paths point at the local extracted/, wiki/, and Walkers symlink.
This commit is contained in:
47
dump_loot_bytes.py
Normal file
47
dump_loot_bytes.py
Normal file
@@ -0,0 +1,47 @@
|
||||
#!/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))
|
||||
Reference in New Issue
Block a user