read what the binary says about itself: names, signatures, prototypes; gen v2
This commit is contained in:
parent
54ef572202
commit
c458b4cb50
34 changed files with 58363 additions and 192 deletions
|
|
@ -2,7 +2,7 @@
|
|||
|
||||
Render a published [source2rosetta](../../README.md) gamedata release into whatever format your framework
|
||||
reads. `source2rosetta` does the hard part — deriving CS2 / Dota 2 gamedata from the stripped engine and
|
||||
validating it on a live server — and publishes two JSON files per game. `source2rosetta-gen` turns those into
|
||||
validating it on a live server — and publishes a small set of JSON files per game. `source2rosetta-gen` turns those into
|
||||
CounterStrikeSharp, Metamod/SourceMod, ModSharp, Swiftly, Plugify, or a typed C# SDK, locally, in a second.
|
||||
|
||||
It's deliberately tiny: it links only `source2rosetta-core` (serde + the format emitters) — **no** ELF reader,
|
||||
|
|
@ -23,10 +23,19 @@ does **not** build it — use `-p source2rosetta-core` or `--workspace`.)
|
|||
|
||||
## Use it
|
||||
|
||||
Download the two artifacts for your game from the release page:
|
||||
Three of the published artifacts are `gen` inputs, one per `--` flag:
|
||||
|
||||
- `gamedata-<game>.json` — the derived gamedata (function signatures + vtable offsets), tiered by confidence.
|
||||
- `netvars-<game>.json` — the typed schema (every class's field offsets + runtime types).
|
||||
- `gamedata-<game>.json` (`--from`) — the derived gamedata (function signatures + vtable offsets), tiered by confidence.
|
||||
- `netvars-<game>.json` (`--netvars`) — the typed schema (field offsets + runtime types, plus the class base
|
||||
graph and per-type sizes).
|
||||
- `abi-<game>.json` (`--abi`) — declared parameter and return types, each re-judged against the footprint
|
||||
measured in that build. This is what a function TAKES, as opposed to where it is. See
|
||||
[Call shapes](#call-shapes----abi-abi-gamejson).
|
||||
|
||||
`bindings-<game>.json` ships beside them and `gen` does **not** render it — it is not locator data. It is
|
||||
what the binary declares about itself, in five sections: Pulse bindings (display name, description, call
|
||||
policy, and each binding's typed signature), entity-IO inputs and outputs, map-classname → C++ class, and
|
||||
console commands. Plain JSON, readable as-is.
|
||||
|
||||
Then point `gen` at whichever you need and pick a `--format`. Output goes to `--out`, or stdout if omitted.
|
||||
|
||||
|
|
@ -51,15 +60,69 @@ source2rosetta-gen --netvars netvars-cs2.json --format netvars --out netvars.jso
|
|||
|
||||
| `--format` | needs | output |
|
||||
|---|---|---|
|
||||
| `cssharp` *(default)* | `--from` | CounterStrikeSharp combined gamedata (a commented, sectioned file) |
|
||||
| `cssharp` *(default)* | `--from` | CounterStrikeSharp combined gamedata — **JSONC**: banner comments mean a strict JSON parser will reject it |
|
||||
| `metamod` | `--from` | Metamod:Source / SourceMod gamedata VDF (`.games.txt`) |
|
||||
| `modsharp` | `--from` | ModSharp gamedata JSON |
|
||||
| `swiftly` | `--from` | Swiftly gamedata JSON |
|
||||
| `swiftly` | `--from` | Swiftly gamedata JSON — **signature entries only**; vtable-offset entries are omitted, because that framework takes offsets through a separate file |
|
||||
| `plugify` | `--from` | Plugify gamedata JSON |
|
||||
| `model` | `--from` | the canonical model, re-serialized (format-neutral) |
|
||||
| `model` | `--from` | the selected tiers flattened to one name → locator map (format-neutral; not a re-readable monolith) |
|
||||
| `cs-sdk` | `--netvars` | typed C# SDK — `static class` per schema class, `const int` field offsets tagged with their type |
|
||||
| `netvars` | `--netvars` | flat schema map, `{ class: { field: offset } }` |
|
||||
|
||||
### Call shapes — `--abi abi-<game>.json`
|
||||
|
||||
The same framework ids, a different input: `--abi` renders **how to call** a function rather than where it
|
||||
is. The input picks the family, so `--abi … --format cssharp` emits typed call sites while
|
||||
`--from … --format cssharp` emits the gamedata those calls resolve through.
|
||||
|
||||
All five framework ids work here, exactly as they do for `--from`:
|
||||
|
||||
```sh
|
||||
source2rosetta-gen --abi abi-cs2.json --format cssharp --out RosettaFunctions.cs
|
||||
source2rosetta-gen --abi abi-cs2.json --format metamod --out rosetta_prototypes.h
|
||||
source2rosetta-gen --abi abi-cs2.json --format modsharp --out RosettaCalls.cs
|
||||
source2rosetta-gen --abi abi-cs2.json --format swiftly --out prototypes.json
|
||||
source2rosetta-gen --abi abi-cs2.json --format plugify --out prototypes.json
|
||||
```
|
||||
|
||||
| `--format` | output |
|
||||
|---|---|
|
||||
| `cssharp` | C# `MemoryFunction*` fields (signature) / `VirtualFunction*` factories (vtable slot) |
|
||||
| `metamod` | C++ header of `using X_t = RET (*)(…)`, plus an `X_vtidx` constant for a slot — Metamod plugins are C++ and take the **declared** types verbatim |
|
||||
| `modsharp` | C# `[AddressKey]` interface for its Roslyn generator (signature) + a vtable-dispatch class (slot) |
|
||||
| `swiftly` | JSON per-function type descriptors (`{"args":"ppf","ret":"v","call":"address"}`) |
|
||||
| `plugify` | JSON runtime type arrays (`{"paramTypes":["pointer","string","float"],"retType":"void"}`) |
|
||||
|
||||
Source for the two C# targets and for C++ because their type lists are **compile-time**; data for Swiftly
|
||||
and Plugify because theirs are resolved at runtime.
|
||||
|
||||
**The two locator forms are not interchangeable, and every output distinguishes them.** A signature
|
||||
resolves to one address; a vtable slot is entered through the object, so the framework reaches it by a
|
||||
different call entirely — `VirtualFunctionVoid(instance, slot)` rather than `GameData.GetSignature(key)`,
|
||||
`GetVFuncIndex` rather than `GetAddress`, `(*(void***)self)[idx]` rather than a scanned pointer. Roughly
|
||||
a quarter of a LIVE-derived manifest's call sites are vtable-located, so binding them all through the
|
||||
signature path would look up keys that live in the gamedata's `offsets` section and never in its
|
||||
`signatures` one.
|
||||
|
||||
An **offline**-derived manifest emits none through the vtable path at all: a slot is recorded only once
|
||||
live validation has confirmed it is really a vtable slot and not a carried member offset, so an offline
|
||||
run states no slot rather than guess one. Same artifact shape, fewer vtable call sites — worth knowing
|
||||
before diffing two manifests produced different ways.
|
||||
|
||||
**The receiver is always in the type list.** Where the declaration came from an Itanium-mangled symbol
|
||||
`this` is invisible, so it is prepended, spelled from the function's own class (`CBaseEntity*`, not
|
||||
`void*`) and marked `[this]` in the C++ header. It is a real register in the call frame — leaving it out
|
||||
shifts every argument by one.
|
||||
|
||||
Only functions the deriver could stand behind are emitted: `status: verified` **or `lower-bound`** (the
|
||||
declaration passes registers the callee never reads and contradicts it in none — safe to call, and
|
||||
marked as such in every output), a receiver settled by evidence (the declaration names it, a
|
||||
live-validated vtable slot proves it, or the measurement independently agrees), and every parameter
|
||||
mappable onto an ABI class. A function whose return **nobody
|
||||
declared** is still emitted — otherwise Dota would lose 2,304 of its 3,732 call sites — but it is marked as such in every
|
||||
output (prose in the generated source, `ret_declared` / `retDeclared` in the data), and the value is
|
||||
documented as the raw return register rather than a typed result.
|
||||
|
||||
## Confidence tier
|
||||
|
||||
The gamedata formats (the `--from` ones) take a `--tier`, cumulative and defaulting to `high_confidence`:
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue