Compare commits

..

3 Commits

3 changed files with 34 additions and 1 deletions

View File

@@ -58,6 +58,13 @@ load: gunzip -> XOR decrypt -> Newtonsoft-BSON parse
If a game update changes the key, recover it with no RE via `walker/recover_key.py`.
- `pymongo`'s `bson.encode` reproduces Newtonsoft.Bson byte-for-byte, so decode→encode is identity.
### Walker naming convention
A walker's display name is **two indices**, not a string: top-level `firstNameIndex` + `secondNameIndex`
(BSON int32, **031 each**). Resolve them via `name_index.json``first_name` / `second_name` tables
(e.g. `(16,5)` = "Veteran Veteran", second `6` = "…Beast"). The top-level `name` field is **null/unused**
— the shown name comes from the indices. "name1" = `firstNameIndex`, "name2" = `secondNameIndex`. Set
both with `build_wbt.py rename <wbt> <first> <second> -o out`, or edit the index directly when copying.
### The 5 hashes (a `.wbt` is a serialized `WalkerBlueprintDto`)
All = `MD5(UTF8(JsonConvert.SerializeObject(obj))).hexUPPER` — Newtonsoft compact JSON: no whitespace,
@@ -157,7 +164,7 @@ All use UnityPy with an IL2CPP TypeTreeGenerator (`GameAssembly.dll` + `global-m
- **`TASK.md`** — `.wbt` format cracked (BSON-verified) summary.
- **`PRODUCTION_LINES.md`**, **`SALES_VALUE.md`**, **`WEAPON_DAMAGE.md`** — static-data location maps (track across updates).
- **`SCRAPE_RUNBOOK.md`** — read-only live-scrape steps for when a playtest is online.
- **`GHIDRA.md`** — headless Ghidra on `GameAssembly.dll`: **inject Il2CppDumper symbols, don't full-analyze** (`ghidra/scripts/apply_il2cpp_symbols.py`); targeted decompile/disasm; the `_JAVA_OPTIONS` heap gotcha.
- **`GHIDRA.md`** — headless Ghidra on `GameAssembly.dll`: **inject Il2CppDumper symbols, don't full-analyze** (`ghidra/scripts/apply_il2cpp_symbols.py`); targeted decompile/disasm; the `_JAVA_OPTIONS` heap gotcha. **The named DB is already built at `ghidra/project/SAND`** (564k methods, git-ignored/local) — decompile any function on demand via `-process … -postScript decomp_targets.py`.
- **`BUNDLES.md`** (repo root) — inventory of the 35 asset bundles.
Operator memory lives in `~/.claude/projects/-home-downloadpizza-sand-tools/memory/` (loaded each session).

View File

@@ -3,6 +3,13 @@
How to get a workable Ghidra database for the client, and the **big lesson**: for an IL2CPP binary
you **inject the symbol table from Il2CppDumper** — you do *not* sit through full auto-analysis.
> **CURRENT STATE (2026-06-16): the DB is already built and ready** at `ghidra/project/SAND`
> (~945 MB, **564,713 methods named**, 294,174 function boundaries, 32,958 string labels; symbol-inject,
> no auto-analysis). `ghidra/` is git-ignored so it's local/machine-specific — if it's missing, rebuild
> with the import command below (~17 min). Decompile any target right now via the `-process` command in
> "After the DB exists". (First real use: confirmed the master-server WS has **no cert pinning** — see
> `docs/MASTER_SERVER.md` / TLS notes.)
## Inputs (all already on disk)
- Binary: `/mnt/d/SteamLibrary/steamapps/common/Sand Playtest/GameAssembly.dll` (~137 MB).
- **Il2CppDumper ("yoten")**: `/mnt/c/Users/downloadpizza/Downloads/yoten/` — produces, for the

View File

@@ -12,6 +12,25 @@ and the formula function (RVAs below); the literal constants need a different me
end). This corrects an earlier draft that wrongly concluded "no value exists" — the values
**are** live at runtime; they just aren't statically anchorable constants.
**Confirmed 2026-06-16 (offline, `bundle/dump_blueprint.py`): the `Damage*DataComponent`s are
NOT authored on the item/ammo EntityBlueprints in the bundles.** Decoded `item_grenadeContact`,
`item_shotgunAmmo`, `item_pistolAmmo`, `item_shotgun`, `item_revolverSmall_dusters` — every one
has only generic components (InteractActions, Count, ItemName, ItemType, NiceName, View,
ViewSize, colliders, Physics); **zero** `Damage{Physical,…}DataComponent` / `MeleeDataComponent`
/ AoE. The only `.value` floats present are `ViewSizeDataComponent` (~0.30.97), not damage. So
`GetDamage`'s `DamageXxxDataComponent.value` reads are populated **at runtime (server-authoritative)**
— there is no per-weapon damage constant in the bundles *or* as a static anchor in the DLL.
**Ways to get actual base numbers, ranked:**
-**In-game empirical measurement** (controlled damage tests) — the only clean route.
- ⚠️ Live-client runtime memory (the components hold real values once spawned) — but that's
process inspection → **BattlEye / no injection** → off-limits.
- ❌ Static extraction (bundles) — values absent (proven above).
- ❌ Static decompile constant — none exists (generic Entitas dispatch).
- ❌ Master-server query — no damage field / no stats endpoint (see [MASTER_SERVER.md](MASTER_SERVER.md)).
- ❓ Game-server (not master) entity-snapshot capture *might* carry component values, but unverified
and the server may only transmit results, not per-weapon stats.
## Damage model (all static, all in `il2cpp/dump.cs` + verified by disasm)
Per-type damage lives as a `float value` (object offset **+0x10**) on 8 components on the