🧾

CCK用のUnityエディタ拡張を作る時の雑多メモ

2025/02/26に公開

CCK(Cluster Creator Kit)向けエディタ拡張を作る時に役立つ知識やメモやネタとかを浅めに雑多にまとめる記事です。
一般的なエディタ拡張については、既に世に情報があるのであまり触れません。

最初に

VisualStudioで作業する場合は、パッケージマネージャー経由ではなくコードから直接入れると便利!
https://zenn.dev/vkao/articles/66cad6475be26f


公式系情報

APIなどが公開されつつあるので、それのまとめ。

公式リファレンス

https://docs.cluster.mu/creatorkit/world/unity-spec/extend-editor/
CCK向けエディタ拡張用に、公式が用意している以下のAPIを紹介している。現在(CCK2.31.0)では1つのみ。もっと増えて欲しい。

  • アップロード前後のコールバック
    ◯◯ジェネレーター的なエディタ拡張の場合に重宝する。

https://docs.cluster.mu/creatorkit/world/unity-spec/
アップロード時に何が起きているかの概要。
エディタ拡張作ったものの、ビルドでエラーとなった場合にまずこのあたりを思い出したい。

Cluster World Tools

https://creator.cluster.mu/2023/06/19/clusterworldtools/
https://github.com/ClusterVR/ClusterWorldTools
公式のCCK向けエディタ拡張。
シンプルかつ多彩なので、まずはこのツールの機能を覚えてソースコードを見るのがおすすめ。


CCKの構造概要

Packages/mu.cluster.cluster-creator-kit/以下の構造についてザックリまとめ。

Runtime/ 以下

ここのコンポーネントが、実際にAssetBundleに組み込まれてワールドとして送信される。
CCK用エディタ拡張で操作する相手は、ここのコンポーネントがほとんど。
ここのソースを加工すると、壊れるかエラーになるか無視される。やってはいけない。

Editor/ 以下

いわゆるエディタ用スクリプト
つまりRuntime/以下を使いやすくするためのエディタ拡張。
なので、CCK向けエディタ拡張を作りたい場合の参考になる。

UIは基本的にUI Toolkit(UIElements)で作られている。IMGUIやuGUIの方ではないので検索する時に注意。
インスペクタの拡張はEditor/Custom/以下が参考になる。
ウィンドウとか出る方の拡張はEditor/Preview/EditorUI/以下とEditor/Window/以下が参考になる。

ここのソースは加工できるが、CCKをパッケージマネージャー経由で導入していると元に戻ってしまうので、公開するのには適さない。個人用途にはいける。
ここのソースの一部はオーバーライドできるようになったので、操作をちょっとラクにするみたいなのは作りやすくなったと思う。ただ他のエディタ拡張のCustomEditorオーバーライドと衝突すると何が起きるかよく知らないので、これも公開には適さないかもしれない(当方未検証・有識者求む)。

ThirdParty/ 以下

クラフトアイテムやアクセサリーをアップロードするための規格のデータを作るためのモジュールとか置いてある。
なので、クラフトアイテムのMetallic問題とかの修正はこのあたりに入っていたりする。
glTFへの収め方が気に入らない時とかに、ここのソースを加工してアップロードすることは一応できる。おすすめはできない。


CCKのコンポーネント詳細

エディットモード中(非プレビュー時)に、よく使われそうなところを中心にダラダラとメモ。

TriggerやLogicやGimmickを自動で作る

階層の深さとリフレクションの嵐でめちゃくちゃ面倒。例を出すのが面倒になるぐらい面倒。
逆に言うと丁寧に型を見ていけばできる

ScriptableItemの「コード」に対して何かする

リフレクションでsourceCodeから取得しようとしない。
素直にGetSourceCode(true)で取得する。

ScriptableItemの「元ファイル」に対して何かする

インポーターを挟んでいるので、そっちを参照しに行く必要がある。

実装例
    [RequireComponent(typeof(ScriptableItem))]
    public class ScriptableItemFilePath
        : MonoBehaviour
    {
        private void Start()
        {
            var scriptableItem = GetComponent<ScriptableItem>();
            var javaScriptAsset = (JavaScriptAsset)scriptableItem.GetType()
                .GetField("sourceCodeAsset", BindingFlags.Instance | BindingFlags.NonPublic)
                .GetValue(scriptableItem);
            var assetPath = AssetDatabase.GetAssetPath(javaScriptAsset);
            var javaScriptImporter = AssetImporter.GetAtPath(assetPath);
            Debug.Log($"{javaScriptImporter.assetPath}");
        }
    }

CCKのプレビュー詳細

プレビュー中(非エディットモード時)に、よく使われそうなところを中心にダラダラとメモ。

CCKのプレビュー処理の全てが詰まってる所

Editor/Preview/Bootstrap.csに全てが詰まっているので、まずはこれを見る。
staticなクラスにstaticで積まれているので、いつでも参照できる。初期化完了前はnullなので注意。

プレビュー開始時の処理

プレビュー時に動かしたいエディタ拡張では、playModeStateChangedを使う。InitializeOnLoadも忘れないように。
しかし当然ながらCCKのプレビューもこれを使っているので、CCK向けエディタ拡張の場合はCCKの初期化完了を待つ必要がある。

幸いにしてBootstrapにOnInitializedEventがあるので、プレビュー開始後にこれに登録しておけばOK。

これについて細かいハマりどころ

プレビュー前(InitializeOnLoad時等)に登録しておいても、イベントは発生しない(記憶が確かなら)。
これはPlayModeとEditModeの行き来の間に、シリアライゼーションが挟まってオブジェクトの状態がリセットされるため(記憶が確かなら)。
なので結局、CCKと同様にPlayModeStateChange.EnteredPlayModeのタイミングで初期化処理をする必要がある。

しかしplayModeStateChangedの呼び出し順は定義されていないので、CCKの初期化が先かこちらのエディタ拡張が先かが分からない。
そこで以下のように工夫する。

Itemのステート情報

GimmickやLogic系の値とか、ClusterScriptのgetStateCompatとかの情報はBootstrap.RoomStateRepositoryにある。構造は単なるDictionaryだが、key/valueが独特なので注意。
くわしくはClusterWorldToolsのトリガーモニターを参照。


おわり

弊BOOTHでは様々なエディタ拡張を配布しています!!!

思い出したり思いついたら随時追記していきます。
よきエディタ拡張ライフを!!!

Discussion