Möglichkeiten & Grenzen
Diese Seite listet alles auf, was SheetForge nicht tut, noch nicht tun kann oder anders macht, als Sie vielleicht erwarten würden — mit dem Grund, dem Workaround und ob es künftigen Spielraum gibt.
Format pro Eintrag: Was / Warum / Workaround (+ künftiger Spielraum, wo sinnvoll).
1. Plattform & Abhängigkeiten
Addressables ist erforderlich — die Pipeline sperrt sich ohne das Paket
- Was: Adressbasiertes Laden ist der Laufzeitpfad, und der Typ
AssetRef@Groupbenötigtcom.unity.addressables, sodass das Paket installiert sein muss, um das Asset zu nutzen. Das Asset selbst kompiliert auch ohne das Paket — der gesamte Addressables-nutzende Code liegt hinter einem Versions-DefineSHEETFORGE_ADDRESSABLES, das sich nur einschaltet, wenn das Paket vorhanden ist. - Verhalten bei Fehlen: Die gesamte Pipeline (Import · Export · Push · Authoring-Rückschreiben) ist gesperrt, nicht degradiert — das Ausführen jedes Einstiegspunkts zeigt einen Installationshinweis und bricht ab. Es gibt keinen Teil- oder stillen Pfad (kein „Asset-Schlüssel-Validierung überspringen"-Fallback). Da der Editor auch ohne das Paket kompiliert, fällt er nie in den Safe Mode: Das Fenster „Erste Schritte" öffnet sich normal, seine Addressables-Zeile zeigt ✗ mit einer Schaltfläche Package Manager öffnen. Der abhängigkeitsfreie Bootstrap
SheetForge.Setupbleibt als Anleitungsnetz für andere, unabhängige Kompilierungsfehler erhalten. - Im Data Studio ohne das Paket: Die ⊙-Picker-Schaltfläche der Asset-Zelle und ihr Drag-and-Drop-Ziel sind deaktiviert, mit dem Grund als Tooltip; das Eintippen einer Adresse in die Zelle funktioniert weiterhin.
- Warum keine duale Resources-/Addressables-Abstraktion: Bewusst nicht gebaut — als Over-Engineering eingestuft.
- Workaround: Installieren Sie Addressables. Der Asset-Store-Importdialog übernimmt dies vor der Kompilierung; haben Sie es übersprungen, leitet Sie der kompilierende Editor zur Installation an.
- Verifikation: Beide Zweige werden live durchlaufen — mit entfernten Versions-Defines (simuliert „Addressables fehlt") kompilieren die Produkt- und Test-Assemblies mit 0 Fehlern; wiederhergestellt, mit 0 Fehlern und 0 Warnungen. Unabhängig End-to-End verifiziert, indem das Asset in ein frisches Projekt ohne installierte Addressables importiert wurde: Das Projekt kompiliert, und das Installationshinweisfenster erscheint wie vorgesehen.
Unity Localization ist optional — nur die StringTable-Synchronisierung wartet darauf
- Was: Lokalisierungstabellen (
@loc),LocRef-Referenzen, Schlüsselkonstanten, Abdeckungsberichte, Export, Push, xlsx und die Web-App funktionieren allesamt ohne installiertescom.unity.localization. Das Einzige, was wartet, ist der StringTable-Synchronisierungs-Ausgang: Er zeigt einen Installationshinweis (einmal pro Sitzung) und stoppt. Aller paketberührende Code liegt hinter einem Versions-DefineSHEETFORGE_LOCALIZATION, sodass jede Assembly und jede Zeile generierten Codes ohne das Paket kompiliert – generierte Felder sind die einfacheLocRef-Struct, nie ein Pakettyp. - Verhalten bei Fehlen: Nichts degradiert, und nichts wird anderswo stillschweigend übersprungen – die Tabellen bleiben vollständige Tabellen; nur der Synchronisierungs-Ausgang ist gesperrt, mit angezeigtem Grund.
- Unterstützte Version: 1.5 oder neuer.
- Workaround: Installieren Sie das Paket, wenn Sie die Tabellen möchten; alles, was vor diesem Zeitpunkt verfasst wurde, synchronisiert sich beim nächsten abgeschlossenen Import. Siehe Lokalisierungstabellen.
Keine Ein-Klick-Installation per Programmcode
- Was: Das Sicherheitsnetz-Fenster leitet Sie an; es installiert das Paket nicht selbst. Dieselbe Regel gilt für den Unity-Localization-Installationshinweis.
- Warum: Die Einreichungsregeln des Asset Store schränken die programmatische Paketänderung ein; ein Hinweisfenster ist die sichere, regelkonforme Wahl.
Das SHEETFORGE-Produkterkennungs-Define wird nicht automatisch entfernt
- Was: Die Editor-Assembly registriert bei jedem Build-Target selbst ein
SHEETFORGE-Scripting-Define-Symbol, sodass andere Assets zur Kompilierzeit erkennen können, dass SheetForge installiert ist (siehe Plugin-Erstellung ▸ SheetForge aus einem anderen Asset erkennen). Die Registrierung ist idempotent (wird nur hinzugefügt, wenn sie fehlt — keine Neukompilierungs-Unruhe, sobald sie vorhanden ist). - Grenze: Löschen Sie das Asset später, bleibt dieses Define bestehen — der Code, der die Entfernung bemerken würde, ist mit ihm verschwunden.
- Workaround: Entfernen Sie es von Hand unter Project Settings ▸ Player ▸ Scripting Define Symbols (pro Plattform). Wir lassen bewusst keinen Hintergrund-Watcher laufen, nur um ein einziges Symbol zu bereinigen. Dies ist getrennt von
SHEETFORGE_ADDRESSABLES, einem internen Version-Define, das lediglich widerspiegelt, ob das Addressables-Paket vorhanden ist.
2. Google-Sheets-Quelle
Der ExportUrl-Modus ist schreibgeschützt
- Was: Push, Übernehmen, Strukturbearbeitung und Löschen sind im ExportUrl-Modus allesamt deaktiviert.
- Warum: Es ist der nicht authentifizierte, per Link geteilte Export-Pfad — von Natur aus schreibgeschützt. Push erfordert immer SheetsApi-Zugangsdaten, erzwungen noch vor jedem Netzwerkaufruf.
- Workaround: Verwenden Sie für jedes Rückschreiben den SheetsApi-Modus (Service-Account – siehe Google Sheets einrichten).
ExportUrl erfordert eine Gid-Map
- Was: Eine leere Gid-Map lässt den Import fehlschlagen; doppelte Gids werden abgelehnt.
- Warum: Eine Export-URL ohne Gid liefert stillschweigend nur den ersten Tab zurück — eine Falle stiller Beschädigung, in die das Produkt sich weigert hineinzulaufen. SheetsApi entdeckt Tabs automatisch.
- Workaround: Registrieren Sie den
#gid=-Wert jedes Tabs, oder verwenden Sie SheetsApi.
Push löscht Zeilen anhand des Schlüssels, und nur verifizierte
- Was: Ein lokal gelöschter Datensatz wird beim Push aus der Live-Tabelle entfernt — nachdem der Abruf vor dem Senden bestätigt hat, dass sein Schlüssel noch in der Zeile sitzt, die Ihr Import gesehen hat. Eine bereits verschwundene Zeile gilt als erledigt (idempotenter erneuter Push); ein auf einer anderen Zeile gefundener Schlüssel wird mit einem Hinweis übersprungen, niemals anhand der Position gelöscht. Löschungen werden in einem eigenen Abschnitt der Bestätigungsübersicht aufgeführt und zuletzt gesendet, innerhalb jedes Tabs von unten nach oben.
- Warum: Der Abgleich per Schlüssel gegen die Live-Tabelle ist es, was Löschen auf einer möglicherweise verschobenen Tabelle sicher macht; alles, was der Abgleich nicht bestätigen kann, wird unangetastet gelassen.
- Grenze: Eine Quelle ohne die Fähigkeit, Zeilen zu löschen (ein benutzerdefinierter Provider, der sie nie erhalten hat), fällt auf das alte Verhalten zurück — die Löschung wird gemeldet, und die Live-Zeile bleibt für Sie zum Entfernen übrig.
Push überspringt widersprüchliche Zellen (by design)
- Was: Zellen, die seit Ihrem Import von Dritten bearbeitet wurden, Zeilen, deren Schlüssel sich mehrdeutig verschoben hat, fehlende Zeilen oder doppelte Live-Schlüssel werden mit Warnungen übersprungen — nicht überschrieben.
- Warum: Das ist das Sicherheitsnetz bei der Arbeit: gesendete Zellen sind gültig; Übersprünge schützen die Änderungen anderer und verhindern Schreibvorgänge in die falsche Zeile.
- Workaround: Prüfen Sie die Anzahl der angewendeten/übersprungenen Zellen im Bericht; importieren Sie zum Abgleich erneut und pushen Sie dann erneut. (Eine Oberfläche zur Konfliktlösung wäre ein separates Feature — nicht geplant.)
Push erfordert eine Schlüsselspalte
- Was: Ein geänderter Tab ohne
RecordId-Schlüsselspalte kann nicht gepusht werden — das ist ein Planfehler, der den gesamten Push blockiert (null Sendevorgänge für jeden Tab; kein Teil-Senden). - Warum: Push lokalisiert Zeilen in der Live-Tabelle anhand des Schlüssels neu; ohne Schlüssel kann der Schutz vor der falschen Zeile nicht greifen.
- Workaround: Fügen Sie eine Schlüsselspalte hinzu, oder exportieren Sie in eine Datei und fügen Sie ein.
3. xlsx-Quelle
-
Tab umbenennen schließt Tabs mit xlsx-Ursprung aus — Schutz von Arbeitsmappen mit mehreren Sheets. Benennen Sie in der Arbeitsmappe um und importieren Sie erneut.
-
Propagierung von Schlüssel-Umbenennungen in einen Tab mit xlsx-Ursprung blockiert den gesamten Batch — der xlsx-Pfad kann keine chirurgisch präzisen Zell-Updates sicher durchführen, und teilweises Übernehmen ist nie erlaubt. Bearbeiten Sie diesen Tab direkt und importieren Sie erneut.
-
Nicht darstellbare Zellen werden abgelehnt — Formelzellen ohne zwischengespeicherte Werte, Fehlerzellen sowie Tabulatorzeichen/Zeilenumbrüche innerhalb einer Zelle. Der eingebaute OOXML-Reader ist absichtlich minimal gehalten (kein Fremdcode). Materialisieren Sie Formeln; verwenden Sie
;für Listen. -
Nur Werte — Formeln, Daten und Formatierung werden ehrlich interpretiert — eine Formelzelle liefert ihren zwischengespeicherten Wert (nie neu berechnet), eine datumsformatierte Zelle wird als
yyyy-MM-dd-Anzeigetext gelesen, und Zahlenformate, verbundene Zellen und Diagramme werden nicht importiert. Der Import-Dialog der Web-App benennt, was tatsächlich vorkam, in einem Hinweis „Wie diese Arbeitsmappe gelesen wurde"; im Editor gilt dieselbe Richtlinie stillschweigend pro Zelle (die oben genannten Ablehnungen melden weiterhin pro Zelle). -
Manche exportierten Dropdown-Regeln können nicht übertragen werden — der Export ist eine einzige Arbeitsmappe, daher wird das Dropdown einer Referenzspalte als echter Bereich über die Schlüsselspalte des Ziel-Sheets geschrieben, dieselbe Bedeutung, die die Google-Regel hat. Drei Fälle werden weiterhin ausgelassen und gemeinsam in einer einzigen Warnung
DropdownNotSupportedByFormatbenannt:- ein Member, der ein Komma enthält (der Inline-Trenner würde ihn aufspalten);
- eine Inline-Liste über dem 255-Zeichen-Limit des Formats (Anführungszeichen eingeschlossen);
- ein Bereich, dessen Ziel-Tab nicht in der Arbeitsmappe ist.
Die Werte werden so oder so vollständig exportiert. Siehe Quellen, Export & Push.
4. Authoring — das Data Studio
Ein Tab ohne Schlüsselspalte nimmt keine neuen Datensätze auf, und seine Wertbearbeitungen verlieren ihren Anker
-
Was: Ein Tab ohne
RecordId-Schlüsselspalte wird normal importiert und angezeigt, und die Strukturbearbeitung funktioniert vollständig — Hinzufügen, Entfernen, Umbenennen, Neuanordnen von Spalten und Markierungen, plus das Umbenennen und Löschen auf Tabellenebene. Was er nicht erhalten kann, ist ein neuer Datensatz, da ein Datensatz ohne Schlüssel weder benannt noch referenziert werden kann:- Die Zeilen-Hinzufügen-Steuerung ist deaktiviert;
- der Referenz-Picker verweigert dort das Erstellen („… hat keine Schlüsselspalte, daher kann dort kein neuer Datensatz erstellt werden");
- eine Canvas- oder Inspector-Aktion, die dort hineinzuschreiben versucht, bewirkt nichts.
Wertzellen sind bearbeitbar — aber ohne Schlüssel, über den die Zeile adressiert werden könnte, wird die Bearbeitung nur gegen die Position der Zeile vorgemerkt.
-
Warum: Jede vorgemerkte Bearbeitung wird normalerweise logisch adressiert, als
(tab, record key, field), und unmittelbar vor dem Schreiben gegen die Tabelle neu aufgelöst. Das ist es, was eine Bearbeitung einen erneuten Import, eine Zeilen-Neuanordnung oder das Einfügen von Zeilen darüber durch jemand anderen überstehen lässt. Ohne Schlüsselspalte gibt es keine solche Adresse, daher läuft die Bearbeitung stattdessen an einer Zeilennummer verankert durch — außerhalb dieses Sicherheitsnetzes.Verschieben sich die Zeilen der Tabelle also unter Ihnen, bevor Sie zurückschreiben (ein erneuter Import, oder jemand bearbeitet die Quelle direkt), kann eine positionsverankerte Bearbeitung in der falschen Zeile landen. Merken Sie diese in kurzen Batches vor und übernehmen Sie sie.
-
Workaround: Fügen Sie eine
RecordId-Spalte hinzu (Strukturbearbeitung ist verfügbar, Sie können dies also im selben Fenster tun), übernehmen Sie, und der Tab wird mit dem logischen Anker wieder vollständig bearbeitbar. Schlüssellose Tabs bleiben zum Importieren vollkommen gültig — dies ist eine Authoring-Grenze, keine Schema-Grenze.
Spalte umbenennen / @type-Änderung bricht referenzierenden Spielcode; nach dem Übernehmen nicht rückgängig zu machen
- Was: Name/Typ des generierten Feldes ändern sich; Spielcode, der es referenziert, muss von Hand aktualisiert werden. Ctrl+Z funktioniert nur vor dem Übernehmen.
- Warum: starke Typisierung — das Feld ist Teil des generierten Schemas. Ein Kompilierungsabbruch wird durch den sicheren Abbruch der automatischen Kette mit einem umsetzbaren Hinweissatz abgefangen. Die Werte der Spalte bleiben vollständig erhalten (nur Markierungszellen ändern sich).
- Workaround: Der Bestätigungsdialog warnt zuerst; aktualisieren Sie Ihren Code und lassen Sie den nächsten Import fortsetzen.
Tab umbenennen bricht referenzierenden Spielcode; nach dem Übernehmen nicht rückgängig zu machen
Dieselbe Mechanik wie oben — der Name der generierten Klasse ändert sich (FooDatabase → BarDatabase); der erneute Import übernimmt automatisch die gesamte Aufräumarbeit auf Asset-Seite (alte Klasse, SO, Adresse).
Gegenseitige (Tausch-) und zyklische Tab-Umbenennungen werden unterstützt
- Was:
Alpha→Beta+Beta→Alpha(ein Tausch) sowie längere Zyklen (A→B→C→A) lassen sich in einem Batch vormerken und übernehmen — egal welche Hälfte Sie zuerst vormerken, es funktioniert, und die Tab-Leiste zeigt die getauschten Namen sofort an (WYSIWYG, rückgängig machbar). Die UI-Schranke nutzt Eindeutigkeit der finalen Namensmenge (nur ein echter Konflikt — zwei Umbenennungen mit demselben Zielnamen — wird abgelehnt); das Übernehmen erzwingt dies strikt. - Referenzen folgen den Daten (Tab-Identität), nicht dem Namen: Nach einem A↔B-Tausch wird
RecordId@Aatomar zuRecordId@Bumgeschrieben (einmaliger Durchlauf — nie doppelt angewendet), sodass es weiterhin auf dieselben Daten zeigt, die nach B verschoben wurden. - Lokal: Ein Tausch vertauscht die Inhalte der beiden Dateien in einem einzigen Schreibvorgang; eine Kette, die einen Namen über eine andere Dateiendung hinweg wiederverwendet, löscht die veraltete Datei mit der alten Endung (pfadbasierter Löschschutz), sodass der erneute Import niemals einen doppelten Tab sieht.
- Google: Titeländerungen werden topologisch geordnet und brechen jeden Zyklus mit einem temporären Titel auf (
A→tmp, B→A, tmp→B), sodass die Live-Tabelle nie einen kurzzeitigen doppelten Titel enthält. Schlägt eine Titeländerung mitten in der Sequenz fehl, wird der unter einem temporären Namen verbliebene Tab mit einer Anleitung zur Wiederherstellung gemeldet.
Nur bei Google: getauschte Tabs, die sich gegenseitig referenzieren, werden nicht umgebogen
- Was: Wenn die beiden getauschten Tabs sich gegenseitig referenzieren (Tab
Ahat eineRecordId@B-Spalte und TabBhat eineRecordId@A-Spalte), bewahrt der Google-Pfad ihren Inhalt über die Titeländerung an Ort und Stelle und schreibt ihre eigenen@type-Zellen nicht um — sodass diese gegenseitige Selbstreferenz auf Google nicht umgebogen wird. - Warum: Google benennt einen Tab um, indem es dessen Titel ändert (Inhalt unangetastet, by design); das Umschreiben des eigenen Grids des umbenannten Tabs würde das zunichtemachen. Lokale Quellen schreiben die Projektion des umbenannten Tabs um, sodass lokal dies vollständig handhabt. Referenzen von einem dritten Tab aus werden auf beiden Pfaden umgebogen.
- Workaround: Leiten Sie bei Google die gegenseitige Referenz über einen dritten Tab, oder übernehmen Sie den Tausch über einen Zwischennamen.
Das Staged-Value-SO-Overlay hat keine Schaltfläche mehr
- Was: Das Overlay „vorgemerkte Werte auf SOs vorschauen" (
EphemeralSoApply) wurde von einer Workbench-Schaltfläche angesteuert, und dieses Fenster ist verschwunden. Der Typ bleibt öffentliche API für ein Werkzeug, das ihn nutzen möchte; der Schalter Testbearbeitung des SO-Inspectors deckt den alltäglichen Fall ab, eine Laufzeit-Zahl auszuprobieren. - Grenze, wenn Sie ihn doch aufrufen: Das Overlay lehnt — mit einem Badge — (a) ausstehende/neue Spalten und (b) Zellen mit Parse-Fehlern ab. Neue Zeilen werden unterstützt. Es nutzt denselben echten Parse-+Bake-Pfad, daher lehnt es ab, was es nicht wahrheitsgemäß berechnen kann, statt es vorzutäuschen.
- Workaround: Es war immer nur eine Vorschau; übernehmen Sie normal für die echte Änderung. Ein erneuter Import stellt immer die Wahrheit wieder her.
Vorgemerkte Bearbeitungen werden isoliert, wenn ihre Zeile extern umbenannt, gelöscht oder in einen Schlüsselkonflikt gerät
- Was: Eine vorgemerkte Bearbeitung, deren Zeile zwischen Vormerken und Übernehmen extern umbenannt, extern gelöscht wurde oder in einen Schlüsselkonflikt geriet, wird vom Übernehmen ausgeschlossen und mit „isoliert" gekennzeichnet.
- Warum: Ihre logische Adresse kann nicht neu aufgelöst werden — aber sie wird weder stillschweigend verworfen noch darf sie die Sitzung blockieren.
- Workaround: Verwerfen Sie sie einzeln (nach Bestätigung) und merken Sie sie erneut vor.
Propagierung von Schlüssel-Umbenennungen betrifft nur Baseline-Zellen
- Was: Text, den Sie gerade erst im selben Batch eingegeben haben und der den alten Schlüssel referenziert, wird nicht automatisch umgeschrieben.
- Warum: Das stillschweigende Umschreiben der frischen Eingabe des Benutzers ist verboten; die Vorab-Validierung erkennt stattdessen die hängende Referenz.
- Workaround: Beheben Sie die vorgemerkte Referenz selbst, oder übernehmen Sie zuerst die Umbenennung.
Die verbleibenden Einträge drehen sich alle um das Data Studio, das eine Authoring-Fenster. Das ältere Workbench-Fenster wurde entfernt; die drei Funktionen, die nur sie bot, wanderten zuerst in das Studio und den Einstellungs-Inspector — siehe Was aus der Workbench wurde.
Eine Tabelle, deren Validierung fehlschlug, öffnet sich zur Bearbeitung — aber Export, Push und Builds bleiben blockiert
- Was: Wurde die Quelle vollständig gelesen, werden ihre Tabellen als Baseline gespeichert, selbst wenn die Validierung fehlschlug, sodass das Studio sie öffnen kann und Sie die Fehler an Ort und Stelle beheben können. Codegenerierung und Bake laufen erst, wenn die Fehleranzahl null erreicht, und Export, Push zur Live-Tabelle und Player-Builds werden allesamt verweigert, solange sich die Tabelle in diesem Zustand befindet, jeweils mit Begründung.
- Warum: Diese drei Ausgänge kombinieren alle die zuletzt erfolgreich gebackenen Werte mit den neueren Tabellen. Einen davon jetzt auszuführen, würde veraltete Werte über Zellen spleißen, die jemand bereits korrigiert hat — ein stiller Rollback. Das Blockieren der Ausgänge ist es, was den Eingang offen hält.
- Eine Korrektur zu übernehmen fragt einmal nach: Bei einer unter Quarantäne stehenden Tabelle zeigt das Rückschreiben eine zusätzliche Bestätigung, weil die Vorab-Validierung dort nicht das harte Gate sein kann (die Tabelle hat bereits Fehler). Alles Gefundene wird in diesem Übernehmen-Vorgang als Warnung gemeldet, und der automatische erneute Import validiert die gesamte Tabelle erneut. Gesunde Tabellen sind unbetroffen — die Vorab-Validierung verweigert das Schreiben weiterhin.
- Workaround: Beheben Sie jeden gemeldeten Fehler und pullen Sie erneut. Die Blockade hebt sich von selbst an der einen Stelle auf, die sie löscht: einem Lauf, der bis zum Bake vollständig durchläuft.
Sortierung und Filter des Data Studio sind nur für die Anzeige — und deaktivieren die Zeilen-Neuanordnung, solange sie aktiv sind
- Was: Die tabellenweise Sortierung des Studios (beliebige Spalte, auf-/absteigend, pro Projekt gespeichert) und der Textfilter ändern nur die Anzeigereihenfolge. Die Randspalte behält die echten Tabellen-Zeilennummern, und keines von beidem wirkt sich auf Staging, Übernehmen, Push oder Export aus. Solange eine Sortierung oder ein Filter aktiv ist, sind die Neuanordnungs-Werkzeuge ▲▼ der Zeile mit einem Tooltip deaktiviert.
- Warum: Ein Neuanordnen nach „sichtbarem Nachbarn", während die Ansicht sortiert oder gefiltert ist, würde Zeilen stillschweigend neben Zeilen verschieben, die der Benutzer nicht sehen kann. Echte Änderungen der Zeilenreihenfolge sind eine Strukturoperation — löschen Sie zuerst Sortierung/Filter.
- Hinweis: „Nach Neuestem sortieren" existiert nur, wenn Ihre Tabelle eine Spalte hat, die dies kodiert (z. B. eine
IntIdoder eine datumsähnliche String-Spalte) — die Tabelle selbst speichert keine Zeitstempel.
Die Problems-Anzeige des Data Studio ist ein Entwurf, solange eine Schlüssel-Umbenennung vorgemerkt ist
- Was: Solange eine Schlüsselzelle (
RecordId) eine vorgemerkte Bearbeitung trägt, führt das Problems-Panel ein Entwurf-Badge, und nicht aufgelöste Referenz-Einträge darin können Fehlalarme sein. - Warum: Die Vorschau im Speicher wendet die Propagierung von Schlüssel-Umbenennungen nicht an — die läuft erst beim Übernehmen, über alle Tabs hinweg. Statt die Diagnosen zu verbergen oder die Propagierung vorzutäuschen, sagt Ihnen das Fenster, dass die Liste ein Entwurf ist, bis die Umbenennung geschrieben ist.
- Workaround: Übernehmen Sie die Umbenennung (die Propagierung läuft mit ihrer eigenen Bestätigung), und lesen Sie dann die aktualisierte Liste.
Die Tabelle ist oberhalb von 200 Zeilen zeilen-virtualisiert — mit zwei wissenswerten Randfällen
-
Was: Jenseits von 200 Zeilen baut die Tabelle Zeilenelemente nur für das sichtbare Fenster (plus zwölf Zeilen Overscan), mit Platzhaltern oberhalb und unterhalb, die die wahre Gesamthöhe halten, damit die Scrollleiste nicht lügt. Das Scrollen über eine Fenstergrenze hinweg verwendet die überlebenden Zeilen weiter und baut nur die neu hinzugekommenen. Das Browser-Grid tut dasselbe, bei derselben Schwelle.
Zwei Fälle bauen weiterhin alles. Bei 200 Zeilen oder darunter wird jede Zeile exakt wie zuvor gebaut, bit für bit. Ebenso eine Tabelle, deren Viewport-Höhe überhaupt nicht abgefragt werden kann — eine, die außerhalb eines Fensters steht, wo Layout nie ankommt —, weil dort der ehrliche Fallback „alles bauen" ist. Eine große Tabelle, die einfach noch nicht layoutet wurde, wartet stattdessen einen Frame, sodass sie ab ihrem ersten Zeichnen fensterbasiert ist, statt alles zu bauen und wieder wegzuwerfen.
-
Die Zeile, die Sie gerade bearbeiten, bleibt am Leben, auch nachdem sie aus dem Fenster gescrollt ist, sodass Caret, Fokus und Ihr getippter Text überleben. Dieses Am-Leben-Halten hat eine Distanzobergrenze, jenseits derer der offene Editor committet und den Fokus verliert, statt unbegrenzt mitgeschleppt zu werden. Dabei geht nichts verloren — der Wert steckt bereits in der Staging-Session.
-
Nur die Elementerstellung ist fensterbasiert. Spaltenbreiten-Abtastung, Suche, Sortierung, Koordinaten und das Staging-Overlay betrachten weiterhin jede Zeile, weil jedes davon eine andere Antwort geben würde, sähe es nur, was auf dem Bildschirm ist. Der Wechsel zu einer sehr großen Tabelle verrichtet also weiterhin Arbeit proportional zu ihrer Größe; was er nicht mehr tut, ist Tausende Widgets zu bauen.
-
Im Browser misst der fensterbasierte Modus die Spalten, statt das Layout dies tun zu lassen. Auto-Layout-Breiten würden aus welchen Zeilen auch immer gerade im Fenster stehen berechnet, sodass eine Spalte beim Scrollen zucken würde. Im fensterbasierten Modus stammen die Breiten aus einer datengetriebenen Schätzung über alle Zeilen und werden dann fixiert. Der Voll-Render-Modus (≤ 200 Zeilen) verwendet weiterhin unverändert Auto-Layout.
Die Canvas schwenkt nur innerhalb ihres Scroll-Bereichs, und ihre gestrichelten Zyklus-Verbindungen werden gröber, je größer sie werden
- Was:
- Strg/Cmd + Mausrad zoomt die Record-Canvas zwischen 25 % und 200 %, wobei der Punkt unter dem Cursor stillsteht — ein zentrumsverankerter Zoom würde die Karte, die Sie gerade betrachten, aus dem Bild schieben. Die Prozentzahl im Canvas-Header ist eine Schaltfläche, die zu 100 % zurückkehrt. Ein einfaches Mausrad scrollt weiterhin.
- Ziehen mit der mittleren Maustaste — oder Alt + linke Taste, für Hardware ohne mittlere Taste — schwenkt, und der Cursor markiert den Griff, solange er gehalten wird. Links-Ziehen bleibt dem Auswählen und Verbinden vorbehalten, es könnte also nicht zugleich „die Ansicht bewegen" bedeuten.
- Das Panel ist eine Scroll-Ansicht, daher ist der Schwenkbereich der Scroll-Bereich: Er stoppt am Rand des Inhalts, statt in den leeren Raum abzudriften, und wenn der Inhalt kleiner ist als der sichtbare Bereich, bewegt er sich überhaupt nicht. Dies ist keine unendliche Canvas.
- Eine gestrichelte Verbindung, die einen Zyklus markiert, deckelt, wie viele Striche sie zeichnet, und verdoppelt ihre Strichperiode bei einem langen Pfad, sodass eine sehr lange Schleife gröber statt schärfer wirkt.
- Warum: Unity weist Mesh-Vertices pro Draw-Call zu, mit einer harten Obergrenze von 65,535, und ein Überschreiten lässt die Zeichnung vollständig verschwinden, während die Tessellation trotzdem bezahlt wird. Der Strich-Deckel hält einen
Strokeinnerhalb dieses Budgets, by design. Das gepunktete Hintergrundraster saß früher an derselben Klippe und tut das nicht mehr: Es ist eine kleine sich wiederholende Hintergrund-Kachel, die null Vertices kostet und in konstanter Zeit neu zeichnet, egal wie groß die Canvas wird. (Ein als Pfad gezeichneter Punkt kostet gemessene 28 Vertices, nicht seine vier Ecken — die Arithmetik hinter dem 1,800-Punkte-Budget des Zeichen-Fallbacks, und der Grund, warum die Kachel der ausgelieferte Pfad ist.) - Workaround: Für das Raster ist keiner nötig. Für eine große Nachbarschaft zoomen Sie heraus, verengen Sie das Richtungssegment, oder öffnen Sie einen Nachbarn als neuen Endpunkt, statt zu versuchen, alles auf einen Bildschirm zu bekommen.
Eine Tabelle ohne Datentabelle wird übersprungen, nicht importiert
- Was: Ein Tab, der keine der drei Pflichtmarkierungen und keine Datenzeile hat — eine brandneue Tabelle, die nur Kommentare oder eine
@style-Zeile enthält — wird mit einer WarnungEmptyTabSkippedübersprungen, statt den Import an drei fehlenden Markierungen scheitern zu lassen. Ihr bereits generierter Code, das per Bake erzeugte Asset und die Adresse bleiben erhalten, statt bereinigt zu werden, als wäre der Tab gelöscht worden. Export und Push überspringen ihn symmetrisch, weil alle drei dasselbe Prädikat abfragen. - Warum: Eine unfertige Tabelle darf nicht jeden anderen Tab am Importieren hindern können, und ein Autor legt die Tabelle üblicherweise vor ihrer Kopfzeile an.
- Grenze: Eine halb geschriebene Tabelle (irgendeine Pflichtmarkierung vorhanden) wird nicht übersprungen — sie scheitert ehrlich, weil ein stilles Überspringen echte Arbeit verbergen würde. Eine Tabelle, die ab Spalte A statt Spalte B typisiert ist, wird ebenso an den Parser übergeben, sodass ihre echte Diagnose („Spalte A ist die Markierungsspalte, die Daten beginnen bei B") erhalten bleibt.
Ein aus Plugin-C#-Code registriertes Enum kann keine Member aus einer Tabelle erhalten
- Was: Ein
Enum<T>, dessenTein Plugin mitenums.Register<T>()registriert hat, gehört dem Code. Eine Enum-Definitionstabelle darf diesen Namen nicht beanspruchen (DuplicateEnumName), und die Zeile „Add a new member…" im Zellen-Dropdown fehlt bei einer solchen Spalte schlicht. - Warum: Die Tabelle ist nur für das kanonisch, was sie selbst definiert. Einen Member in eine Tabelle zu schreiben, die nicht mehr über den kompilierten Typ entscheidet, würde einen Member erzeugen, der nie im Code erscheint — ein Versprechen, das das Produkt nicht halten kann. Die fehlende Zeile ist die Art, wie die UI das sagt, statt eine Aktion anzubieten, die scheitern würde.
- Workaround: Verschieben Sie das Enum in eine Enum-Definitionstabelle, falls die Tabelle es besitzen soll, oder fügen Sie den Member in Ihrem Plugin-C#-Code hinzu und kompilieren Sie neu.
- Die Struktur folgt derselben Besitzlinie: Die Struktur einer Enum-Definitionstabelle wird in beiden Hosts vollständig bearbeitet — definieren, umbenennen, löschen, Spalten neu anordnen, den zugrunde liegenden Typ und die Beschreibung bearbeiten —, aber nichts davon kann einen code-eigenen Enum-Namen anfassen, und eine Definitionstabelle kann einen solchen Namen ebenfalls nicht beanspruchen. Die Ablehnung nennt den Grund.
Enum-Definitionstabellen: Member werden nur angehängt, und es gibt keine Sortierung
- Was: Die Struktur der Enum-Tabelle wird im Editor wie in der Web-App gleichermaßen direkt vor Ort bearbeitet, aber Member-Zeilen werden immer nur angehängt — eine Lücke wird nie nachträglich aufgefüllt —, und die Ansicht bietet keine Sortierung oder Filterung.
- Warum: Die Position eines Members ist sein Ganzzahlwert. Eine Lücke zu füllen oder Member neu anzuordnen würde stillschweigend Werte umnummerieren, die bereits in Assets gebacken und in Spielständen gespeichert sind. Die Spaltenreihenfolge trägt dagegen keine Bedeutung, weshalb das Neuanordnen von Spalten immer erlaubt ist.
- Workaround: Um einen Wert explizit festzulegen, verwenden Sie die
Name=value-Syntax; die Darstellungsreihenfolge anderswo ist Sache des Konsumenten, nicht der Tabelle.
Ein tabellendefiniertes Enum generiert immer in den Einstellungsordner
- Was: Generierte Tab-Typen werden an Ort und Stelle neu generiert, in welchem Ordner sie auch bereits leben — aber die Enum-Datei (
SheetForgeEnums.cs) hat keinen Tab, an dem sie sich verankern könnte, daher wird sie immer in den in den Einstellungen benannten Ordner für generierten Code geschrieben. Verwendet ein Tab, dessen generierter Code in seinem eigenen Paketordner lebt, ein tabellendefiniertes Enum, schlägt die Kompilierung dieser Paket-Assembly mitCS0246fehl. - Warum: Eine einzige Datei enthält jedes tabellendefinierte Enum, weil ein Enum eine projektweite Ausgabe ist, keine pro Tab — daher gibt es keinen einzelnen Tab, dessen Heimat sie folgen könnte.
- Workaround: Legen Sie beide generierten Ordner in einer Assembly ab, oder registrieren Sie dieses Enum stattdessen aus Plugin-Code. Der Fehlschlag ist ein sichtbarer Kompilierungsfehler mit dem benannten fehlenden Typ, niemals stille Beschädigung.
Typisierte Asset-Referenzen lösen gegen geladene Typen auf — Kurzname nur bei Eindeutigkeit, keine Typen aus vordefinierten Assemblies
- Was:
AssetRef@Group<Type>akzeptiert jeden vonUnityEngine.Objectabgeleiteten Asset-Typ, den das Projekt laden kann, Engine oder eigener, ohne Allowlist. Drei Dinge werden abgelehnt statt erraten: Ein Kurzname, den sich mehrere geladene Typen teilen (AmbiguousAssetType—TextAssetkann je nach installierten Paketen einer sein) muss als vollständiger Name geschrieben werden (UnityEngine.TextAsset); ein unbekannter Name istUnknownAssetTypemit einem Vorschlag für die nächstliegende Übereinstimmung; und ein Typ, der in einer vordefinierten Assembly liegt (Assembly-CSharpund ihre Geschwister — jeder Skriptordner ohne Assembly-Definition), istAssetTypeNotReferenceable. - Warum: Die generierte Begleitassembly ist eine Assembly-Definition, und eine Assembly-Definition kann die vordefinierten Assemblies nicht referenzieren —
AssetReferenceT<T>würde für ein solchesTnicht kompilieren. Einen mehrdeutigen Namen durch Auswahl aufzulösen, würde die Spalte still an den falschen Typ binden. - Workaround: Verschieben Sie den Typ in eine Assembly-Definition, oder lassen Sie die Einschränkung
<…>weg und behalten Sie das uneingeschränkteAssetRef@Group. Components und reine Editor-Typen kommen nie infrage. - Außerdem: Der Browser löst Typnamen nicht auf (er hat kein Projekt, gegen das er auflösen könnte): Die Web-App parst
<Type>und zeigt es im Spalten-Tooltip, erzeugt aber keine der drei Typnamen-Diagnosen und bietet weder Picker noch Drop an. Codegen gibt nie einen nicht aufgelösten Namen wortgetreu aus — ein Name, den es nicht auflösen kann, fällt aufAssetReferencezurück, mit einerAssetTypeUnresolvedFallback-Warnung.
Der Asset-Picker, der Drop und vorgemerkte Registrierungen — was automatisch ist und was nicht
- Was: Das Ablegen oder Auswählen eines Assets schreibt die Adresse sofort in die Zelle und merkt die Addressables-Änderung (Hinzufügen · Verschieben · Gruppe erstellen) für das Übernehmen vor; die Änderung läuft erst, nachdem das Schreiben der Tabelle erfolgreich war — oder, wenn nur Registrierungen vorgemerkt sind, für sich allein, gefolgt vom automatischen erneuten Import; ein Übernehmen, das nicht schreiben konnte, weil seine Tabs auf einer Arbeitsmappe beruhen, hält sie weiterhin vorgemerkt. Eine Registrierung, auf die nichts mehr verweist, wird verworfen, wenn die Zelle umgetippt wird, und jede, die bis zum Übernehmen überlebt, wird als unreferenced übersprungen; ein bereits in der Gruppe vorhandenes Asset behält seine bestehende Adresse; ein Asset in einer anderen Gruppe wird erst nach einer Bestätigung verschoben, die die anderen Zellen nennt, die es referenzieren. Die automatische Adresse ist der Dateiname ohne Erweiterung, und eine Adresse, die in dieser Gruppe bereits von einem anderen Asset verwendet wird, wird abgelehnt statt umbenannt. Neue Gruppen erhalten das Standard-
BundledAssetGroupSchemaundContentUpdateGroupSchema. Angewendete und übersprungene Elemente werden mit ihren Gründen in der Konsole protokolliert, und bei einer lokalen Ordnerquelle wiederholt der Abschlussdialog des Übernehmens die Zusammenfassung (Addressables: N registered, M skipped). - Warum: Die Tabelle ist kanonisch — das Projekt darf sich nie für ein Übernehmen ändern, das die Tabelle nicht erreicht hat, und ein Eintrag, auf den keine Zelle zeigt, wäre eine Waise, die die Tabelle nicht erklärt.
- Workaround: Wurde eine Registrierung übersprungen, meldet der nächste erneute Import die Zelle als
UnknownAssetKey; beheben Sie die Ursache und übernehmen Sie erneut. Die Registrierung setzt immer das Addressables-Paket voraus.
Sub-Assets werden als parent[sub] adressiert, und eine Textur im Sprite-Modus besteht <Sprite>
- Was: Ein Sub-Objekt-Eintrag (ein Sprite in einer Textur, ein Material in einer Schriftart) wird so adressiert, wie Addressables ihn benennt —
parent[sub]— und dieser Schlüssel wird gegen den eigenen Typ des Sub-Objekts geprüft. Die Elternadresse erfüllt sowohl ihren eigenen Typ als auch jeden Sub-Asset-Typ, den sie enthält, was es einer im Sprite-Modus importierten Textur erlaubt, eine<Sprite>-Spalte zu bestehen. Das Ablegen eines Sub-Assets merkt das Elternteil für die Registrierung vor und schreibtparent[sub]in die Zelle. - Grenze: Ein Sub-Objekt-Eintrag muss im Addressables-Katalog existieren, damit
parent[sub]sich validiert; der Picker listet die Sub-Schlüssel, die er kennt, nach ihrem Elternteil auf.
Farben haben kein HDR, Kurventangenten folgen ihrem Modus, Verläufe werden quantisiert — mit Absicht
- Was:
Colorsind vier Bytes — ein Kanal über 1 (HDR) wird beim Export auf 0…1 begrenzt. EineAnimationCurve-Tangente, deren SeiteAuto,Linear,ConstantoderClampedAutoist, wird beim Import aus dem Modus neu berechnet, sodass eine von Hand eingetippte Zahl, die ihrem Modus widerspricht, ersetzt wird (dieselbe Neuberechnung, die Unity durchführt, wenn der Modus angewendet wird);Oncewird alsClampForevergelesen und nie zurückgeschrieben; eine Kurve ohne Schlüsselpunkte hat keine Textform und existiert nur als leere Zelle einer optionalen Spalte.Gradient-Schlüsselpunkt-Zeiten werden beim Import auf 16 Bit quantisiert (genau wie Unity sie speichert), ein Verlauf mit einem einzelnen Schlüsselpunkt kommt von Unity als zwei identische Schlüsselpunkte zurück, und der Farbraum wird nur geschrieben, wenn er gesetzt wurde. - Warum: Der Wert, den die Tabelle zeigt, muss der Wert sein, den die Engine hält, daher wird die Normalisierung, die Unity sonst später durchführen würde, einmal am Eingang durchgeführt, und jede Oberfläche — Tabelle, Editor-Feld, Web-Vorschau, gebacktes Asset — zeigt eine Kurve und einen Verlauf.
- Workaround: Verwenden Sie
Free/Free, wenn die Tangentenzahlen wörtlich genommen werden sollen; speichern Sie HDR-Intensitäten in einer separatenfloat-Spalte.
Chip-Editoren und native Felder gibt es nur für die drei visuellen Typen
- Was: Das Data Studio zeigt
Color-,AnimationCurve- undGradient-Skalare als Unitys eigene Felder und ihreList<>s als Chip-Editoren; die Web-App zeigt Vorschauen mit ihren eigenen Editoren und Chip-Listen. Jede andere Listenspalte —List<int>,List<Enum<…>>, Wrapper-Listen — bleibt in beiden Hosts kanonischer Text, und auch ein Wrapper, der einen der drei enthält (Pair<Color>), ist Text. - Warum: Die drei Typen sind diejenigen mit einem Bild pro Element; für den Rest ist eine einzige kanonische Zeile bereits die exakteste Darstellung, und die äußere Notation eines Wrappers gehört seinem Plugin.
- Spielraum: Ein Plugin-Typ, der einen der drei Werte speichert, kann dieselben Editoren übernehmen, indem er den passenden
StudioCellEditorHint-Archetyp deklariert (siehe Plugin-Erstellung §4.16).
Besitz-Färbung ist nur Tabelle-versus-Code
- Was: Die Seitenleiste/Legende unterscheidet genau zwei Ursprünge — echte Tabellen-Tabs und virtuelle Code-Registry-Tabs. Es gibt keine dritte Klassifikation „generiert" und keine Besitz-Färbung pro Spalte.
- Warum: Der Ursprung wird vom Tab selbst abgeleitet, den das Fenster bereits mit Sicherheit kennt; eine Klassifikation pro Spalte bräuchte einen weiteren Erweiterungspunkt, um wahrheitsgemäß zu sein, und kein Konsument hat danach gefragt.
- Nicht dasselbe wie die Farbe einer Tabelle:
@stylelässt eine Tabelle ihre eigene Farbe benennen, und diese Farbe ist Anzeigemetadaten, die der Autor gewählt hat — sie sagt nichts darüber aus, woher die Tabelle stammt. Die beiden Färbungen werden aus unterschiedlichen Quellen gelesen und verschmelzen nie.
Referenz-Dropdowns beantworten Mitgliedschaft, nicht Reihenfolge
- Was: Eine
RecordId@Tab-Zelle hat jetzt ein durchsuchbares Dropdown (und eine Checkliste fürList<>), aber das Dropdown der Listenzelle fügt nur Elemente hinzu und entfernt sie — es kann keines verschieben. Das Neuanordnen einer Liste erfolgt auf der Canvas, wo jedes Element seine eigene Zeile hat. - Warum: Ein Dropdown beantwortet „was ist hier drin"; „welche Position" braucht eine Oberfläche, die Dinge aufreiht, was die Canvas bereits ist. Dies an zwei Stellen zu duplizieren, wären zwei Antworten, die gepflegt werden müssten.
- Außerdem: Das Dropdown hängt sich nur an eine einfache Referenzspalte ohne Wrapper an. Der Text einer Wrapper-Zelle trägt die eigene Notation des Wrappers, sodass das Einfügen eines bloßen Schlüssels dort den Wert zerstören würde — das Hineingreifen in einen Wrapper ist die Aufgabe eines registrierten Cell-Widgets (siehe Plugin-Erstellung).
Die All-Suche liest per Bake erzeugte Daten im Editor und die Live-Sitzung im Browser
- Was: Der All-Eintrag des Data Studio durchsucht die per Bake erzeugten Datenbanken, benötigt also zunächst einen erfolgreichen Import und aktualisiert sich selbst, wenn ein Import abgeschlossen ist oder sich die aktiven Einstellungen ändern. Der All-Eintrag der Web-App durchsucht die Werte, die die Sitzung gerade jetzt zeigt, vorgemerkte Bearbeitungen eingeschlossen. Übereinstimmung, Ergebnisreihenfolge und die 50-Zeilen-Seite sind in beiden derselbe Code, und in beiden wird ein Ergebnis doppelgeklickt (oder mit Enter bei ausgewählter Zeile), um diese Tabelle mit der markierten Zelle ausgewählt zu öffnen.
- Warum: Der Browser hat keine per Bake erzeugten ScriptableObjects; was er hat, ist die Live-Sitzung — und mit dem Wert auf dem Bildschirm zu antworten, ist genau wofür eine Browser-Sitzung da ist. Der Editor liest weiterhin die per Bake erzeugte Wahrheit, die er bereits hat.
- Grenze: Im Editor wird eine Bearbeitung, die vorgemerkt, aber noch nicht übernommen ist, von All erst gefunden, nachdem ein Import gelaufen ist, und ein Ergebnis aus einer Tabelle, die die Sitzung nicht geladen hat, navigiert nicht — ein Hinweis unter der Liste sagt warum. Im Browser wird eine vorgemerkte Bearbeitung sofort gefunden, und jedes Ergebnis lässt sich ansteuern.
5. Performance
- Der Normalpfad ist linear und schnell: 50,000 Zeilen × 20 Spalten ≈ 628 ms (laufender Editor, Mono; 144 ms Headless); 50 Tabs × 2,000 Zeilen mit 180k Referenzzellen ≈ 294 ms. Typische Projektgrößen sind kein Thema.
- Der Speicherverbrauch ist linear, aber boxing-intensiv: ≈ 59 Bytes/Zelle dauerhaft belegt (≈ 138 Spitzenwert während des Imports). An der Zellen-Obergrenze von Google Sheet (~10M Zellen) hochgerechnet ergibt das ~6.3 s Import, ~590 MB dauerhaft belegt, ~1.4 GB Spitzenwert — bei extremen Größen sind Low-Spec-/32-Bit-Umgebungen zu beachten. (Eine spaltenorientierte IR ist ein anerkannter Backlog-Punkt.)
- Die Authoring-Tabelle ist oberhalb von 200 Zeilen zeilen-virtualisiert, sowohl im Editor als auch im Browser, sodass das Öffnen einer großen Tabelle nicht länger ein Widget pro Zeile baut. Nicht fensterbasiert ist die Pro-Zeile-Logik, die anders antworten würde, wäre sie es — Breiten-Abtastung, Suche, Sortierung, Koordinaten, das Staging-Overlay. Details und die zwei Randfälle stehen in §4.
- Der Fehlerpfad ist ebenfalls linear: Selbst wenn Referenzen massenhaft brechen, bleibt die Berechnung der nächstliegenden Vorschläge beschränkt — ein Vorschlagsbudget pro Feld plus eine längen-vorgefilterte, früh abbrechende Editierdistanz halten sie annähernd linear in der Anzahl der defekten Referenzen (≈ 45 ms bei 4,000 defekten Referenzen, Headless; gültige Daten in derselben Größenordnung ≈ 2.7 ms). Das Umbenennen eines referenzierten Tabs bricht Referenzen von vornherein nicht massenhaft: Die Umbenennung schreibt die referenzierenden
@type-Zellen um.
6. Demo-Szene
- Die Beispiele sind selektive Importe — die beiden Demo-Beispiele und ihre Szenen sind standardmäßig nicht vorhanden. Sie werden als Unity-Pakete ausgeliefert (
Assets/SheetForge/Examples/SheetForgePluginDemo.unitypackageundSheetForgeCoreDemo.unitypackage); importieren Sie eines davon (Doppelklick, oder die Schaltfläche Plugin Demo importieren/Core Demo importieren im Fenster „Erste Schritte"), umAssets/SheetForge.PluginDemo/…bzw.Assets/SheetForge.CoreDemo/…wiederherzustellen. Bis dahin sind die Beispiele überhaupt nicht in Ihrem Projekt vorhanden — sie werden ausschließlich als diese Pakete ausgeliefert —, sodass sie niemals mit Ihrem Projekt kollidieren können — das Kernprodukt ist ohne sie vollständig eigenständig. - Erfordert zuerst einen Import (pro Maschine) — die Addressables-Adressen, die es lädt, sind ein nicht committeter Cache. Davor zeigt es eine Hinweismeldung an.
- Für die Demos ist keine Namespace-Einstellung nötig — die committeten Beispieltypen verwenden den Standard-Namespace
SheetForge.Generatedmit einem Klassen-PräfixExample*, sodass ein erneuter Import einer Demo sie ohnegeneratedNamespace-Einstellung an Ort und Stelle regeneriert.
7. Plugin-Erweiterung — ausgelieferte Nahtstellen (mit Grenzen) und was weiterhin reserviert ist
Sechzehn Erweiterungsverträge sind ausgeliefert, jeder Einzelne allein durch Registrierung und ganz ohne Änderungen am Core — die vollständige Liste steht in Plugin-Erstellung. Alle sechzehn werden per Entdeckung gefunden (Unitys TypeCache; der Scan der hochgeladenen Assembly im Browser), ohne Assembly-Referenz und ohne zu bearbeitendes Manifest. Die elf Core-Verträge erhalten eine Registry, in die sie eintragen, was sie beisteuern, während die fünf Editor-Verträge — Graph-Widget, Inspector-Aktion, Cell-Editor-Provider, Panel-Provider und Source-Provider — einfach entdeckt und so verwendet werden, wie sie sind.
Fünf der ausgelieferten Nahtstellen tragen Grenzen, die es wert sind, hier festgehalten zu werden, statt Sie sie selbst entdecken zu lassen:
Benutzerdefinierte Zelltypen referenzierbar machen — volle RecordId@Tab-Parität für Ihre eigene Notation
-
Was: Ein registrierter Zell-Parser, der zusätzlich
IReferencingCellTypeimplementiert (und dessen WertIRefBearingValueimplementiert), sagt dem Core, wie er den in seiner eigenen Notation vergrabenen Schlüssel liest und umschreibt. Diese Spalte erhält dann alles, was eine eingebaute Referenz erhält:- Integritätsprüfung mit Vorschlägen für die nächstliegende Übereinstimmung;
- Propagierung von Schlüssel-Umbenennungen unter Erhalt der Nutzlast (
attack:add:10→power:add:10); - Graph-Kanten und Ports, den
▾-Picker, Rückreferenz-Zählungen; - Waisen-Erkennung und exportierte Dropdown-Regeln.
Die Erkennung ist ein Cast des bereits registrierten Parsers — es gibt keinen neuen Registrierungskanal, und ein benutzerdefinierter Typ, der es nicht implementiert, bleibt bit-genau unverändert. Siehe Plugin-Erstellung §4.4a.
-
Grenzen: Eine Nutzlast darf kein
;enthalten — der Core teilt eine Listenzelle in Elemente auf, bevor Ihr Parser den Text überhaupt sieht, sodass ein Semikolon innerhalb eines Werts in zwei Elemente zerrissen würde (dieselbe Einschränkung, die Wrapper-Typen tragen). Und@targetmuss einen echten Tabellen-Tab benennen: Der virtuelle Tab einer Code-Registry wird mitUnknownTargetTababgelehnt, genau wie beiRecordId@Tab. Diese Einschränkung ist es, die es der eigenen Meldung nicht aufgelöster Referenzen und der Umbenennungs-Propagierung des Core erlaubt, unverändert zu gelten.
<>-Wrapper-Typen (MyWrapper<T>) — mit Ablehnungsregeln
-
Was: Ein Plugin registriert eine generische Wertform (z. B.
Pair<int>=1~2) überICellWrapperType; der Core löst den inneren Typ rekursiv auf (siehe Tabellensyntax). -
Ablehnungsregeln:
Pair<List<T>>wird abgelehnt — eine Liste darf nicht innerhalb eines Wrappers stehen, undListbleibt flach und ganz außen.Pair<int>@Tabwird abgelehnt — setzen Sie das@auf das innere Blatt:Pair<RecordId@Tab>.Pair<int?>/Pair<int=1>werden abgelehnt — Optionalität/Standardwerte sind auf Feldebene, nicht Teil des inneren Typs.
List<Pair<T>>ist erlaubt, aber das eigene Trennzeichen des Wrappers muss sich von;(dem Listentrennzeichen) unterscheiden — eine Verantwortung der Plugin-Erstellung, die der Core nicht erzwingen kann.
Benutzerdefinierte Strukturmarkierungen (@yourMarker) — nur für Metadaten pro Spalte
- Was: Ein Plugin registriert eine
@marker-Zeile überIStructuralMarkerDefinition/ISheetForgeMarkerPluginund verallgemeinert damit die spaltenweise Validierung von@overlap. Der Wert wird alsFieldSchema.MarkerValues-Metadaten gespeichert. - Grenzen: Eine Markierung besitzt nur ihre spaltenweise Wertvalidierung — sie übernimmt nicht das Parsen einer zeilenweiten Datenform (Normalisierung bleibt der Weg, Datenformen auszudrücken). Und Codegen bakt Markierungswerte nicht: Wie
@overlapsind sie nur Validierungs-/Anzeige-Metadaten, unsichtbar für den Schema-Fingerabdruck — sodass nichts Markierungsbezogenes den generierten Code oder das per Bake erzeugte SO erreicht.
Farb-Presets — die Oberflächen, die wir bemalen, nicht Unitys Widgets
- Was: Ein Plugin registriert ein Farb-Preset über
ISheetForgeThemePlugin/ThemeRegistry; es erscheint unterPreferences ▸ SheetForge ▸ Themeneben den eingebauten Presets Default und High contrast und wirkt sich nur aus, wenn der Nutzer es auswählt (das Registrieren übernimmt nie eigenmächtig den Bildschirm). Ein Preset überschreibt nur die Slots, die es benennt — jeder andere Slot behält die Produktvorgabe, sodass Presets gültig bleiben, während Slots hinzukommen. - Grenze — gemischtes Erscheinungsbild ist zu erwarten: Das Theme deckt ab, was SheetForge selbst zeichnet (Fensterhintergründe, Kopfzeilen, Text, Akzente, Grid- und Staging-Farben). Native Unity-Widgets, die innerhalb dieser Fenster gezeichnet werden — Schaltflächen-Rahmen, Feldränder, Popup-Pfeile — folgen weiterhin dem Editor-Skin, den Unity ein Paket nicht umgestalten lässt. Wählt man also Always light, während der Editor den dunklen Skin verwendet, ergibt das eine helle SheetForge-Oberfläche mit dunklen nativen Widgets darauf. Stellen Sie den Editor-Skin passend ein, wenn Sie ein einheitliches Erscheinungsbild möchten.
- Grenze — nur Farbe: Presets tragen Farben (
0xRRGGBBpro Slot). Abstände, Schriftgrößen und Layout sind nicht themefähig, und durchscheinende Füllungen (Badge-Hintergründe, der Modal-Scrim) leiten sich aus einer Slot-Farbe plus einem festen Alphawert ab, statt separat einstellbar zu sein.
Deklarative Authoring-Oberflächen — ein absichtlich begrenztes Vokabular
- Was:
ISheetForgeStudioPluginlässt ein Paket Verben, Panels, Spalten-Badges und Cell-Editor-Formen als Daten beschreiben, sodass eine Registrierung sowohl vom Editor als auch vom Browser gleichermaßen gezeichnet wird. Das Vokabular ist fest und wächst nur durch Anhängen: fünf Aktions-Platzierungen, dreizehn Node-Arten, sieben Cell-Editor-Archetypen (die beiden neuesten,CurveEditorundGradientEditor, sind die, die die eingebauten Kurven- und Verlaufstypen verwenden). - Grenze — es ist kein UI-Framework. Beliebiges Rendering, zusammengesetzte Eingaben und mehrstufige Abläufe haben hier keine Worte, und sie hinzuzufügen würde bedeuten, für immer ein Miniatur-UI-Toolkit zu pflegen. Dafür ist
IStudioPanelProviderda: Registrieren Sie es unter derselben Id wie ein beschriebenes Panel, und der Editor zeichnet das umfangreiche, während der Browser das beschriebene zeichnet. Es gibt keine reine Web-Ausweichmöglichkeit — der Browser kann keinen UIToolkit-Typ laden, und das Gegenteil vorzutäuschen würde die Erweiterung eines Plugins nur auf einem Bildschirm zeigen. - Grenze — die Fähigkeiten einer Aktion sind genau vier: eine Zelle vormerken, mehrere Zellen als einen Undo-Schritt vormerken, einen Datensatz fokussieren, ein Neuzeichnen anfordern. Das Verb eines Plugins ist also eine gewöhnliche vorgemerkte Bearbeitung, die dasselbe Gate, dieselbe Vorab-Validierung und denselben Push durchläuft wie eine von Hand getippte. Die Authoring-Session selbst wird bewusst nicht offengelegt.
- Nullfeuern, nie Falschfeuern, für Beobachter:
IPipelineObserverfeuert am Ende eines expliziten Import-Zyklus. Zwei Pfade erreichen diesen Punkt überhaupt nie — ein Lauf, der stoppt, bevor die Pipeline startet (keine aktiven Einstellungen; Addressables nicht installiert), und ein Codegen→Kompilierung-Abschnitt, der durch einen Kompilierungsfehler unterbrochen wird. Brauchen Sie „ein Import wurde versucht", kombinieren Sie dies mit dem editor-seitigenImportEvents-Bus.
Weiterhin entworfen, aber nicht gebaut (noch kein Konsument)
- Markierungen für zeilenweite Datenformen (z. B. eine Markierung, die eine 2D-Matrix als einzelnes Feld liest) — bewusst nicht gebaut: Eine Markierung besitzt spaltenweise Validierung, nicht Zeilen-Parsing, und Normalisierung (Referenzen +
type-Spalte +List<T>) ist ausdrucksstark genug für alles. Die Registrierungs-NahtstelleMarkerRegistryselbst wird ausgeliefert; nur diese formparsende Interpretation ist reserviert. - Das Backen benutzerdefinierter Markierungswerte in generierten Code — außerhalb des Umfangs, bis ein Konsument Markierungs-Metadaten als Codegen-Konstanten/-Attribute benötigt.
- SO-Container pro Datensatz / mit Lazy-Load — design-fertig, ungebaut; der aktuelle Codegen erzeugt ausschließlich vollständig ladende Database-SOs pro Tab.
8. Schema-Evolution
- Export/Push erfordern nach einer Schema-Änderung ein frisches Bake — ein veraltetes Bake schlägt mit
ExportSchemaMismatchfehl (Fingerabdruck-Diskrepanz). Die Ablehnung bietet jetzt an, diesen Import für Sie auszuführen: eine Bestätigung startet ihn, und danach wird nichts automatisch exportiert oder gepusht — sobald der Import abgeschlossen ist, drücken Sie einfach erneut die ursprüngliche Aktion. - Der erste Import nach einer Schema-Änderung läuft intern zweistufig ab (Codegen → Kompilierung → Bake) — automatisch, eine Benutzeraktion; nur ein Kompilierungsfehler stoppt ihn (sicherer Abbruch, umsetzbarer Hinweissatz, maximal 3 Versuche).
9. Lokalisierungsumfang
Bericht-Detail-Fragmente (fehlerhafte Werte, Vorschläge), Low-Level-Exceptions und Entwickler-Logs sind Inline-Englisch innerhalb des lokalisierten Berichtsgerüsts — Laufzeit-Interpolationen können keine Sprachtabellen-Schlüssel sein (branchenübliche Grenze). Alles vom Editor Gezeichnete sowie das Berichtsgerüst und die Warum-/Wie-Sätze sind vollständig in allen 10 Sprachen lokalisiert.
Alle zehn Sprachen sind vollständig übersetzt. Jeder Schlüssel in jeder Sprachtabelle trägt eine echte Übersetzung — das Data Studio, die Theme-Einstellungen, Dialoge und Log-Zeilen eingeschlossen. Die Schlüsselparität über die zehn Dateien hinweg wird testseitig erzwungen, sodass nichts auf einen rohen Schlüssel zurückfällt oder einen Platzhalter zerstört.
Eine Handvoll Einträge pro Sprache liest sich tatsächlich genauso wie im Englischen, und das ist eine Übersetzungsentscheidung, kein ausstehender Durchgang: Es sind Symbole und reine Platzhalter-Strings (—, +), Eigennamen und Formatnamen (Google Sheets, SHA-256) sowie Wörter, die eine Sprache tatsächlich genauso schreibt wie das Englische (OK, Alpha).
Die eigenen Labels eines Plugins stehen nicht in der Core-Tabelle: Registrieren Sie sie mit ISheetForgeStringsPlugin, damit sie der Sprache des Nutzers folgen, oder lassen Sie sie unregistriert, dann werden sie unverändert angezeigt.
10. Editor-Interaktionen
- Ctrl+Z-Umfang: Ein fokussiertes Textfeld verbraucht Ctrl+Z zuerst (Standard des Betriebssystems); nach einem erfolgreichen Übernehmen wird der Staging-Verlauf gelöscht — Undo reicht niemals in das hinein, was bereits in die Tabelle geschrieben wurde (die Tabelle ist kanonisch).
- Sprachwechsel ist während Import/Export/Push gesperrt (er löst eine Neukompilierung durch Menü-Regenerierung aus). Theme-Wechsel sind nicht gesperrt — sie lösen nie eine Neukompilierung aus, sodass Helligkeit und Preset jederzeit gewechselt werden können, auch während eines laufenden Vorgangs.
- Theme und Sprache sind pro Benutzer (EditorPrefs), nicht pro Projekt — jedes Teammitglied behält seine eigene Wahl, und keine davon taucht in der Versionskontrolle auf. Die Wahl eines Nicht-Standard-Farb-Presets schreibt ein generiertes Stylesheet unter
Assets/SheetForge/Editor/Generated/(gitignored, selbstheilend); das Standard-Preset schreibt nichts und löscht es. - Generierter Code + per Bake erzeugte SOs + die Addressables-Gruppe sind maschinenspezifische, gitignorete Caches — jede Maschine führt einmal einen Import aus; Spielcode lädt über die Adresse, niemals über eine direkte Szenenreferenz.
11. Lizenzierung
Das Repository enthält einen LICENSE-Hinweis: Die Unity Asset Store EULA ist die maßgebliche Vereinbarung, mit einem Hinweis zur Repository-Einsicht (Quellcode einsehbar zu Referenzzwecken und für lizenzierte Käufer; keine Weiterverbreitung/kein Weiterverkauf außerhalb der EULA ohne schriftliche Genehmigung). Fremdcode: keiner — einschließlich des handgeschriebenen OOXML-xlsx-Readers/-Writers.
12. Verifizierter Zustand (zum Release)
- Doppelter Test-Harness: 2,150 Headless-.NET-Tests (2,150 bestehen) + 3,021 EditMode-Tests (3,021 bestehen, 0 Fehlschläge, 4 übersprungen). Diese beiden Zahlen sind die einzige Stelle, an der die Zählungen genannt werden; jede andere Seite verlinkt hierher.
- Die vier Skips sind der Live-Google-Round-Trip, der nur läuft, wenn Service-Account-Zugangsdaten in der Umgebung vorhanden sind, und wurde in diesem Lauf übersprungen. Mit Zugangsdaten wurde er wiederholt gegen eine echte Tabelle durchlaufen — Abrufen → Push, einschließlich der Erkennung von Konflikten durch verschobene Zeilen, gebietsschema-unabhängiger Float-Behandlung, eines tab-übergreifenden gemischten Batches und eines vollständigen Dispatcher-Laufs, der genau einen zusammengeführten Bericht und genau einen automatischen erneuten Import pro Sendevorgang bestätigt. Ergebnis: 4/4 grün.
- Die Web-App hat ihre eigenen Gates, alle grün: Type-Check, Lint, 414 Unit-Tests, ein WebAssembly-Publish-plus-Smoke-Lauf (der eine echte Plugin-DLL lädt), ein Produktions-Build, 56 Ende-zu-Ende-Browsertests und eine sprachübergreifende Konstantenprüfung (sechs Unity↔Web-Paare: Host-Version, Plugin-Format, Registry-Schema-Version, OAuth-Scope, Host-Assembly-Namen, Zeilen-Fenster-Schwellen).
- Alle kompilierten Produkt-asmdefs: 0 Fehler, 0 Warnungen. (Die Beispiel-asmdefs — zwei in jeder Demo — entstehen erst, wenn Sie ein Demo-Paket importieren, und werden auch erst dann kompiliert.)
- Schutztests grün: null koreanische Literale im Produktquellcode, null Domänenvokabular in den Kernel-Nahtstellen (beide überspringen
/Samples~/— das Beispiel ist Domäneninhalt), 10-sprachige Schlüsselparität. - Die Konsumenten-Simulations-Assembly ohne IVT kompiliert allein gegen die öffentliche API (compilererzwungen), und eine Mini-Plugin-Sonde ohne IVT implementiert dort fünfzehn der sechzehn Erweiterungsverträge (
ISheetForgePlugin/ Validator / Edge / Marker / Vorlage / Graph / Code-Registry / Theme / Studio-UI / Strings / Pipeline /ISheetSourceProvider/ Studio-Widget / Studio-Inspector-Aktion / Studio-Cell-Editor) allein über die öffentliche Oberfläche — sodass die Öffentlichkeit der Verträge bewiesen bleibt, auch wenn das Plugin-Demo-Beispiel nicht kompiliert wird. Der sechzehnte,IStudioPanelProvider, gibt einVisualElementzurück und wird stattdessen von einem editor-seitigen Test geprüft. Dieselbe Sonde implementiert außerdem die optionalen Capability-Interfaces, einschließlichIReferencingCellType/IRefBearingValue, und übt sie über die öffentliche Oberfläche aus (Erkennung per Cast, alle fünf Hooks, Erhalt des Rests).
Punkte, die erst zum Zeitpunkt der Asset-Store-Einreichung verifiziert werden können (nicht im Repository): das Verhalten des .unitypackage-Installationsdialogs, die Portal-Abhängigkeitsdeklaration, der Ausschluss von Test-Assemblies aus dem verteilten Paket und eine erneute 0-Warnungen-Prüfung an einem sauberen Projekt.
13. Lokalisierungstabellen (Spieltext)
Die Grenzen von Lokalisierungstabellen und der Unity-Localization-Bridge, ehrlich benannt. (Das Paket selbst ist optional – siehe §1.)
Die Bridge ist eine Einbahnstraße, und externe Tabellenänderungen werden erfragt – nie automatisch zusammengeführt
- Was: Die Synchronisierung läuft nur Tabelle → StringTables. Die Bridge markiert die Tabellen, die ihr gehören, und erstellt bei jeder Synchronisierung einen Fingerabdruck; wurde eine StringTable seither von etwas anderem bearbeitet – dem Localization-Tables-Fenster, Unitys eigener Google-Sheets-Erweiterung, einem XLIFF-Import –, stoppt die nächste Synchronisierung und fragt nach: Überschreiben von der Tabelle aus, oder Abbruch mit einem Unterschiedsbericht.
- Warum: Zwei schreibende Oberflächen über denselben Daten enden in stillen Überschreibungen. Die Tabelle ist kanonisch, daher muss die andere Oberfläche explizit sein, nicht still.
- Workaround: Leiten Sie Übersetzungen über die Tabelle – die Übersetzungs-Arbeitsmappe (xlsx-Export + reiner Sprachspalten-Teilimport) existiert genau dafür.
Ein außerhalb des Studios umbenannter Schlüssel ist ein Löschen plus ein Hinzufügen
- Was: Das Umbenennen eines Schlüssels im Data Studio benennt den Tabelleneintrag an Ort und Stelle um und bewahrt die interne Id, an die
LocalizedString-Referenzen binden – Szenen-Referenzen überleben. Das Umbenennen des Schlüssels direkt in der Tabellenquelle (Google Sheets, Excel) ist nicht davon zu unterscheiden, einen Schlüssel zu entfernen und einen anderen hinzuzufügen: Die Bridge legt einen frischen Eintrag an, und der alte wird zur Waise, während Szenen-Referenzen weiterhin auf die Waise zeigen. - Warum: Ein Textvergleich auf Zeilenebene kann eine Umbenennung nicht ohne Raten von einem Löschen-plus-Hinzufügen unterscheiden, und ein falsches Raten würde Referenzen still umbinden.
- Workaround: Benennen Sie Schlüssel im Data Studio um (in beiden Hosts); der Waisenbericht fängt die Folgen einer externen Umbenennung ab.
Verwaiste Tabellenschlüssel bleiben standardmäßig erhalten
- Was: Ein Schlüssel, der in der StringTable vorhanden ist, aber nicht mehr in der Tabelle, wird beibehalten, als Waise gemeldet und nur über die explizite Bereinigungsaktion entfernt – oder automatisch, wenn Sie die Einstellung Beim Synchronisieren löschen aktivieren. Nichts wird als Nebeneffekt gelöscht.
- Warum: Eine fehlende Zeile in der Tabelle kann mitten in der Bearbeitung ein Versehen sein; Übersetzungen deswegen zu zerstören, wäre nicht wiederherstellbar.
Nur StringTables – AssetTables werden nicht abgedeckt
- Was: Die Bridge füllt
StringTable-Collections. DieAssetTable-Achse von Unity Localization (lokalisierte Sprites, Audio, Prefabs) wird nicht aus Tabellen synchronisiert. Ein anerkannter Backlog-Punkt. - Workaround: Verwalten Sie AssetTables mit den eigenen Werkzeugen des Pakets; die Bridge lässt sie unberührt.
XLIFF und Pseudo-Sprachen werden nicht neu implementiert
- Was: Die synchronisierten Tabellen sind gewöhnliche Unity-Localization-Tabellen, daher funktionieren der XLIFF-Export/-Import und die Pseudo-Lokalisierung des Pakets unverändert auf ihnen. SheetForge fügt keine zweite Implementierung hinzu.
- Grenze: Was diese Werkzeuge in die Tabellen zurückschreiben, zählt als externe Bearbeitung (erster Eintrag oben). Behalten Sie die Tabelle als Quelle der Wahrheit, und transportieren Sie Übersetzungen über die Übersetzungs-Arbeitsmappe.
Keine sprachspezifischen Smart-Format-Helfer werden ausgeliefert
- Was: Die Spalte
smartmarkiert einen Eintrag als Smart String, aber SheetForge liefert keine eigenen Grammatik-Formatter – die Auswahl koreanischer Partikel zum Beispiel ist bewusst nicht enthalten. - Workaround: Die Smart-Format-Erweiterungspunkte des Pakets bleiben für selbst geschriebene Formatter vollständig verfügbar.
Schlüsselkonstanten werden ASCII-bereinigt
- Was: Die generierten
{Tab}Keys-Konstanten verwandeln jedes Zeichen außerhalb von ASCII-Buchstaben, Ziffern und_in_(Kollisionen erhalten ein numerisches Suffix), sodass ein Nicht-ASCII-Schlüssel einen unlesbaren Konstantennamen ergibt – der Schlüssel selbst funktioniert überall weiterhin. - Workaround: Halten Sie Schlüssel ASCII (
ui.ok,dialog.intro), wenn Sie die Konstanten verwenden. Wie die tabellendefinierte Enum-Datei generiert auch die Konstantendatei immer in den Einstellungsordner – derselbe Assembly-Hinweis gilt entsprechend.
Die Web-App verfasst Lokalisierungstabellen; die Synchronisierung gehört dem Editor
- Was: Authoring, Validierung, Abdeckung, das Prägen neuer Schlüssel, die Sprachlinse und die Übersetzungs-Arbeitsmappe funktionieren allesamt im Browser. Das Schreiben von StringTables nicht – der Browser hat kein Unity-Projekt, in das er schreiben könnte.
- Warum: Ehrlicher Umfang, kein fehlendes Feature: Die Tabellen leben im Projekt.
Verwandte Seiten
- FAQ & Fehlerbehebung – die symptomorientierte Sicht auf viele dieser Einträge
- Quellen, Export & Push – die Google-/xlsx-Grenzen im Kontext
- Data Studio – die Authoring-Grenzen im Kontext