Dumpception
SDK dumping is a slog. Run an external dumper, get a 50MB JSON, ctrl-F through it. Different game, different engine, different dumper. I wanted something that lives inside the IDE, runs against the live process, dumps any engine I'd care to look at, and writes it to a website I can actually browse.
So: AngelScript script in Perception on one end, SvelteKit web app on the other. Five engine backends behind a common interface.
Engines supported
- Unreal Engine 3 → 5.7 – every property layout and
GNameschunking variant since UDK. - Source 1 – CS:GO, TF2, L4D2, the GoldSrc descendants on the original Source SDK.
- Source 2 – CS2, Dota 2, Half-Life: Alyx. Schema system instead of property tables.
- Unity IL2CPP – ahead-of-time-compiled Unity. Walks the IL2CPP metadata to recover class info that no longer exists at runtime in the C# sense.
- Unity Mono – classic Mono-runtime Unity, full reflection still intact.
The detection layer fingerprints the running process and routes to the right backend. Each engine module lives under source/engines/<engine>/ and implements the same walker interface.
How it works
The script attaches, fingerprints the engine, and walks whatever type system that engine exposes. For UE that's the UObject tree starting from GObjects. For Source 1 it's the entity factory tables and the datamap chain. For Source 2 it's the schema system and SchemaSystem_001. For Unity it's the runtime class table (Mono) or the IL2CPP metadata blob.
Whatever the engine, the output normalises to the same JSON shape: a list of classes, structs, enums, with their fields, methods, offsets, and parents. That JSON is the contract between the script and the website (source/output/json.as on the script, web/src/lib/types/schema.ts on the site). Any schema change has to land in both files at once.
The site authenticates the upload via a per-user access code, splits it into MongoDB: dumpsMeta for per-game metadata and offsets, dumpsData for the class/struct/enum payloads sliced by package or namespace. Browse from the web UI – inheritance chains as clickable links, every type cross-references back, Mongo-text-indexed search that scopes globally or to a single dump.
Per-engine quirks
Unreal. FProperty replaced UProperty in 4.25. GNames chunked layouts vary by version. GObjects can be a single TUObjectArray or a chunked one depending on build flags. Some titles encrypt the FName pool with AES plus custom variants. The detection module fingerprints the engine version and the unreal/ engine module picks the right layout for property reads, name resolution, and global addressing.
Source 1. The engine is older and the property system is simpler – datamaps are just linked structs. The harder bit is that entity classes are registered through global factory linked lists, so the walker has to chase those rather than reading a single global.
Source 2. Schema system replaces datamaps. SchemaSystem_001 is the entry point; from there every class has a SchemaClassInfo with field offsets, types, and inheritance. Mostly boring once you find the entry point.
Unity IL2CPP. No reflection at runtime – the C# class info is baked into a metadata blob shipped alongside the binary. The walker parses global-metadata.dat (or its in-memory equivalent) and stitches type info back together.
Unity Mono. Easy mode. The Mono runtime has full reflection, walk the assembly list, walk classes per assembly, read fields and methods directly.
Stack
Script side:
- AngelScript inside Perception.
- One module per engine under
source/engines/. - Detection module fingerprints the running process.
- HTTP upload to the web API once the walk is done.
Web side:
- SvelteKit, file-based routing.
- MongoDB with Mongoose.
- Docker Compose for the deploy.
What's annoying
Schema versioning. As I add new metadata to dumps – decryption keys, runtime offsets, build flags – older dumps don't have those fields. I'm not yet doing migrations on read, just defaulting missing fields, which works but is an audit-debt problem.
The dump is held in memory while the script generates JSON. For some UE5 titles with massive object counts, or modded Unity games with tens of thousands of classes, the script can OOM. I'd like to switch to a streaming serialiser but AngelScript doesn't have great primitives for that.
Adding a sixth engine means writing detection fingerprints, a walker, and aligning its types to the common JSON shape. The first one was hard; each subsequent one has been more about matching the shape than discovery.
Source: source/main.as (script entry), source/engines/ (per-engine walkers), web/ (SvelteKit app).