TUKI0136 | 同期の方式が None の Behaviour のネットワークイベント | [UdonBehaviourSyncMode(BehaviourSyncMode.None)] の Behaviour はネットワークイベントを受けない。その Behaviour へ送る SendCustomNetworkEvent は送る時点で受け付けられず、[NetworkCallable] のメソッドはネットワーク越しに呼ばれない。ネットワークイベントを使うなら、方式を NoVariableSync にする(同期)。コンパイルは通る(停止しない) |
TUKI0104 | 変数の格納先が足りない | 1 つのプログラムが使える変数の数には上限がある |
TUKI0105 | 型引数の展開が多すぎる | ジェネリックへ渡した組み合わせが多すぎて、展開しきれない |
TUKI0107 | 同期の方式と変数の矛盾 | [UdonBehaviourSyncMode] の指定と [UdonSynced] の付け方が噛み合っていない |
TUKI0117 | テストがワールドに含まれるファイルにある | [TsukimiTest] を本体側のファイルに書いている。Assert か Mimic を呼ぶテストは、その呼び出しがワールドに含まれるプログラムに残るので、Unity がビルドを止め、inspect もエラー(compiles: false)にする。どちらも呼ばないテストは、ワールドに含まれるプログラムに入り、エントリポイントとして公開される(こちらは警告で、コンパイルは通る)。テストは 名前.Tests.cs のファイルへ移す |
TUKI0202 | 常に同じ結果になる null 比較 | 値型と null を比べている。コンパイルは通る(停止しない) |
TUKI0203 | object から値型を取り出している | 取り出しに変換が 1 本かかる。コンパイルは通る(停止しない) |
TUKI0204 | 2 次元配列の費用 | 要素を 1 個ずつボックス化して出し入れする形になる。コンパイルは通る(停止しない) |
TUKI0116 | 予約された名前 | __ で始まる名前と、書いたイベントの引数を受け取るヒープ変数の名前(OnPlayerJoined なら onPlayerJoinedPlayer)はコンパイラが自分のヒープ変数に使う。フィールドの名前を変えれば直る |
TUKI0120 | 焼き込めないモデル | モデルの属性で名指したモデルを焼き込めない。どの場合かはメッセージが言う: 属性が決まりどおりに書かれていない(C# を直す)・モデルのファイルが読めない・モデルの中に変換できない物がある(メッセージが名指すモデルの部分を変える。C# の誤りではない)(ONNX モデル(試験中)) |
TUKI0121 | シェーダに書けない名前 | GPU で動く部分(カーネルと、そこから呼ぶメソッド、その引数とローカル変数)の名前に、半角の英数字と下線以外が入っている。名前を付け直せば直る(Udon 側に残るメソッドやフィールドの名前は自由)。そのカーネルを使う Gpu.Run などの行に続けて出るエラーも、同じ番号になる。そちらは直さなくてよく、名前を直せば消える |
TUKI0122 | イベントにならないイベント名のメソッド | 組み込みイベントの名前のメソッドが、イベントの宣言どおりに書かれていない(引数の型・数か戻り値が違う、引数のあるイベントを引数無しで書いた、VRChat のイベントを override 無しで書いた)。普通のメソッドとしてコンパイルされ、イベントとしては呼ばれない。警告の文が書くべき形を名指す(イベント)。イベントのつもりでなければ、名前を変えれば警告は消える。引数の無い Awake にも出る。Awake は VRChat が呼ばないので、本文は Start へ移す(ソースのどこかで Awake の名前を使っていれば出ない)。コンパイルは通る(停止しない) |
TUKI0123 | 16 ビットで持った低いビットの重み | 学習済みモデルの 8 ビットか 4 ビットの重みを、読む層がその大きさで使えないので、16 ビットの値で持った。層ごとに 1 件出て、層の名前・使えない理由・重みが何倍のメモリになるかを示す。計算する値は変わらない。メモリを減らすなら、理由に従ってその層の重みの量子化の仕方か層の形を変える(GPU で計算する ONNX モデル(試験中))。コンパイルは通る(停止しない) |
TUKI0135 | 16 ビットの上限を超えうる層 | 層の間の値を 16 ビットの小数で持つモデル(実数のモデルなど)に、16 ビットの最大値 65504 を超える値を出しうる層がある。超えた値は 65504(負なら -65504)として持たれ、元のモデルと値が違う。超えるかはモデルに渡す値で決まるので、メッセージが層の名前と理由と、入力がどこまで大きくなると超えるかを示す(同じ理由の層は 1 件にまとめる)。名指された層に届く値が示された大きさより小さいままなら、直す物は無い。確認するには、同じ入力で Unity の出力と元のモデルの出力を比べる。超えないようにするには、モデルの中でその層の入力を Clip で縛るか、演算が許すなら定数で割ってから層を通し、後で掛け戻す(GPU で計算する ONNX モデル(試験中))。コンパイルは通る(停止しない) |
TUKI0124 | 命令数とヒープ使用量を測れなかった | 命令数とヒープ使用量は、Unity がコンパイルするプログラムで測る。Unity は 名前.Tests.cs のファイルを外してコンパイルするので、渡したファイルがそのテストのファイルだと、測るプログラムが残らない。外したプログラムが、Unity がプログラムを保存する前に行う検査でエラーになる場合にも出る。どちらの場合かはメッセージが言う。inspect の cost を指定したときだけ出る。Behaviour を宣言したファイル(名前が .Tests.cs で終わらないもの)を渡す(テスト)。コンパイルは通る(停止しない) |
TUKI0125 | ファイルスコープの名前空間 | namespace X; は C# 10 の構文で、Unity も C# 9 でコンパイルするため、同じファイルは Unity でもエラーになる。namespace X { に変えてファイルの最後に } を足す(中のコードの字下げは変えなくてよい)(ファイル構成と名前空間) |
TUKI0126 | Unity の外では決まらないシンボル | #if か #elif が、Unity の外では定義が決まらないシンボルを読んでいる(UNITY_ANDROID のようにビルドターゲットで決まるものと、ファイルで #define していないもの)。そのシンボルは未定義としてコンパイルした。Unity ではビルドターゲットとプロジェクトの Scripting Define Symbols で決まるので、別の分岐がコンパイルされることがある(COMPILER_UDONSHARP と UDONSHARP は常に定義され、UNITY_EDITOR は常に定義されない)。コンパイルされた分岐が意図どおりなら、直す物は無い。もう一方の分岐を確認するには、確認する間だけファイルの先頭に #define を書く(プリプロセッサ)。コンパイルは通る(停止しない) |
TUKI0127 | インスタンスのあいだで共有されない static フィールド | Behaviour の static で readonly でないフィールド(と、set を持つ static の自動プロパティ)は、値を Behaviour のインスタンスごとに別に持つ。C# の static のようには共有されない。const と static readonly には出ない。インスタンスごとの値でよければ、static を外せば警告は消える。1 つの値を共有するなら、1 つの Behaviour の普通のフィールドに置き、ほかの Behaviour は、Inspector で設定したその Behaviour への参照を通して読み書きする(static クラスに移しても共有はできず、static クラスの readonly でない static フィールドを読むとエラーになる)(メンバの宣言)。コンパイルは通る(停止しない) |
TUKI0128 | C# 10 以降の構文 | コレクション式・プライマリコンストラクタ・record struct・global using は C# 10 以降の構文で、Unity も C# 9 でコンパイルするため、同じファイルは Unity でもエラーになる。メッセージが構文の名前と、C# 9 で代わりに書く形を言う([1, 2, 3] なら new int[] { 1, 2, 3 })。プライマリコンストラクタと record struct では、直すまでファイルのほかのエラーは出ないので、直した後にもう一度コンパイルする |
TUKI0129 | 戻り値を捨てた跨ぐメソッドの呼び出し | async FrameTask のメソッドの呼び出しを文として書き、戻り値の FrameTask を捨てている。同時に実行できる本数(既定は 1 本)が全部埋まっているときの呼び出しは始まらず、それを知る方法は戻り値の Started だけになる。async FrameTask のメソッドの中なら await で待つ(本数が 2 以上のメソッドと、ほかの Behaviour のメソッドは待てない)。どこでも if (!M().Started) { ... } のように Started を読める。始まらなくてよい呼び出しなら、_ = M(); と書けば警告は出ない(async / await)。コンパイルは通る(停止しない) |
TUKI0130 | 同期する値の大きさ | 同期する変数がある Behaviour に、inspect が 1 件出す情報。同期する変数の数(構造体の変数は、そのフィールドごとに 1 つと数える)と、大きさが値によらない変数の型の大きさの和(int と float は 4、Vector3 は 12)を示す。string・VRCUrl・配列は和に入れず、名前を別に挙げる。和は VRChat がネットワークに送るバイト数ではなく、上限とも比べていない。直す物は無い(同期)。コンパイルは通る(停止しない) |
TUKI0131 | 同期するフィールドの、値が決まらない初期化子 | [UdonSynced] のフィールドか、[FieldChangeCallback] の対象のフィールドに、コンパイル時に値が決まらない初期化子(Random.Range(1f, 2f) など)が付いている。値が決まる初期化子はフィールドの初期値になり、実行時には実行されない。決まらない初期化子は、その Behaviour のイベントか public メソッドが最初に呼ばれたときに 1 回実行されるので、それより先に受信した値や外から設定された値を上書きする。定数や、new Vector3(0f, 2f, 0f)・Vector3.up * 2f のように値が決まる形で書くか、初期化子を外す。外した後で値が必要なら、OnDeserialization と Start のどちらが先に実行されてもよいように書く(同期) |
TUKI0132 | Unity から呼ばれないエディター用のメソッド | Behaviour に OnValidate・OnDrawGizmos・OnDrawGizmosSelected を書いている。Unity はこれらをエディターで MonoBehaviour に対して呼ぶが、ここで書いた Behaviour は UdonBehaviour が実行する Udon のプログラムになるので、Unity からは呼ばれず、中のコードは実行されない。メソッドは普通のメソッドとしてコンパイルされる。エディターでだけ必要な処理はエディターのスクリプトへ、ワールドで実行する処理は Start などのイベントへ移す。Unity から呼ばれるためのメソッドでなければ、名前を変えれば警告は出ない。コンパイルは通る(停止しない) |
TUKI0111 | 変化の伝播を組み立てられない | リアクティブの属性は読めたが、変化を伝える処理を 1 つも置けなかった。そのクラスの効果は自動では実行されない。比べ方の無い型(配列・DataList・DataDictionary など)の [Reactive] と、その型の成分を持つ struct の [Reactive] で出て、メッセージがそのフィールドか成分を名指す(リアクティブプログラミング) |
TUKI0113 | どこからも実行されない効果 | その効果のトリガーが、どのエントリポイントでも変わらない。コンパイルは通る(停止しない) |
TUKI0115 | 同期するフィールドに付いた属性 | 届いた値では効果が実行されない(伝播が入るのは値を書いたエントリポイントだけ)。そのフィールドに [FieldChangeCallback] を付け、setter でフィールドへ代入すると、届いた値は setter を通って効果が実行され、この警告も出ない。コンパイルは通る(停止しない) |
TUKI0119 | 読んだ値が変わっても実行し直されない効果 | [Effect](か [Computed] を読む効果)が、読んだ値が変わっても実行し直されない。メッセージが場合を言う: 依存を書くエントリポイントが 1 つも見つからず、起動時に 1 回だけ実行される・ほかのインスタンスかほかのクラスの [Reactive] か [Computed] の値を読んでいる・名前を書いた [Effect] が、書いていない値を読んでいる(リアクティブプログラミング)。コンパイルは通る(停止しない) |
TUKI0134 | 効果が実行されない道でのリアクティブなフィールドへの書き込み | [Reactive] のフィールドへ、ほかのクラスから代入している・同じクラスの別のインスタンスへ代入している・SetProgramVariable に名前を書いて書き込んでいる(そのクラスの中で自分へ書く場合も)。効果が実行されるのは、そのフィールドを宣言したクラスのメソッドが自分のフィールドへ代入したときだけなので、値だけが変わり、効果は実行されない。そのクラスに代入するメソッドを書き、外からはそれを呼ぶ。[FieldChangeCallback] も付けたフィールドへの名前での書き込みは、setter を通って効果が実行されるので、この番号にならない(リアクティブプログラミング) |
TUKI0235 | null で始まる同期する配列 | [UdonSynced] の配列が null で始まる。初期化子が無く Inspector に出ない配列(private か [NonSerialized] のもの)と、初期化子が null か default の配列に出る。VRChat の公式ドキュメントは、同期する配列が 1 つでも null の間はその Behaviour を同期しないと書いているので、その配列だけでなく、ほかの同期する変数もほかのプレイヤーに届かない。= new int[0] のような初期化子を書くか、最初に送る前(Start など)に配列を代入する。後から null を代入すると、配列を代入し直すまで同期されない(同期)。コンパイルは通る(停止しない) |
TUKI0255 | 型の違う値の名前での書き込み | SetProgramVariable に名前を書いて、フィールドの型と違う型の値を書き込んでいる(float のフィールドへの SetProgramVariable("speed", 2) など)。名前での書き込みは値をフィールドの型へ変換せずに代入するので、float のフィールドに int が入り、そのフィールドを float として使う所で Behaviour が停止する(C# では変換されて入る)。2f のように型の合う値を渡すか、自分のフィールドなら直接代入する。名前がコンパイル時に決まり(文字列のリテラル・const・nameof)、相手が自分か、型が自分で宣言した Behaviour のクラスの変数のときに出る。名前を変数で渡す呼び出し・UdonBehaviour 型の相手・object の変数に代入してから渡した値は確認しない(コンポーネントの取得と呼び出し)。コンパイルは通らない |
TUKI0440 | テストのファイルにあるイベント | Udon のイベント(Interact などの override と、Start・Update のように VRChat が名前で呼ぶメソッド)を、テストのファイル(名前.Tests.cs)に書いている。このファイルはワールドに含まれないので、ワールドのプログラムにそのイベントは無く、呼ばれない。テストを実行するとき(Tsukimi Tests のウィンドウと MCP の test)と、inspect にテストのファイルも渡したときに出るエラーで、テストは実行されない(ワールドに含めるコンパイルでは出ない)。イベントを .Tests.cs で終わらない本体のファイルへ移す。両方のファイルは partial で同じクラスなので、テストからはそのまま呼べる。テストメソッドと、テストで使うメソッドとフィールドは、テストのファイルに残してよい(テスト) |
TUKI0485 | 別のプログラムアセットが指す partial のファイル | partial で分けた Behaviour のファイルの 1 つを、別のプログラムアセットがソースとして指している。1 つのクラスは 1 つのプログラムにコンパイルされるので、そのファイルはこのプログラムから外れ、中のメンバ(Interact など)がワールドのプログラムに入らない。Unity でのコンパイルで出て、どちらのプログラムアセットのプログラムもコンパイルされない。基底のクラスを書いたファイルのプログラムアセットを残し、もう一方のファイルを指すプログラムアセットを消す。ファイルは消さない(クラスの続きとして、残したプログラムに入る)(クイックスタート) |
TUKI0486 | テストのファイルにだけ宣言した Behaviour | Behaviour を、テストのファイル(名前.Tests.cs)の中でだけ宣言している(public class LampSuite : TsukimiBehaviour など)。このファイルはワールドに含まれないので、その Behaviour はワールドに無い。テストを実行するとき(Tsukimi Tests のウィンドウと MCP の test)と、inspect にそのファイルを渡したときに出るエラーで、テストは実行されない(ワールドに含めるコンパイルでは出ない)。Behaviour は .Tests.cs で終わらない自分のファイル(LampSuite.cs)に宣言してプログラムアセットを作り、テストは LampSuite.Tests.cs に、基底のクラスを書かない partial のクラスとして残す(テスト) |
TUKI0490 | GPU で C# と値が違いうる書き方 | GPU のカーネルが、値によって GPU での結果が C# と違う関数・演算子・分岐の書き方を使っている(float の %・Mathf.Pow・底を指定した Mathf.Log と、float m = 0f; if (f > 0f) m = f; のように、比べた 2 つの値の片方を if の前で、もう片方を else の無い if の中で代入する書き方など)。inspect が出す情報で、カーネルごと・関数や演算子や書き方ごとに 1 件、最初に使った位置に出る。カーネルは書いたとおりに変換される。メッセージが、何をどこで使ったかと、どの値のときに違うかを示す。その値が届かないなら、直す物は無い。届く値で C# と同じ結果が必要なら、メッセージの示す書き方へ変える(剰余を int で取る・f > 0f ? f : 0f のように両方の値を 1 か所に書く、など)(カーネルから呼べる関数)。コンパイルは通る(停止しない) |
TUKI0901 | コンパイラの内部エラー | 書いたコードの誤りではない。同じコードが正しいこともあるので、書き直しても直るとは限らない |
TUKI0902 | 解析の失敗 | 解析が途中で失敗した。結果が空でも、その危険が無いという意味にはならない |
TUKI0903 | 出力したプログラムに無い名前の呼び出し | コンパイル結果のプログラムが、この環境の Udon API に存在しない名前を呼んでいる。書いたコードの中には出てこない名前 |