LoginSignup
10
4

More than 3 years have passed since last update.

エディタ拡張でUdonBehaviourを編集しよう

Last updated at Posted at 2021-04-18

はじめに

UdonがVRChatに現れてから早いもので1年が経過しました。
近頃はUdonを書く人も大分増えて、日本界隈でも市民権を得てきているなぁ、と思う今日この頃です。
本格的にUdonを触るようになって、エディタ拡張で自動化したいシチュエーションが増えてきたのですが、VRCTriggerと違ってUdonBehaviourはserializedObjectからUdonの変数に触る事は出来ないようです。
そんなわけでエディタ拡張からUdonの変数を設定する方法を調べてみました。

Udonの構造

UdonはUdonAssemblyProgramAssetを継承したクラス(Udonコンパイラ)によってコンパイルされます。
その際、シリアライズされた変数は型と変数名を合わせたSymbolという形で保存されます。
このSymbolに値は含まれておらず、値はPublicVariablesという、変数名と紐づけされた形でUdonBehaviourに保存されます。
image.png

Symbolの取得

SymbolはUdonコンパイラによって生成されるSerializedUdonProgramAssetが持っています。UdonBehaviourからは下記の経路でSymbolにアクセスできます。

using VRC.Udon;
using VRC.Udon.Common.Interfaces;

public class SymbolTable
{
    public UdonBehaviour udonBehaviour;

    public IUdonSymbolTable GetSymbolTable()
    {
        IUdonSymbolTable symbolTable = udonBehaviour.programSource.SerializedProgramAsset.RetrieveProgram().SymbolTable;

        return symbolTable;
    }
}

SymbolTableから下記関数を使用してSymbolの情報を取得できます。

  • ImmutableArray<string> GetExportedSymbols()
    • 変数名の配列を返す。
  • bool HasExportedSymbole(string publicVariableSymbol)
    • 指定した変数名がテーブルに含まれるならTrueを返す。
  • Type GetSymbolType(string exportedSymbol)
    • 変数名からSymbolの型を返す。

PublicVariablesの編集

PublicVariablesはUdonBehaviourのメンバ変数から取得できます。
IUdonVariableTable publicVariables = udonBehaviour.publicVariables;

PublicVariablesが持つ下記関数から変数の値にアクセスできます。

  • bool TryGetVariableValue(string exportedSymbol, out object variableValue)
    • 変数名からSymbolの値をobject型で取得する。失敗したらFalseを返す。
  • bool TrySetVariableValue(string exportedSymbol, object variableValue)
    • 変数名からSymbolの値をSetする。失敗したらFalseを返す。

サンプルスクリプト

Scene内の全てのAudioSourceを取得してUdonBehaviourに設定するエディタ拡張です。

using UnityEngine;
using UnityEditor;
using VRC.Udon;
using VRC.Udon.Common.Interfaces;

public class UdonAudioSetup : MonoBehaviour
{
    public UdonBehaviour udonBehaviour;
    public string symbolName;
}

[CustomEditor(typeof(UdonAudioSetup))]
public class UdonAudioSetupEditor : Editor
{
    UdonAudioSetup udonAudioSetup;

    private void OnEnable()
    {
        udonAudioSetup = (UdonAudioSetup)target;
    }

    public override void OnInspectorGUI()
    {
        base.OnInspectorGUI();

        EditorGUILayout.Space();
        EditorGUILayout.Space();

        // Symbolを取得出来なければボタンを無効化
        using (new EditorGUI.DisabledScope(!IsSetupReady(udonAudioSetup)))
        {
            if (GUILayout.Button("Setup"))
            {
                SetupUdonBehaviour(udonAudioSetup.udonBehaviour, udonAudioSetup.symbolName);
            }
        }
    }

    private void SetupUdonBehaviour(UdonBehaviour udonBehaviour, string exportedSymbol)
    {
        // PublicVariables取得
        IUdonVariableTable publicVariables = udonBehaviour.publicVariables;

        var audioSources = GameObject.FindObjectsOfType<AudioSource>();

        // Undo用意
        Undo.RecordObject(udonBehaviour, "Modify Public Variable");
        // 値をPublicVariablesに設定
        if (!publicVariables.TrySetVariableValue(exportedSymbol, audioSources))
        {
            Debug.Log("Error! Failed Setting Public Variables.");
            return;
        }

        Debug.Log("Setup Completed.");
    }

    private bool IsSetupReady(UdonAudioSetup udonAudioSetup)
    {
        // Symbolテーブル取得
        IUdonSymbolTable symbolTable = udonAudioSetup.udonBehaviour?.programSource?.SerializedProgramAsset?.RetrieveProgram()?.SymbolTable;
        if (symbolTable == null)
            return false;

        // Symbolが存在しなければFalse
        if (!symbolTable.HasExportedSymbol(udonAudioSetup.symbolName))
            return false;

        // Symbolの型がAudioSource[]でなければFalse
        if (symbolTable.GetSymbolType(udonAudioSetup.symbolName) != typeof(AudioSource[]))
            return false;

        return true;
    }
}

使用バージョン

  • VRCSDK3-WORLD-2021.03.22.18.27_Public
  • UdonSharp_v0.19.8
10
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
4