メインコンテンツまでスキップ

Luaスクリプティング:トラブルシューティング

webapp_banner.jpg

このページでは、Luaパワーの作成やデバッグ時に遭遇する一般的な問題と、EliteScriptから移行する作者向けのアドバイスを取り上げます。NPCスクリプトをデバッグしている場合はNPCスクリプトを参照してください。動作する例を探している場合は例とパターンを参照してください。はじめての方ははじめにを参照してください。

共有Luaエンジン

EliteMobsは、Nightbreakプラグイン全体で共有されるMagmaCore Luaスクリプティングエンジンを使用しています。サンドボックス、スケジューラ、ゾーン、ワールドAPI、エンティティテーブル、プレイヤーUIメソッドなどの共有概念のドキュメントについては、MagmaCore Luaスクリプティングエンジンページを参照してください。


一般的な問題

1. パワーがまったく読み込まれない

サーバー起動時のコンソールのエラーを確認してください。最も一般的な原因はLua構文エラー(endの欠落、括弧の不一致など)です。ファイルが.luaで終わり、正しいpowersディレクトリに配置されていることも確認してください。

2. フックが発火しない

フック名がフックリストに記載されている通りに正確に綴られていることを確認してください。よくある間違い:on_boss_hit(誤り)vs. on_boss_damaged_by_player(正しい)、またはon_tick(誤り)vs. on_game_tick(正しい)。

3. context.playerがnil

すべてのフックがプレイヤーを提供するわけではありません。on_spawnon_game_tickon_exit_combatにはプレイヤーがありません。on_enter_combatcontext.player(戦闘を発生させたプレイヤー)を提供しますon_boss_damaged(汎用ダメージ)では、ダメージを与えた相手がプレイヤーとは限りません。context.playerを使用する前には必ずnilガードを追加してください。

4. タイムアウト / 実行予算超過

フックまたはコールバックの実行に時間がかかりすぎると、ラグを防ぐためにパワーが自動的に無効になります。コンソールメッセージは次のようになります。

[Lua] my_power.lua took 73ms in 'on_game_tick' (limit: 50ms) — script disabled to prevent lag.

よくある原因:エンティティを過剰にイテレートする、ティックごとにゾーンを作りすぎる、on_game_tickで高コストの文字列操作を実行する、など。高コストの処理はクールダウンゲートの後ろに移動するか、呼び出しごとの処理量を減らしてください。

5. スケジューラコールバックが古いデータを使用している

おそらくコールバックパラメータではなく外側のcontextを使用しています。function() ... context.boss ... endfunction(tick_context) ... tick_context.boss ... endに変更してください。

6. ゾーンクエリがエンティティを返さない

ゾーン定義を再確認してください。ネイティブゾーンの場合、kindが小文字であることを確認してください("sphere"であって"SPHERE"ではない)。スクリプトユーティリティの場合、shapeが大文字であることを確認してください("CONE"であって"cone"ではない)。また、originまたはTargetが実際に有効な位置に解決されることも確認してください。

7. パーティクルが表示されない

パーティクル名が有効なBukkit Particle enum値でUPPER_CASEであることを確認してください。よくある間違い:"flame"(誤り)vs. "FLAME"(正しい)。また、amountが少なくとも1であり、その位置が読み込み済みのチャンク内にあることも確認してください。

8. クールダウンが機能していないように見える

check_local(key, duration)(1回の呼び出しでチェックと設定の両方を行う)を使用していることを確認してください。local_ready(key)の後に別途set_local(duration, key)を呼ぶ形ではありません。local_readyだけを使うと、チェックするだけでクールダウンを設定しません。

9. ボスが死後もパワーを実行し続ける

on_exit_combatおよび/またはon_deathにクリーンアップロジックを追加して、スケジューラタスクをキャンセルしてください。ボスが死ねばon_exit_combatは発火するはずですが、両方のフックに明示的なクリーンアップを追加しておくほうが安全です。


エラーメッセージの読み方

Luaパワーで何か問題が発生すると、コンソールは[Lua]プレフィックス付きの分かりやすいエラーブロックを出力します。これらのメッセージは、どのファイル、どの行、どのフックで、何が問題だったかを平易な言葉で正確に教えてくれます。デバッグの前に、必ずメッセージ全体を読んでください。

典型的なエラーは次のようになります。

[Lua] Error in 'push_zone.lua' at line 35 during 'on_boss_damaged_by_player':
[Lua] -> You tried to call a method or function that doesn't exist.
[Lua] -> Check the method name for typos, or make sure you're using ':' (colon) for method calls, not '.' (dot).
[Lua] -> Script has been disabled for this entity to prevent further errors.

このシステムは、よくあるLuaエラーを平易な言葉に翻訳します。最も一般的なものは次のとおりです。

生のLuaエラーコンソールが教えてくれること
attempt to call nil存在しないメソッドまたは関数を呼び出そうとしました。メソッド名のタイプミスを確認するか、メソッド呼び出しに.(ドット)ではなく:(コロン)を使用していることを確認してください。
index expected, got nilnilであるものに対してフィールドにアクセスしようとしました。それより前のコードで初期化されていることを確認してください。
attempt to indexnilまたは無効な値のプロパティにアクセスしようとしました。
bad argument具体的な引数の不一致の詳細を表示します(期待される型 vs. 実際の型)。
Timeout<filename> took Xms in 'hook_name' (limit: 50ms) -- ラグを防ぐためにスクリプトが無効になりました。
ヒント

コンソールに[Lua]エラーが表示されたら、エラーメッセージが、どのファイル、どの行、どのフックで、何が問題だったかを平易な言葉で正確に教えてくれます。コードに飛び込む前にメッセージ全体を読んでください -- 通常、修正方法を直接示してくれます。


文書化されていないエイリアスが存在すると仮定しないでください

Lua APIは特定のメソッド名のセットを公開しています。手動またはAIの支援でパワーを書く場合、短縮名や代替名が存在すると仮定しないでください。以下は存在せず、エラーの原因となる名前の例です。

  • show_temporary_boss_bar() -- 代わりにplayer:show_boss_bar(title, color, style, duration)を使用してください。
  • run_command_as_player() -- 代わりにplayer:run_command(command)を使用してください。
  • em.location(...) -- メソッド名が誤りです。代わりにem.create_location(x, y, z)、またはcontext.boss:get_location() / context.player.current_locationを使用してください。
  • em.vector(...) -- メソッド名が誤りです。代わりにem.create_vector(x, y, z)、またはプレーンな{x=0, y=1, z=0}テーブルを使用してください。
  • em.zone.sphere(...) -- メソッド名が誤りです。代わりにem.zone.create_sphere_zone(radius)、または{kind = "sphere", radius = 5, origin = location}のようなゾーン定義テーブルを使用してください。
  • entity:teleport_to(...) -- entity:teleport_to_location(location)を使用してください。
  • entity:set_velocity(...) -- entity:set_velocity_vector(vector)を使用してください。
  • entity:set_facing(...) -- entity:face_direction_or_location(direction_or_location)を使用してください。

疑問がある場合は、APIリファレンスページを確認してください(ボスとエンティティワールドと環境ゾーンとターゲティング)。そこに文書化されていなければ、存在しません。


EliteScript作者向けの移行アドバイス

すでに良いEliteScriptを書けるなら、Luaパワーを学ぶ最も簡単な方法は次のとおりです。

  1. イベント、ターゲット、ゾーン、相対ベクトル、パーティクルの観点で考え続けてください。 概念は同じです -- 構文だけが変わります。EliteScriptのイベントはon_spawnon_boss_damaged_by_playerのようなフック名になります。ターゲットとゾーンは、EliteScriptゾーンEliteScriptターゲットのページに文書化されている同じフィールド名を使い、テーブルとしてcontext.scriptに渡されます。

  2. 制御フローをLuaに移行してください。 ランダムロール、共有ヘルパー関数、ループ、永続ステート(context.state)、タスクスケジューリング(context.scheduler)は、純粋なEliteScriptでは簡単にできない、Luaが追加するものです。まずは1つの分岐や条件付きパワーをLuaに変換し、他はすべて同じに保つことから始めてください。

  3. ターゲティングとゾーンジオメトリにはcontext.scriptを使用してください。 スクリプトユーティリティはEliteScriptと同じフィールド名(targetTypeshapeTargetTarget2rangeoffsetcoverage)を受け付けるため、それらの仕様については既存のEliteScriptドキュメントを引き続きリファレンスとして使えます。これにより、ロジック層でLuaの柔軟性を得ながら、慣れ親しんだパターンを活用できます。


初心者の学習パス

このシステムをゼロから学びたい場合、次の段階を踏むとうまくいきます。

  1. api_version = 1on_spawnだけのファイルを書く。
  2. ボスにメッセージを送信させるか、サウンドを再生させる。
  3. context.cooldownsでクールダウンを追加する。
  4. on_boss_damaged_by_playerのような、プレイヤーがトリガーするフックを1つ追加する。
  5. context.scheduler:run_after(...)で遅延アクションを1つ追加する。
  6. 単純なネイティブLuaゾーンクエリ、または単純なcontext.script:target(...)を1つ追加する。
  7. それからやっと、回転攻撃、ステートマシン、マルチステップのメカニクスに進む。

各ステップは前のステップの上に積み上がり、どの段階でもテストできます。最初のLuaパワーとしてマルチフェーズのボスを書こうとしないでください。


次のステップ

  • はじめに -- ファイル構造、フック、最初のパワーの解説、コピー&ペースト用テンプレート
  • NPCスクリプト -- NPCの近接、インタラクション、ライフサイクルのスクリプト
  • 例とパターン -- 学習・応用できる完全な動作パワー