Kernkonzepte
Die Tabelle ist die einzige Quelle der Wahrheit
Es gibt genau eine kanonische Form Ihrer Daten: die Tabelle. Alles andere wird daraus abgeleitet:
- Die IR (unveränderliche Definitionen) ist die validierte, zusammengesetzte Form der Tabelle.
- Die generierten C#-Klassen sind das Schema der IR, stark typisiert gemacht.
- Die per Bake erzeugten ScriptableObjects sind die Werte der IR, ladbar gemacht – ein Lookup-Cache, niemals eine eigenständige Wahrheit.
Jede Änderung läuft über die Tabelle und muss die Re-Import-Validierung bestehen, um real zu werden. Ein direktes Bearbeiten eines per Bake erzeugten SO würde eine zweite Wahrheit schaffen und die Validierung umgehen – das Produkt unterstützt dies bewusst nicht als Workflow.
(Der Schalter „Testbearbeitung" im Inspector existiert für temporäre Laufzeit-Experimente. Er wird nie zurückgeschrieben, und der erneute Import löscht ihn.)
Warum das wichtig ist: Projekte, die das SO als Quelle der Wahrheit behandeln, enden mit unvalidierten Daten, die von der Tabelle abweichen, ohne Möglichkeit zum Abgleich. Hier ist der Abgleich strukturell verankert – stets aus der Tabelle neu generieren.
Die IR – eine unveränderliche, validierte Zusammenstellung
Die IR ist das Ergebnis der Validierung. Für jeden Tab enthält sie eine SheetTable (Schema + Datensätze), deren Zellen bereits typisierte Werte sind: int, float, enum-Werte, Datensatz-Referenzen, Asset-Referenzen, Listen, benutzerdefinierte Plugin-Typen.
Wesentliche Eigenschaften:
- Kein Teil-Zusammenbau. Existiert irgendwo ein einziger Fehler, wird die IR nicht gebaut (
ImportResult.Success == false ⇔ Registry == null– eine harte Invariante). - Keine Nulls. Eine leere optionale Zelle materialisiert sofort ihren Typ-Standardwert, markiert mit
IsDefaulted– Konsumenten müssen niemals auf null prüfen. - Unveränderlich. Die IR ist nach dem Zusammenbau schreibgeschützt; Ausgänge (Codegen, Bake, Export) lesen sie, verändern sie aber nie.
Die Pipeline
fetch → parse markers/schema → parse cells → validate (keys, references,
@overlap, asset keys, domain rules) → assemble IR → codegen (.cs) → bake (SO)
└──────────────── collect ALL diagnostics ────────────────┘- Die Validierung sammelt alles. Sie erhalten die vollständige Liste der Probleme in einem einzigen Durchlauf – wo / was / warum / wie, pro Fehler – statt pro erneutem Import nur einen Fehler zu beheben.
- Codegen ist die letzte Stufe, nach Validierung und Wertzusammenbau, weil das Schreiben von
.cs-Dateien einen Domain-Reload auslöst. Die Pipeline ist so aufgebaut, dass der Reload sicher ist und die Kette danach automatisch fortgesetzt wird. - Fehler sind strukturierte Objekte, die als Sätze dargestellt werden. Jeder Fehler enthält den Tab, die 1-basierte Zeile sowie den Spaltenbuchstaben und den Feldnamen. Er enthält außerdem den fehlerhaften Wert, die verletzte Regel und einen umsetzbaren Lösungsvorschlag (mit Vorschlägen für die nächstliegende Übereinstimmung bei Tippfehlern). Dieselben Objekte werden für Logs/CI auch als Maschinenkoordinaten dargestellt.
Die automatische Importkette
Ist ein Schema neu oder geändert, erledigt ein einziger Importlauf intern zwei Dinge:
- Generierten Code schreiben → Unity kompiliert → Domain-Reload.
- Nach dem Reload setzt sich die Kette von selbst fort und schließt den Bake ab.
Sie müssen nie manuell etwas erneut auslösen. Schlägt die Kompilierung fehl (z. B. weil Ihr Spielcode ein Feld referenziert, das gerade durch ein Umbenennen geändert wurde), bricht die Kette sicher ab mit einem umsetzbaren Hinweissatz in der Konsole, statt sich in einer Schleife zu verfangen (maximal 3 Versuche, Fortsetzungs-Log).
Starke Typisierung, kein Runtime-Parsing
Codegen liest @name / @type / @desc und erzeugt pro Tab Foo:
FooDefinition— eine stark typisierte Record-Klasse, ein Feld pro Spalte;@descwird zum XML-Doc-Kommentar und Inspector-Tooltip.FooDatabase : DefinitionDatabase— das Container-SO pro Tab mitRecords, lazy Id-Lookups und einemSchemaFingerprint.
Der Bake schreibt echte typisierte Felder – null Text-Parsing zur Laufzeit, keine Runtime-Reflection –, was ihn IL2CPP-sicher macht (keine Stripping-Risiken).
Adressbasiertes Laden — wie der Cache teilbar bleibt
Per Bake erzeugte SOs sind maschinenspezifische Caches mit maschinenspezifischen GUIDs. Direkte Szenenreferenzen auf sie würden zwischen Maschinen brechen. Stattdessen gilt:
- Der Import registriert jedes Database-SO automatisch in der Addressables-Gruppe
SheetForgeunter der stabilen Adresse"SheetForge/{tab}"(erneute Bakes verknüpfen die neue GUID erneut mit derselben Adresse; gelöschte Tabs werden bereinigt). - Spielcode lädt über die Adresse:
SheetForgeDatabases.LoadAsync<FooDatabase>("Foo"). - Das Addressables-Gruppen-Asset ist gitignored und selbstheilend (wird vom Import neu erzeugt, wenn es fehlt).
Baselines — wie der Round-Trip Ihre Tabelle bewahrt
Beim Import wird ein normalisierter Schnappschuss der Struktur jedes Tabs (Markierungszeilen, Spaltenreihenfolge, Kommentare, von Menschen geschriebener Text) als Baseline gespeichert. Export tauscht dann die aktuellen SO-Werte in die Baseline-Struktur ein.
So bewahrt ein Round-Trip Tabelle → Import → Export → Tabelle Ihre Tabelle strukturell zu 100 % und bewahrt Werte semantisch:
1.0↔1ist zulässig, da der Wert identisch ist.- Fließkommazahlen verwenden das kürzeste round-trip-fähige Format.
- Das Dezimaltrennzeichen ist stets
., unabhängig vom Gebietsschema.
Was committet und was regeneriert wird
| Artefakt | Richtlinie |
|---|---|
| Tabellen (lokale Dateien) / Google Sheet | Die Wahrheit. Committet / geteilt. |
Per Bake erzeugte Database-SOs (Assets/SheetForgeBaked) | Gitignorter maschinenspezifischer Cache – regenerieren durch Ausführen eines Imports. |
Generierter Code (Assets/SheetForgeGenerated) | Es wird empfohlen, ihn zu committen. Er ist der eigene Quellcode Ihres Projekts, liegt außerhalb von Assets/SheetForge, sodass eine Neuinstallation des Produkts ihn nicht löschen kann, und Committen bedeutet, dass ein frischer Klon kompiliert, bevor jemand einen Import ausgeführt hat. Die Ausgabe ist deterministisch, sodass die Importe von Teammitgliedern identische Bytes erzeugen. Ihn ins Gitignore aufzunehmen ist eine gültige Alternative; der nächste Import erzeugt ihn dann neu. Ein Projekt, das älter ist als dieser Standardwert, generiert weiterhin nach Assets/SheetForge/Runtime/Generated, bis dieser Ordner leer ist; siehe Erste Schritte. |
Addressables-Gruppen-Asset SheetForge | Gitignored, selbstheilend. Committen Sie nicht den einzeiligen Settings-Diff, den seine erste Erstellung verursacht. |
Der eigene Generated-Ordner eines Domänenpakets | Die eigene Entscheidung des Pakets. Das mitgelieferte SheetForge.PluginDemo-Beispiel committet seinen generierten Code, damit die Demo sofort nach dem Import kompiliert. |
| Import-Einstellungs-Asset | Liegt in Ihrer eigenen Verwaltung; halten Sie Service-Account-Schlüssel-Pfade aus dem Repository heraus (verwenden Sie die Umgebungsvariable SHEETFORGE_SHEETS_KEY). |
Erweiterung ohne Änderung
Registrierungsverträge lassen Plugins der Pipeline beitreten – ganz ohne Änderungen am Core:
- Zelltyp-Parser (einschließlich Wrapper-Typen), Domänen-Validatoren, Kanten-Contributor;
- benutzerdefinierte Strukturmarkierungen, „Create sheet"-Vorlagen, Import-Source-Provider;
- die Canvas-Overrides, Code-Registries, Widgets, Aktionen, Zell-Widgets, Farb-Presets und UI-Strings des Data Studio.
Core referenziert niemals ein Domänenpaket; die Einbahnstraßen-Abhängigkeit wird vom Compiler erzwungen. Die maßgebliche Liste – samt ihrer Anzahl – steht in Plugin-Erstellung.
Verwandte Seiten
- Tabellensyntax – die Markierungs- und Typgrammatik, die der Parser liest
- Data Studio – Authoring auf Basis dieses Modells
- Quellen, Export & Push – Round-Trip-Mechanik
- Authoring-Kernel – die Engine unter dem Authoring-Fenster