本文へスキップ
SheetForge

コアコンセプト

シートは唯一の信頼できる情報源である

あなたのデータには、正規の形式がただ一つだけ存在します。それが シート です。それ以外はすべて、そこから導出されます。

  • IR(不変の定義群)は、シートを検証・組み立てた結果です。
  • 生成された C# クラス は、IR のスキーマを強く型付けしたものです。
  • ベイクされた ScriptableObject は、IR の値を読み込み可能にしたものです——ルックアップキャッシュ であって、独立した情報源ではありません。

すべての変更はシートを経由し、実際のものになるには再インポート時の検証を通過しなければなりません。ベイクされた SO を直接編集すると、二つ目の情報源が生まれ、検証を迂回してしまいます——この製品は、それをワークフローとして意図的にサポートしません。

(インスペクターの「テスト編集」トグルは 一時的な ランタイム実験のために存在します。書き戻されることはなく、再インポートすると消去されます。)

これが重要な理由: SO を情報源として扱うプロジェクトは、検証されていないデータがシートから乖離していき、それを一致させる手段がなくなってしまいます。ここでは、整合性の確保は構造的です——常にシートから再生成するのです。

IR — 不変で検証済みの組立体

IR は検証が生み出すものです。各タブごとに SheetTable(スキーマ + レコード)が存在し、そのセルはすでに型付けされた値(intfloat、enum 値、レコード参照、アセット参照、リスト、プラグインのカスタム型)になっています。

主な特性:

  • 部分的な組み立てはありません。 どこか一箇所でもエラーがあれば、IR は構築されません(ImportResult.Success == false ⇔ Registry == null — これは絶対不変条件です)。
  • null はありません。 空のオプションセルは、ただちにその型のデフォルト値として実体化され、IsDefaulted としてフラグが立てられます——利用側が null チェックをする必要は一切ありません。
  • 不変です。 IR は組み立てられた後は読み取り専用になります。出口(コード生成・ベイク・エクスポート)はそれを読み取るだけで、決して変更しません。

パイプライン

fetch → parse markers/schema → parse cells → validate (keys, references,
@overlap, asset keys, domain rules) → assemble IR → codegen (.cs) → bake (SO)
       └──────────────── collect ALL diagnostics ────────────────┘
  • 検証はすべてを収集します。 一回の実行で、問題の完全なリストが得られます——エラーごとに、どこで/何が/なぜ/どうすればよいか——「一件直しては再インポート」を繰り返す必要はありません。
  • コード生成は最終段階です。 .cs ファイルの書き込みはドメインリロードを引き起こすため、検証と値の組み立てが終わった後に行われます。パイプラインは、リロードが安全に行われ、その後チェーンが自動的に再開されるように構成されています。
  • エラーは構造化されたオブジェクトであり、文として描画されます。 各エラーには、タブ・1始まりの行・列記号 および フィールド名、問題のある値、違反したルール、そして実行可能な提案(タイプミスに対しては最も近い候補の提案付き)が含まれます。同じオブジェクトは、ログや CI 向けにマシン可読な座標としても描画されます。

自動インポートチェーン

スキーマが新規または変更されている場合、一回のインポート実行は内部的に次のことを行います。

  1. 生成コードを書き出す → Unity がコンパイルする → ドメインリロード。
  2. リロード後、チェーンは 自力で再開し、ベイクを完了させます。

手動で何かを再実行する必要は一切ありません。コンパイルが失敗した場合(例えば、名前変更で変わったばかりのフィールドをゲームコードが参照している場合)、チェーンはループする代わりに、実行可能なコンソール文とともに 安全に中断します(試行上限3回、再開ログあり)。

強い型付け、ランタイムでのパースなし

コード生成は @name / @type / @desc を読み取り、タブ Foo ごとに次を出力します。

  • FooDefinition — 強く型付けされたレコードクラスで、列ごとに一つのフィールドを持ちます。@desc は XML ドキュメントコメントとインスペクターのツールチップになります。
  • FooDatabase : DefinitionDatabase — タブごとのコンテナ SO で、Records、遅延評価の id ルックアップ、SchemaFingerprint を持ちます。

ベイクは実際に型付けされたフィールドを書き込みます——ランタイムでのテキストパースは一切なく、ランタイムリフレクションもありません。これにより IL2CPP セーフになります(ストリッピングの危険がありません)。

アドレスによる読み込み — キャッシュが共有可能であり続ける仕組み

ベイクされた SO は、マシンごとの GUID を持つ、マシンごとのキャッシュです。そこへの直接的なシーン参照は、マシンをまたぐと壊れてしまいます。そこで代わりに:

  • インポートは各 Database SO を、Addressables グループ SheetForge の安定したアドレス "SheetForge/{tab}" に自動登録します(再ベイクすると、新しい GUID が同じアドレスに再リンクされ、削除されたタブはクリーンアップされます)。
  • ゲームコードはアドレスで読み込みます: SheetForgeDatabases.LoadAsync<FooDatabase>("Foo")
  • Addressables のグループアセットは gitignore 対象で、自己修復します(存在しない場合はインポートによって再作成されます)。

Baseline — ラウンドトリップがシートを保持する仕組み

インポート時に、各タブの 構造(マーカー行、列の順序、コメント、手書きのテキスト)を正規化したスナップショットが baseline として保存されます。Export は、その baseline の 構造 に現在の SO の を差し込みます。

そのため、シート → インポート → Export → シートというラウンドトリップは、シートを構造的に 100% 保持し、値も意味的に保持します:

  • 1.01 は値が同一であるため許容されます。
  • 浮動小数点数は最短のラウンドトリップ形式を使います。
  • 小数点は常にロケールに依存しない . です。

コミットされるものと再生成されるもの

成果物方針
シート(ローカルファイル)/ Googleシート情報源そのもの。 コミット/共有されます。
ベイクされた Database SO(Assets/SheetForgeBaked)gitignore 対象の、マシンごとのキャッシュ — インポートを実行して再生成します。
生成コード(Assets/SheetForgeGenerated)コミットすることを推奨します。 これはプロジェクト自身のソースであり、Assets/SheetForge の外にあるため製品を再インストールしても削除されず、コミットしておけば誰かがインポートを実行する前から新規クローンがコンパイルできます。出力は決定的(deterministic)なので、チームメイトのインポートも同一のバイト列を生成します。代わりに gitignore する方法も有効で、その場合は次のインポートで再生成されます。この既定値より前からあるプロジェクトは、Assets/SheetForge/Runtime/Generated が空になるまでそこへ生成し続けます — スタートガイド を参照。
Addressables の SheetForge グループアセットgitignore 対象で、自己修復します。初回作成時に生じる一行の設定差分はコミットしないでください。
ドメインパッケージ自身の Generated フォルダーそのパッケージ自身の判断に委ねられます。 同梱の SheetForge.PluginDemo サンプルは、クローン直後でもすぐにコンパイルできるよう、生成コードをコミットしています。
インポート設定アセットあなた自身が管理するものです。サービスアカウントキーの パス はリポジトリに含めないでください(SHEETFORGE_SHEETS_KEY 環境変数を使ってください)。

変更なしの拡張

登録契約により、プラグインは Core への変更ゼロ でパイプラインに参加できます:

  • セルタイプパーサー(ラッパー型を含む)、ドメインバリデーター、エッジコントリビューター
  • カスタム構造マーカー、「シート作成」テンプレート、インポートソースプロバイダー
  • Data Studio のキャンバスオーバーライド・コードレジストリ・ウィジェット・アクション・セルウィジェット・カラープリセット・UI 文字列

Core がドメインパッケージを参照することは決してなく、この一方向の依存関係はコンパイラによって強制されます。正式な一覧——そしてその数——は プラグイン作成 にあります。

関連ページ