差分
このページの2つのバージョン間の差分を表示します。
両方とも前のリビジョン 前のリビジョン 次のリビジョン | 前のリビジョン | ||
appendix:エラーのお話 [2023/02/07 16:31] fumble |
appendix:エラーのお話 [2024/11/06 18:54] (現在) fumble |
||
---|---|---|---|
行 3: | 行 3: | ||
エラーを見れるようになる必要はないですがエラーに含まれている情報でどこが重要なのかを知れば、他者に聞くときに渡すべき情報がどれかのの判断の一助になるかもしれません。\\ | エラーを見れるようになる必要はないですがエラーに含まれている情報でどこが重要なのかを知れば、他者に聞くときに渡すべき情報がどれかのの判断の一助になるかもしれません。\\ | ||
- | ====コンソール(黒いあの画面)に出力されるエラー==== | + | ====コンソール(黒いあの画面)に出力されるエラーメッセージ==== |
- | まず大きく2種類のパターンがあります。 | + | まず大きく2種類のパターンがある。。 |
* 個々の処理がエラーを捕まえて自分でエラーメッセージを出しているもの。 | * 個々の処理がエラーを捕まえて自分でエラーメッセージを出しているもの。 | ||
- | * 個々のエラー処理が例外を捕まえておらず、システム((Unityの例外処理機構))が出しているもの。 | + | * 個々のエラー処理が例外を捕まえておらず、システム((Unityとかmonoの例外処理機構))が出しているもの。 |
- | 前者の「個々の処理がエラーを捕まえて自分でエラーメッセージを出している」のほうは、どういった動作をするかはその「個々の処理」次第であるため非常に有意義な情報を出してくれる場合もあれば、まったくなにも出さなかったり誤った情報を出す場合などもあります。\\ | + | 前者の「個々の処理がエラーを捕まえて自分でエラーメッセージを出している」のほうは、どういった動作をするかはその「個々の処理」次第であるため、有意義な情報を出してくれる場合もあれば、まったくなにも出さなかったり、誤った情報を出す場合などもありえます。\\ |
\\ | \\ | ||
後者のシステムが出すものは、決まった内容を出してきます。\\ | 後者のシステムが出すものは、決まった内容を出してきます。\\ | ||
====個々の処理が出しているエラー==== | ====個々の処理が出しているエラー==== | ||
- | 役に立つ情報を出している場合もあれば、そもそも何が出しているのかわからないものもあります。\\ | + | 役に立つ情報を出している場合もあれば、内容は出している処理次第なのでそもそも何が出しているのかわからないものも。\\ |
+ | (おいらのプラグインはUnityで出力する際は((PatcherやManagedなどでConsoleに出している場合はこの限りではない。))プラグイン名とバージョンを付けるようにしている。) | ||
- | ====システム(Unityの例外処理機構)が出しているエラー==== | + | ====システム(Unityとかmonoの例外処理機構)が出しているエラー==== |
+ | 正常に動作出来ない状況になった際に例外(Exception)が発生します。\\ | ||
+ | これを捕まえ(catch)ずに放置すると見慣れたメッセージが出力されます。\\ | ||
こちらは決まったパターンで出力されます。\\ | こちらは決まったパターンで出力されます。\\ | ||
+ | |||
+ | 最初の行\\ | ||
+ | TypeLoadException: | ||
+ | 「TypeLoadException」は例外の種類、続いてその説明「A type load exception has occurred.」。\\ | ||
+ | 次の「Stack trace: | ||
===エラー(例外)の種類=== | ===エラー(例外)の種類=== | ||
- | 何がまずかったのかを表しているためヒントになることが多いですが、よくある例外だと「まぁそうだろうね」ぐらいでしかない場合も。\\ | + | 何がまずかったのかを表しているためヒントになることが多いですが、よくある例外だと「またいつものか・・・」ぐらいでしかない場合も。\\ |
==よくある例外== | ==よくある例外== | ||
* NullReferenceException | * NullReferenceException | ||
- | いわゆる「ぬるぽ」本来あるべきもの、本来取得できるものなどがない状態でそれを操作した場合など。\\ | + | いわゆる「ぬるぽ」本来あるべきもの、本来取得できるものなどがない状態でそれを操作した場合など。\\ |
- | ほとんどの場合、操作することが問題ではなくあるべきものがない、取得できるはずのものが取得できてないないことが問題。\\ | + | nullが専門用語なので一般の人にはnullを参照した?どういう意味?ってなる。\\ |
- | 直前にファイルが読めてないとか出ている場合はおそらくそれが原因。\\ | + | この「ぬるぽ」は「ぬるぽ」した処理が問題ではなく((エラーを適切に処理していないという意味では問題かもしれないが。))あるべきものがない、取得できるはずのものが取得できてないないことが問題。\\ |
+ | 直前にファイルが読めてないとか出ている場合はおそらくそれが原因。\\ | ||
+ | よくあるのはDLCの色変えMod等でDLCを持ってなくてModelが無いとか。\\ | ||
* FileNotFoundException | * FileNotFoundException | ||
- | 名前通りでファイルが見つからない場合に発生する。\\ | + | 名前通りでファイルが見つからない場合に発生する。\\ |
- | ただしデータファイルに限らずDLLなどがない場合もこれになる場合があるので要注意。\\ | + | ただしデータファイルに限らずDLLなどがない場合もこれになる場合があるので要注意。\\ |
- | * MissingFieldException | + | DLLの場合はAがBを参照していて、BがCを参照している用な状態で、Cが無いときもAの処理で出たりする。\\ |
- | 本来あるはずのものがない場合。((ある型にあるべきフィールドがない場合。))\\ | + | |
- | 非常によくあるのが" | + | |
* TypeLoadException | * TypeLoadException | ||
- | これもあるはずのものがない場合。((あるべき型がない場合。))\\ | + | 本来あるはずのType(型)((専門用語「型(かた)」例えばMaid型なら、メイドさんを表すための定義))、がない場合。\\ |
- | これも同じで" | + | * MissingFieldException |
+ | これもあるはずのField(フィールド)がない場合。((Fieldも専門用語、型にある値を格納する箇所。例えばさっきのメイドさんの例であれば名前とか。(実際は入れ子になっていてMaid.m_Status.firstName_) ))\\ | ||
+ | |||
+ | 非常によくあるのが" | ||
+ | これが出る場合は、COM3D2版とCOM3D2.5版の取り違えとか、オダメのバージョンがプラグインの想定するバージョン((バージョンアップで追加されたものが無いとか))でないかあたりを確認する。 | ||
+ | |||
+ | ===スタックトレース=== | ||
+ | 例外が発生した箇所までにどういった処理が呼び出されているかを示したもの。\\ | ||
+ | 最初の行(一番上の行)が最後に処理された箇所、つまり例外が発生した箇所です。\\ | ||
+ | |||
+ | ただ、ここに問題があると言うわけではなく、例えば渡されたメイドさんを××するという処理だとして、メイドさんが渡されなかった場合はここでメイドさんがいないんじゃぁ例外((おそらくNullReferenceException、チェックして例外を起こしたならArgumentNullExceptionとか。))が発生しますが、その原因はメイドさんを渡さなかった直前の処理です。\\ | ||
+ | その直前の処理もその前の処理が原因かもしれないのでどの処理が悪いかは単純に判断出来ません。\\ | ||
+ | ただし、エラー発生に至るまでの処理がわかるので、その処理を行ったプラグインがぁゃιぃと言うような見当を付けることは出来ます。\\ | ||
+ | |||
+ | 例外発生時にスタックトレースを出力せずに「エラー」とかだけ出すプラグインとかがあると、ログからエラー箇所を特定するのが困難に。\\ | ||
+ | (環境を考慮したスタックトレースプラグイン((メイドいぢりのUnityログを有効にしても同様の効果あり。))を入れると、Unityのログ出力の際のスタックトレースを出力するので原因箇所が特定出来るかも?) | ||
+ | |||
+ | ===バージョン不一致=== | ||
+ | |||
+ | ==プラグインインストール時になにかないと言うエラーが出る場合はバージョン不一致であることが多い。== | ||
+ | |||
+ | * COM3D2用のプラグインをCOM3D2.5に入れている | ||
+ | * COM3D2.5用のプラグインをCOM3D2に入れている | ||
+ | * プラグインの想定に対してオダメのバージョンが古すぎる | ||
+ | * プラグインの想定に対してオダメがバージョンが新しすぎる | ||
+ | |||
+ | 特に以下のものはCOM3D2とCOM3D2.5で異なっているので、COM3D2用とCOM3D2用.5用を間違えると出がち。 | ||
+ | |||
+ | * Maid.MaidProp | ||
+ | * Maid.DelSubProp | ||
+ | * CharacterMgr.PresetSet | ||
+ | * ImportCM.LoadSkinMesh_R | ||
+ | * ImportCM.ReadMaterial | ||
+ | |||
+ | * TBody関連(典型的なのはTBody.goSlot) | ||
+ | |||
+ | * COM3D2環境でIsCrcBodyがないと出たらCOM3D2.5用を入れている可能性が大。 | ||
+ | |||
+ | オダメバージョンアップ後になにかないと言うエラーが出る様になった場合は、プラグインが新しいオダメに対応出来なくなった可能性があるのでプラグインの作者に連絡するのもあり。 | ||
+ | |||
+ | プラグインが使えなくなるからオダメのバージョンを上げないという選択肢は、オダメの新しいDLCが使えないだけではなく、新しく公開されたプラグインも使えない可能性があることに注意。\\ | ||
+ | |||
+ | ===プラグインがオダメのバージョンで使えなくなる理由の例=== | ||
+ | |||
+ | ==今まで呼び出していた処理に渡さないといけないものが変更される。== | ||
+ | |||
+ | 処理(引数 a, 引数 b)だったものが、処理(引数 a, 引数 b, 引数 c)に置き換えられた様な場合。\\ | ||
+ | この場合処理の名前は同じでも渡さないいけないものが異なっているので別物として扱われる、そのため元のものがなくそんなものはないよエラーになる。\\ | ||
+ | |||
+ | ==処理結果等渡される値、返される値に想定外のものが追加される。== | ||
+ | これの典型的な例はOnLevelWasLoadedでOnLevelWasLoadedに渡されるレベルに負の値が渡されるようになって、trzr氏のプラグインは負の値が来ることを想定して居らずエラーになっている。\\ | ||
+ | |||
+ | ==enumの値が変更される。== | ||
+ | これの典型的例はSlotがずれる、カテゴリーがずれるというやつ。\\ | ||
- | ===エラーが発災した場所とその経路=== | + | enumは例えば |
- | スタックトレースと呼ばれる処理が呼び出された順序。\\ | + | enum SlotId |
- | どういった流れでどこの処理で発生したかわかるためかなりのヒントになります。\\ | + | { |
- | 「場所: | + | body, |
+ | head, | ||
+ | eye, | ||
+ | } | ||
+ | と定義するとbodyは0, | ||
+ | enum SlotId | ||
+ | { | ||
+ | body, | ||
+ | TNTN, | ||
+ | head, | ||
+ | eye, | ||
+ | } | ||
+ | bodyは0のままだがTNTNの1が追加され、headは2, | ||
+ | 例えばプラグインで頭を大きくしようと MakeBig(head)((ちなみにこんな処理はない、頭の大きさを変えたいならMaid.SetPropをHeadXとかHeadYで呼ぶ。)) の様に呼び出していると、コンパイル時に MakeBig(1) と置き換えてしまう。\\ | ||
+ | (コンパイラーは実行時に都度名前から数値に置き換えのは無駄だとし、コンパイル時に確定してしまう。)\\ | ||
+ | これを新しい環境で実行すると、1は頭じゃなくTNTNなのでTNTNが大きなってしまう。\\ | ||
+ | この問題への簡単な対応は新しい環境でコンパイルし直すことで、コンパイルし直すとMakeBig(head)はMakeBig(2)なり正常に動作するようになる。\\ | ||
+ | (ただし、これを古い環境で実行すると、2はeyeなのでおめめぱっちりになる。)\\ |