-
Notifications
You must be signed in to change notification settings - Fork 0
Shared Schema
Auto-generated from the repo docs by
tools/sync_wiki.sh— edit the source Markdown in the repo, not this wiki page.
The model schema's shared fields are defined once, in a netstandard2.0 library both halves inherit — so the editor and the plugin can't drift on them.
This page owns the field count. It is the only doc that states a number — the count drifted to three different values across four docs before 2026-08-20; everywhere else now says "the shared fields" and links here. Re-check it with
grep -cE '^\s+public ' Haf.Schema/HafModelSchema.cs(minus the class declaration line). The real guard ischeck_schema_parity.sh, not the number written here.
-
Haf.Schema.HafModelSchema(Haf.Schema/HafModelSchema.cs, netstandard2.0; referencesUnityEngine.CoreModulefor the sharedVector3) holds the 70 fields stored identically by the editor and the plugin — the behavioral / sound / prop / tint config, plusresourceName,pawnDescription, and thepositionoffset (Vector3). -
ModelDef(editor,editor/ModelRegistry.cs): HafModelSchema— adds its bake-time, GUID (int[]), and editor-onlyVector3(rotation) fields. -
ModelEntry(plugin,Patches/UniversalInjectPatch.cs): HafModelSchema— adds its runtime-state and GUID (sa/sb/..) fields.
Both classes inherit, so the shared fields are still used by name (cur.<field>, e.<field>) exactly as before — no
call-site changes.
| Fields | Where |
|---|---|
70 identical fields (string/bool/float/int + the position Vector3) |
HafModelSchema — one definition, compiler-enforced |
| GUIDs |
not shared — int[] skel/atlas/clip (editor) vs sa,sb,sc,sd (plugin): different runtime shapes |
Bake-time-only (size, convertGrid, stripParts, …) |
ModelDef only |
Runtime state (resolved handles, *AnimId, session flags, poll dicts) |
ModelEntry only |
The plugin's primary parse is generic: ParseModels deserializes each model with m.ToObject<ModelEntry>(), so every
name-matching field (all 70 shared + any plugin-own config) maps automatically — no hand-list. Only two shapes stay
explicit: the GUID arrays (one JSON array skel[] → four ints sa/sb/sc/sd, etc.) and position (a
UnityEngine.Vector3, which Newtonsoft can't deserialize — its normalized property self-references — so the key is
stripped from the object before ToObject and re-pinned by hand). The per-entry regex fallback (for malformed
JSON) still hand-lists every field; check_schema_parity.sh asserts it covers the GUID hand-list + every shared field,
and that everything it reads is a field the baker writes. A missing key falls to the field's initializer in
HafModelSchema — the one authoritative default for both halves.
-
Shared (both read it, same type) — add it to
HafModelSchemaonce (with its default as the initializer). Both inherit it and the plugin's primary parse maps it automatically; add the matchingRegex.Matchesline to the fallback, then runcheck_schema_parity.sh(it fails loudly if the fallback lags). -
Editor-only (bake-time) — add to
ModelDef. -
Plugin-only CONFIG (pack-authored, like
rotorSpinBones) — add toModelEntryand to theregistryConfigKeyswhitelist inParseModels: since 2026-08-17 the primary parse strips every non-whitelisted key before the generic map (so pack JSON can never bind runtime-STATE fields likerepointed— test-pinned). A forgotten whitelist entry fails loud (the key is stripped and Diag names it). If the field must survive malformed JSON too, add it to the regex fallback + the parity allowlist. -
Plugin-only runtime STATE — just add the field to
ModelEntry; it is protected from JSON automatically (not whitelisted = stripped). No attribute, no list to remember.
-
Editor writes
pack.jsonvia UnityJsonUtility, which serializes inherited public fields (and always writes every field — no omitted keys). -
Plugin reads via Newtonsoft's generic
ToObject<ModelEntry>()(inherited fields fill by name; GUID arrays andpositionextracted by hand), with the index-aligned regex fallback for malformed JSON.
HafModelSchema builds to Haf.Schema.dll (netstandard2.0), referenced by the plugin via a ProjectReference
(Private=true), so dotnet build emits it into bin/Release alongside the plugin. The plugin depends on it —
BepInEx won't load the plugin without Haf.Schema.dll in BepInEx/plugins/, so deploy both with
tools/deploy-plugin.sh. The editor consumes the same DLL from editor/Plugins/Haf.Schema.dll.
Get started
- Getting Started
- Installation
- Troubleshooting
- Authoring State and Deployment
- Mod Editor version.xml Recovery
- Building
- Backup
Author models and behavior
- Editor Tools
- Factory Manual
- Vehicle Lab Quickstart
- Animated Models
- Animation Pitfalls
- Textures
- Unit Size
- Unit Combat Behavior
- Formations
- Pawn Props
- Projectiles
- Game Sound Lab
- Firing on Attack
- Turn Ease
- Facing Persistence
- Donor Clip Flight
Districts and wonders
Ship and operate
Internals and project