🐼

UdonAssemblyでobjectに初期値を持たせる

2024/01/13に公開

はじめに

UdonAssemblyのdataセクションに配列とかDataListとかのobjectを書く際に、初期値を指定する方法です。
UdonSharpならフィールド初期化時にnew int[]{1,2,3}みたいに書けばいいやつです。
objectでないプリミティブな型ならこちらを参考にしてください。

本記事の対象者

  • UdonAssemblyでobjectのデータに初期値を指定させたい人
  • UdonAssemblyのデータの持ち方が気になってモヤっとしている人

背景

VRCのワールド制作で、設定1つで予め用意するオブジェクトの数を切り替えるようにしたくなりました。(数百~数千くらいの間)
付随してUdonSharpコード内の配列フィールドも変更が必要になり、方法を検討。

⭐以下検討内容と結論

  1. Start()内でnewしてループ回して初期化 👈 Udon遅いので嫌
  2. SerializeFieldにしてエディタスクリプトから指定 👈 シーンが肥大化するからなんか嫌
  3. prefabなら肥大化箇所をその中に抑えられるよ 👈 インスペクタに数千のデータが並ぶのも嫌
  4. エディタスクリプトからUdonSharpソースコードのフィールド初期化箇所を編集 👈 なんか嫌
  5. UdonAssemblyにデータ持たせてエディタスクリプトから更新。実行時にGetProgramVariable()で取得 👈 これ

元々UdonAssemblyのデータがnullしか書いてなくどこにデータ持たせているのか気になっていたのでお勉強もかねて。

結論

UdonAssembly自体にはobjectの初期値の記述はできない。(できたら教えてください)
UdonAssemblyのAssetが持つSerializedUdonProgramAssetが初期値を持っていてこれを更新する。
(UdonGraphUdonSharpはコンパイル時にSerializedUdonProgramAssetに初期値書いてくれている)

以下エディタスクリプトの更新用コード

//SerializedUdonProgramAsset取得。Asset取れれば方法はなんでもいい
var behaviour = GameObject.Find("対象UdonをくっつけたGameObjectのパス")
    .GetComponent<UdonBehaviour>();
var udonAsset = behaviour.programSource;
var serializedAsset = udonAsset.SerializedProgramAsset;

//AssetからIUdonProgramを取得
var program = serializedAsset.RetrieveProgram();

//IUdonProgram編集(該当変数のアドレス取って、Heapに指定して格納)
var address = program.SymbolTable.GetAddressFromSymbol("_Test3");
program.Heap.SetHeapVariable<int[]>(address, new int[] { 1, 2, 3, 4, 5 });

address = program.SymbolTable.GetAddressFromSymbol("_Test");
program.Heap.SetHeapVariable<DataList[]>(address, 
    new DataList[] { new DataList(), new DataList(), new DataList() });

//編集結果をAssetに保存
serializedAsset.StoreProgram(program);

調査時のメモ

あくまでメモ

Discussion