プログラムを書く際(最も単純なものから最も高度なものまで)、プログラムの動作不良を引き起こすバグに必ず遭遇することになります。サンドボックスの性質上、何が起きているのかを正確に把握するのは少し難しい場合があります。そこで、スクリプトの問題を特定するのに役立つヒントをいくつかご紹介します。
「原始人式」デバッグ
スクリプトが実行されている環境に直接アクセスできないため、プログラムで何が起きているかを把握するには、大量のlog()呼び出しに頼ることになります。たとえば、あるコマが正しく動作していない理由がわからず、やり取りされている値について理解を深めたい場合は、次のように実行するとよいでしょう:
on("change:graphic:left", function(obj) {
//ここに渡ってくるオブジェクトの「left」値は何か?
log(obj.get("left"));
obj.set("left", obj.get("left") + 70);
//今は何になっている?
log(obj.get("left"));
//オブジェクト全体をデバッグして、その現在の属性のリストを確認することもできます
log(obj);
});
log()コマンドの出力は、「Mod 出力コンソール」で確認できます。このコンソールは、キャンペーンの「Mod スクリプト設定」ページにあります。
Mod Script サンドボックス v1.5 専用です。可能な限り、エラーメッセージにはコンテキストオブジェクトが含まれるため、どのRoll20オブジェクトが関係していたか(タイプ とID)を確認できます:
エラー:toBelow() は、Roll20 のグラフィック、テキスト、またはパスオブジェクトを引数として呼び出す必要があります。 [Roll20キャラクター -NM0tVij02hIfnoTdihc] で呼び出されました。
エラーロック
サンドボックスは、スクリプトに発生した軽微なエラーに対して、必要に応じてスクリプトを再起動することで自動的に回復します。ただし、回復不可能な重大なエラーを検出した場合、スクリプトを何度も再起動してもエラーが繰り返されるだけになるのを防ぐため、キャンペーンに「エラーロック」をかけ、エラーが解決されるまでModスクリプトが実行されないようにします。スクリプトがエラーによりロックされている場合、「Modスクリプト設定」ページに次のようなメッセージが表示されます:
心配しないで!スクリプトを変更して問題を解決してみてください。その後、「スクリプトを保存」ボタンをクリックしてください。そうすると、エラーロックが解除され、サンドボックスがスクリプトの実行を再度試みます。別のエラーが発生した場合、エラーロックが再適用されます。この手順は、エラーが解消されるまで何度でも繰り返すことができます。失敗回数が多すぎるという理由で、エラーロックの解除ができなくなることはありません。
スクリプト固有のコールスタック
コールスタックにはスクリプト名と行番号が表示されます。
エラーには、連結されたサンドボックスファイルではなく、スクリプト名と行番号が記載された書き換えられたコールスタックが含まれます。手動スクリプトには「SCRIPT」というラベルが付けられ、その後にタブに付けた名前、タブ番号、エラーが発生した行番号、および列オフセットが表示されます:
| パート | 例 |
|---|---|
| ラベル | スクリプト |
| トークン名 | 「悪役」スクリプト |
| タブ | 85 |
| 線 | 3 |
| コラム | 13 |
例:SCRIPT:Bad Actor スクリプト [タブ 85]:3
ワンクリックライブラリスクリプトも同様ですが、ラベルは「1-CLICK」となっています:
コールスタック全体が変換されるため、複数のスクリプトが他のスクリプトを呼び出している場合でも、その処理がどこで行われているのかを把握できるようになります。
無限ループの可能性が検出されました 詳細情報
サンドボックスがハートビートを送信しなくなると、シャットダウンし、無限ループに陥る可能性があります。そのイベントと、実行されていたコールバックがどこに登録されていたかが表示されます。これにより、問題が発生している箇所を特定しやすくなり、解決策を見つけるまでの時間を大幅に短縮できるはずです。
- イベント:
change:graphic - コールバック:Bad Actorスクリプトの37行目
よくある間違い
以下に、より一般的に遭遇するエラーをいくつか示します:
myvar は定義されていません
on("ready", function() {
var myVar;
log(myvar);
});
エラーメッセージには「未定義」と表示されていますが、実際にはその変数が宣言されていないのです。この最も一般的な原因の一つは、変数名のタイプミスです。例えば、大文字の省略などが挙げられます。
プロパティ「myProperty」を読み取れません、またはメソッド「myMethod」を呼び出せません
on("ready", function() {
var myVar;
log(myVar.myProperty);
log(myVar.myMethod());
});
myVar は定義されていないため、スクリプトは、myVar のプロパティにアクセスしようとした場合、どのように処理すべきか判断できません。これはおそらく次のいずれかが原因です:
-
getObjまたはfindObjsを使用してオブジェクトを検索しようとしましたが、結果は未定義でした。プロパティにアクセスする前に、変数が定義されていることを確認するためのエラーチェックを実行してください。 - 変数が条件付きで定義されている(一連の
if文などを使って)ため、どの条件にも一致しなかった結果、変数は宣言されたまま、実際には定義されませんでした。すべての可能性に対する条件を必ず用意するか、デフォルトオプションを設定するか、プロパティにアクセスする前に変数が定義されていることを確認するためのエラーチェックを実行してください。
Roll20のオブジェクトにもgetとsetが必要です。 obj.leftは卓上の位置ではありません。obj.get("left") を使用してください。
予期しないトークン
キャラクターが不足しているか、余分なキャラクターが含まれています。これは、オブジェクトのプロパティのリストや配列の要素の間にコンマを忘れた場合、あるいは複雑なネストされたメソッド呼び出しの末尾で閉じ括弧が多すぎたり少なすぎたりした場合に発生することがあります。
_displayname は undefined を返すのに対し、get("_displayname")は名前を返す
Roll20 オブジェクトのプロパティのほとんどは、get()およびset()メソッドを介してアクセスする必要があります。 get() を使用する場合、読み取り専用プロパティについては先頭のアンダースコアを省略してもかまいません。つまり、obj.get("displayname")はobj.get("_displayname") と同じ意味になります。 obj._displaynameではありません。
それでも問題が解決しない場合は、ぜひ「Mod Scriptsフォーラム」に投稿してください。コンソールのエラーメッセージと、期待していた結果についての簡単な説明を記載してください。