Skip to content

モデル配置プロバイダ連携 ​

SceneEditor プラグイン(COM3D2.SceneEditor.Plugin)のタイムラインが扱うモデルを、 他プラグインの配置機能で賄うための資料。

対象: ModelPlacerProviderRegistry 搭載以降の SceneEditor。

概要 ​

タイムラインのモデル系レイヤー(モデル / モデルボーン / モデルシェイプキー / モデルマテリアル)は、モデルの配置そのものを持たない。 配置のライフサイクル(生成・削除・表示切替・アタッチ)は モデル配置プロバイダ が担い、 タイムラインはプロバイダが列挙する GameObject をキーフレームの対象として扱うだけになる。

  • 発見は属性ベースの自動発見。SceneEditor へのアセンブリ参照は不要
  • 境界を越える型は UnityEngine.GameObject / Maid / プリミティブのみ
  • プロバイダが 1 つも見つからない環境では、モデル系レイヤーは登録されず起動時に警告が 1 回出る
  • 複数見つかった場合は先勝ちで 1 つだけ使う
  • 発見は SceneEditor の初期化時に行い、見つからなければシーン切り替えごとに再走査する。 そのためプラグインのロード順を気にする必要はない

実装手順 ​

1. 属性を自前定義する ​

SceneEditor のアセンブリを参照させないため、レジストリは属性を型の完全一致ではなく 短名 ModelPlacerProviderAttribute の一致で判定する。各プラグインが自分の 名前空間に同名の属性を定義すればよい。

csharp
[AttributeUsage(AttributeTargets.Class)]
public class ModelPlacerProviderAttribute : Attribute
{
}

2. 契約メンバを持つ public static クラスに属性を付ける ​

csharp
[ModelPlacerProvider]
public static class ModelPlacerProvider
{
    public static string ModelPlacerId => "ModItemExplorer";
    public static string ModelPlacerDisplayName => "モデル配置 (ModItemExplorer)";

    /// <summary>配置中モデルの列挙。タイムラインはこの一覧をキーフレーム対象にする</summary>
    public static List<GameObject> GetModels() { ... }

    /// <summary>モデルの元ファイル名。タイムラインの名前解決に使う</summary>
    public static string GetModelFileName(GameObject obj) { ... }

    /// <summary>モデルを配置する。失敗時は null を返す</summary>
    public static GameObject CreateModel(
        string type, string fileName, int myRoomId, long bgObjectId, int group, bool visible) { ... }

    /// <summary>モデル1体を削除する</summary>
    public static void DeleteModel(GameObject obj) { ... }

    /// <summary>配置中モデルを全削除する</summary>
    public static void DeleteAllModels() { ... }

    /// <summary>表示・非表示を切り替える</summary>
    public static void SetModelVisible(GameObject obj, bool visible) { ... }

    /// <summary>メイドのボーンへ追従させる。maid が null か boneName が空なら解除</summary>
    public static void AttachModel(GameObject obj, Maid maid, string boneName) { ... }
}

(実物: ModItemExplorer の source/COM3D2.ModItemExplorer.Plugin/ModelPlacement/ModelPlacerProvider.cs)

契約仕様 ​

いずれも public static。シグネチャは戻り値の型まで一致すること (一致しないメンバは「無い」ものとして扱われる)。

必須メンバ ​

メンバシグネチャ役割
ModelPlacerIdstring(プロパティ)プロバイダ ID。タイムライン XML の pluginName として保存される。空なら登録されない
ModelPlacerDisplayNamestring(プロパティ)表示名。空なら ID を代用する
GetModelsList<GameObject> GetModels()配置中モデルの列挙。タイムラインはこの一覧をキーフレーム対象にする
GetModelFileNamestring GetModelFileName(GameObject)モデルの元ファイル名。タイムラインの名前解決に使う
CreateModelGameObject CreateModel(string type, string fileName, int myRoomId, long bgObjectId, int group, bool visible)モデルを配置し、生成した GameObject を返す。失敗時は null
DeleteModelvoid DeleteModel(GameObject)モデル 1 体を削除する
DeleteAllModelsvoid DeleteAllModels()配置中モデルを全削除する
SetModelVisiblevoid SetModelVisible(GameObject, bool)表示・非表示を切り替える
AttachModelvoid AttachModel(GameObject, Maid, string boneName)メイドのボーンへ追従させる / 解除する

必須メンバが 1 つでも欠けていると、そのプロバイダは登録されず、 欠落したメンバ名がログに出る。

任意メンバ ​

メンバシグネチャ役割
GetModelDisplayNamestring GetModelDisplayName(GameObject)一覧に出す表示名
BeginBatch / EndBatchvoid BeginBatch() / void EndBatch()タイムライン読込のような一括操作の開始・終了通知。2 つ揃っているときだけバインドされる
GetModelAttachBoneTransform GetModelAttachBone(GameObject)アタッチ中の親ボーン(未アタッチなら null)。実装すると、ゲスト側の UI で付け替えたアタッチが SceneEditor のモデルキーへ取り込まれる。UI での付け替えの前に AutoEditModeClient.Enter("ModelTimelineLayer") を呼ぶこと(呼ばないとタイムラインの再生値で元に戻る)
AttachModelToModelvoid AttachModelToModel(GameObject obj, GameObject parent, string boneName)obj を別のモデル parent(同じプロバイダの配置モデル)へ追従させる。boneName は parent 内のボーン名で、空ならモデルの原点(今の SceneEditor は常に空を渡す)。実装すると、SceneEditor のモデルキーでモデルをアタッチ先に選べる。GetModelAttachBone が parent の Transform を返せば、ゲスト側の UI で付け替えたモデルへのアタッチもキーへ取り込まれる
GetModelLayerint GetModelLayer(GameObject)モデルの表示レイヤー(Unity のレイヤー番号)。管理外・不明なら -1。SetModelLayer と対で実装すると、SceneEditor がタイムラインのモデル定義(<ModelLayer>)として保存・復元する
SetModelLayervoid SetModelLayer(GameObject, int)表示レイヤーを変える。タイムライン読込・モデル複製から呼ばれる。0〜31 以外は無視すること。GetModelLayer と片方だけでは無効

各メンバの詳細 ​

CreateModel の type ​

SceneEditor 側 StudioModelType の enum 名がそのまま文字列で渡る。

type内容主に使う引数
ModMOD アイテム(.menu)fileName
Prefab公式 BG プレハブ(アセットバンドル / Resources)fileName
Asset背景オブジェクト(.asset_bg)fileName
MyRoomマイルームカスタムの配置オブジェクトmyRoomId

未知の種別が来たときは黙って落とさず、警告を出して null を返すこと。

CreateModel の bgObjectId ​

公式の背景オブジェクト一覧(PhotoBGObjectData)における ID。 SceneEditor が自分のカタログを引くための識別子で、該当が無いモデルでは 0 が渡る。

fileName と myRoomId だけで生成先を決められるなら無視してよい (ModItemExplorer の実装も使っていない)。

group はヒントでしかない ​

CreateModel に渡る group は「呼び出し側の希望値」であり、 ゲスト側は別の値で採番してよい。タイムラインが実際に使う group は ModelHackManager が列挙順で振り直すため、SceneEditor はゲストの採番を読み戻さない。

AttachModel の boneName ​

SceneEditor 側が AttachPoint からボーンの Transform まで解決し、その名前だけを渡す。 ゲスト側に AttachPoint enum の対応表を持たせずに済ませるための取り決め。

  • maid が null、または boneName が空文字なら解除(ワールド配置へ戻す)
  • 渡るボーン名はゲスト側が用意した定番一覧に無いものも含まれるため、 一覧に無い名前でもアタッチできるようにしておくこと

SceneEditor が付ける部位は、ゲームの PhotoTransTargetObject.AttachPoint の部位に胸(Bip01 Spine1a)と骨盤(Bip01 Pelvis)を足したものです。GetModelAttachBone が返すボーンがこの一覧に無い場合、SceneEditor はそのアタッチをキーへ取り込みません。

AttachModelToModel ​

別の配置モデルへのアタッチ。SceneEditor はアタッチ先モデルの GameObject まで解決して parent に渡す。

  • 付けるときはメイドへのアタッチと同じく、ローカル位置・回転を 0 にする(拡縮は保つ)
  • 解除は既存の AttachModel(obj, null, "") で行う
  • parent を削除するときは、付いている子をワールド位置を保ったまま配置ルートへ戻してから破棄する(戻さないと子も一緒に破棄される)
  • 自分自身や子孫を親にする指定は SceneEditor 側で弾くが、ゲスト側でも無視すること

BeginBatch / EndBatch ​

タイムライン読込時の一括生成・削除を挟む形で呼ばれる。 ゲスト側が操作履歴(undo/redo)を持つ場合、この間は履歴への登録を止めておくと、 読込のたびに履歴が積み上がるのを避けられる。

EndBatch は例外時も必ず呼ばれる(finally から呼び出される)。

既知の相互作用 ​

  • ゲスト側がギズモを持つ場合、タイムライン再生中は毎フレーム Transform が 上書きされるため、ギズモ操作は再生停止時のみ有効になる
  • 旧バージョンの SceneEditor が自前配置していた時代のタイムライン XML は pluginName に "SceneEditor" を持つ。読込時に現行のプロバイダ ID へ自動で読み替えられる