Zum Inhalt springen
SheetForge

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:

  1. Generierten Code schreiben → Unity kompiliert → Domain-Reload.
  2. 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; @desc wird zum XML-Doc-Kommentar und Inspector-Tooltip.
  • FooDatabase : DefinitionDatabase — das Container-SO pro Tab mit Records, lazy Id-Lookups und einem SchemaFingerprint.

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 SheetForge unter 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.01 ist 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

ArtefaktRichtlinie
Tabellen (lokale Dateien) / Google SheetDie 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 SheetForgeGitignored, selbstheilend. Committen Sie nicht den einzeiligen Settings-Diff, den seine erste Erstellung verursacht.
Der eigene Generated-Ordner eines DomänenpaketsDie eigene Entscheidung des Pakets. Das mitgelieferte SheetForge.PluginDemo-Beispiel committet seinen generierten Code, damit die Demo sofort nach dem Import kompiliert.
Import-Einstellungs-AssetLiegt 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