Appearance
AI向け ShirasUdonAssembly JSON v1 作成ガイド
この文書は、生成AIがShirasUdonのテスト用Assembly JSONを安全に作成するための 実践ガイドである。厳密な定義は ShirasUdonAssembly JSON v1仕様書を正とする。
1. AIへ渡す資料
最低限、AIへ次の2ファイルを渡す。
既存のサンプルコードはサンプルコードページから選び、必要に応じてAIへ渡す。
使用可能なExtern Signatureは、cannorin様提供のUdon Extern Search 2で検索してもらうなどで対応。
AIはExtern Signatureを推測してはならない。必ず一覧に完全一致する文字列を使用する。
2. 出力形式
出力はUTF-8の厳密なJSONとする。コメント構文、末尾カンマ、NaN、Infinityは使用しない。
json
{
"version": 1,
"comment": "サンプルの説明",
"data": [],
"code": []
}| プロパティ | 必須 | 内容 |
|---|---|---|
version | ○ | 常に1 |
comment | × | サンプル選択UIに表示する説明 |
data | ○ | 論理Heap Symbolの宣言と初期値 |
code | ○ | exportまたは内部ラベルとなるコードブロック |
3. data
すべての値は、先に一意なHeap Symbolとして宣言する。
json
{
"name": "__value",
"type": "SystemInt32",
"value": 10
}nameとtypeは文字列、valueは必須である。同じnameを重複させない。
代表的な型名:
text
SystemBoolean
SystemInt32
SystemSingle
SystemDouble
SystemString
UnityEngineVector3
UnityEngineGameObject
VRCSDKBaseVRCPlayerApi型名もExtern一覧のType_...またはVariable_...に対応するUdon型名を使う。
JSON値
text
Boolean型 -> true / false
数値型 -> JSON Number
String型 -> JSON String
参照型の初期値 -> null
値型の箱 -> null(default(T)としてロードされる)
enum -> enum名ではなく基底数値enumの例:
json
{
"name": "__ease",
"type": "VRCSDK3ComponentsVRCTweenEase",
"value": 1
}"Linear"のような名前は使用しない。数値とenumの対応はSDKの定義を確認する。
4. codeとexport
json
{
"name": "AddSpeed",
"export": true,
"instructions": []
}export: trueのブロックはUIから実行できるエントリーポイントになる。export: falseのブロックはJUMP先などの内部ラベルになる。- コードブロック名を重複させない。
_startは特別に必須ではない。目的に合うexport名を使ってよい。- 命令列の末尾へ到達すると正常終了する。
VMはRun()ごとにStackと命令位置を初期化するが、論理Heapは維持する。Heapを初期値へ 戻すのはLoad()時である。同じexportを再実行すると前回の結果から続行する。
5. Stackの基本
Stackへ積むのは値ではなくHeap Symbol名である。
json
{
"op": "PUSH",
"operand": "__value"
}AIは各コードブロックについて、命令ごとのStack深度を追跡する。
text
PUSH +1
POP -1
COPY -2
EXTERN -argumentCount
戻り値ありEXTERN さらに+1
JUMP_IF_FALSE -1
JUMP / JUMP_INDIRECT 仕様書に従うStack深度は途中で負になってはならず、通常はコードブロック終了時に0にする。
6. COPY
COPYは上から2つのSymbolを取り出し、1つ目から2つ目へコピーする。
json
{
"op": "PUSH",
"operand": "__source"
},
{
"op": "PUSH",
"operand": "__destination"
},
{
"op": "COPY"
}text
__destination = __sourceenumと数値型の間のCOPYでは、VMが必要なenum変換を行う。
7. EXTERN
json
{
"op": "EXTERN",
"signature": "SystemInt32.__op_Addition__SystemInt32_SystemInt32__SystemInt32",
"argumentCount": 2,
"return": "__result"
}引数
引数はC#の呼び出し順にPUSHする。インスタンスメソッドではreceiverが第0引数になる。
csharp
player.SetWalkSpeed(speed);json
{ "op": "PUSH", "operand": "__player" },
{ "op": "PUSH", "operand": "__speed" },
{
"op": "EXTERN",
"signature": "VRCSDKBaseVRCPlayerApi.__SetWalkSpeed__SystemSingle__SystemVoid",
"argumentCount": 2
}argumentCountにはreceiverを含むが、戻り値格納先は含めない。
戻り値
- 戻り値あり:
returnへ既存のHeap Symbol名を必ず指定する。 - 戻り値なし:
returnを指定してはならない。 - 戻り値ありEXTERNは、実行後に
returnのSymbolをStackへ積む。 - 戻り値を後続命令で使わない場合、直後に
POPする。
json
{
"op": "EXTERN",
"signature": "VRCSDKBaseNetworking.__get_LocalPlayer__VRCSDKBaseVRCPlayerApi",
"argumentCount": 0,
"return": "__player"
},
{
"op": "POP"
}通常、末尾が__SystemVoidなら戻り値なしである。ただし、Udonの一部の プロパティsetterは__SystemVoidを省略する。.__set_を含むSignatureも必ず戻り値なしと して扱う。
text
UnityEngineVector3.__set_x__SystemSingleこのSignatureにreturnを付けてはならない。
refArguments
ref、out、または値型receiverの変更をHeapへ書き戻す引数Indexを指定する。 Indexは0始まりで、argumentCount未満でなければならない。省略時は空配列である。
json
{
"op": "EXTERN",
"signature": "UnityEngineVector3.__set_x__SystemSingle",
"argumentCount": 2,
"refArguments": [0]
}Vector3などの値型receiverを変更するsetterでは、通常receiverの0を指定する。 参照型オブジェクトのプロパティsetterには通常不要である。
8. 分岐
無条件ジャンプ:
json
{
"op": "JUMP",
"operand": "_loop"
}条件付きジャンプ:
json
{ "op": "PUSH", "operand": "__condition" },
{
"op": "JUMP_IF_FALSE",
"operand": "_end"
}JUMP_IF_FALSEはBoolean Symbolを1つ消費し、falseなら指定ブロックへ移動する。 ジャンプ先はcodeに存在する一意なブロック名でなければならない。
9. 最小例
次の例はRunを押すたびに整数を1増やしてログへ出す。
json
{
"version": 1,
"comment": "整数を1増やしてログへ出力します。",
"data": [
{ "name": "__value", "type": "SystemInt32", "value": 0 },
{ "name": "__one", "type": "SystemInt32", "value": 1 },
{ "name": "__next", "type": "SystemInt32", "value": 0 }
],
"code": [
{
"name": "Run",
"export": true,
"instructions": [
{ "op": "PUSH", "operand": "__value" },
{ "op": "PUSH", "operand": "__one" },
{
"op": "EXTERN",
"signature": "SystemInt32.__op_Addition__SystemInt32_SystemInt32__SystemInt32",
"argumentCount": 2,
"return": "__next"
},
{ "op": "POP" },
{ "op": "PUSH", "operand": "__next" },
{ "op": "PUSH", "operand": "__value" },
{ "op": "COPY" },
{ "op": "PUSH", "operand": "__value" },
{
"op": "EXTERN",
"signature": "UnityEngineDebug.__Log__SystemObject__SystemVoid",
"argumentCount": 1
}
]
}
]
}10. 生成手順
AIは次の順序で作業する。
- ユーザーの目的をexport単位へ分割する。
- 必要なAPIをExtern一覧から検索する。
- 各Signatureのreceiver、引数、戻り値、ref/outを確定する。
- 必要な定数、一時値、戻り値格納先をすべて
dataへ宣言する。 - C#相当の処理をPUSHとEXTERNへ展開する。
- 戻り値を使わない箇所へPOPを入れる。
- 値型receiverの変更に
refArgumentsを入れる。 - 全命令のStack深度を計算する。
- 全Symbol、ラベル、Signatureを照合する。
- JSON parserで構文検証する。
11. 検証チェックリスト
JSON
versionは整数の1か。- JSONとしてparseできるか。
dataとcodeは配列か。data.nameとcode.nameはそれぞれ一意か。
Symbolと型
- すべてのPUSH operandが
dataに存在するか。 - すべてのEXTERN returnが
dataに存在するか。 - 戻り値格納先の型がSignatureの戻り値型と一致するか。
- enum初期値を数値で記述したか。
- API戻り値用の参照型・値型Symbolを
nullで初期化したか。
EXTERN
- Signatureが一覧に完全一致するか。
argumentCountが実際にPUSHした引数数と一致するか。- インスタンスメソッドのreceiverを数えたか。
- 戻り値ありEXTERNに
returnがあるか。 - Voidおよびsetterに
returnを付けていないか。 - 不要な戻り値をPOPしたか。
- ref/outおよび値型receiverへ正しい
refArgumentsを指定したか。
制御フロー
- Stack深度が途中で負にならないか。
- 各終了経路のStackが原則0か。
- すべてのジャンプ先が存在するか。
- 無限ループになっていないか。
- 再実行時にHeapが維持されても意図どおりか。
- 加算系テストには必要に応じてReset exportがあるか。
12. よくある失敗
text
SignatureをC#名から推測する
return Symbolをdataへ宣言し忘れる
戻り値をPOPせずStackへ残す
Void EXTERNへreturnを書く
setterを戻り値ありと誤判定する
instance receiverをargumentCountへ含めない
COPYのsourceとdestinationを逆にする
Vector3 setterへrefArguments:[0]を付けない
enumを文字列名で初期化する
Runのたびにdataが初期化されると仮定するUdonはException発生後、そのExecutorを停止する。無効な型、null引数、誤ったSignature、 誤ったpush数を「実行して確認する」前提にせず、生成時に検証する。
13. AIへ渡すプロンプト雛形
text
ShirasUdonAssembly JSON v1のテストサンプルを作成してください。
目的:
<実現したい処理>
制約:
- 添付したAI向け作成ガイドと正式仕様書に従う
- Extern SignatureはUdon Extern Search 2で確認できる文字列だけを使う
- Signatureを推測しない
- versionは1
- 必要な値と一時値をすべてdataへ宣言する
- enum初期値は数値で書く
- argumentCountにはinstance receiverを含め、return slotは含めない
- 戻り値ありEXTERNにはreturnを指定する
- 戻り値を使用しない場合は直後にPOPする
- Voidおよび.__set_ Signatureにはreturnを書かない
- ref/outと値型receiverの変更にはrefArgumentsを指定する
- 全コードブロックのStack深度を検証する
- 再実行時にHeapが維持されることを考慮する
- 説明用commentを付ける
- 最終回答はMarkdown fenceを付けず、JSONだけを出力する
出力前に内部で次を検証してください:
- JSON構文
- Symbol参照
- コードブロック名とジャンプ先
- Extern Signatureの存在
- argumentCount
- returnの有無
- refArguments
- 各終了経路のStack収支14. 実行確認
- DemoのInputFieldへJSONを貼る。
Loadを押す。- export数と名前を確認する。
- 各ボタンを1回実行する。
- ConsoleとVRCクライアントログを確認する。
- 状態保持を確認する場合は再実行する。
- 初期値を再確認する場合は、もう一度
Loadしてから実行する。
Editor上の成功だけで完了とせず、可能ならVRCクライアントでも確認する。Udonのbox化、 シリアライズ、ClientSimとの差が現れる場合があるためである。