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

Luaスクリプティング:行動プログラム

webapp_banner.jpg

行動プログラムは、モブのネイティブAIをLuaのビヘイビアに置き換え、モブがどこへ移動し、何を見て、どのエンティティをターゲットにし、いつ攻撃するかを決めます。EliteMobsはこれらのプログラムを、MagmaCoreのMindランタイムを通じてMinecraftのネイティブBrainシステム上で実行します。

行動プログラムはLuaパワーではありません。Luaパワーはon_boss_damaged_by_playerなどのボスイベントに反応しますが、行動プログラムは毎tick実行され、モブの移動制御を所有します。ボスは両方を使えます。ビヘイビアはon_mind_actionを通じて、ボスのパワーにアクションの実行を依頼できます。

プログラムの選択

ボスの作成で説明しているとおり、カスタムボスファイル、またはエンティティタイプのモブプロパティファイルでbehaviorを設定します。behavior: nativeはバニラのAIを維持します。サーバーのバージョンがネイティブMindに対応していない場合、EliteMobsは起動時にNative Mind interface is unavailable on this Minecraft version.をログに出力します。その場合、プログラムを選択したカスタムボスはスポーンせず、Cannot spawn <boss file>: ...がログに出力されます。behaviorに存在しないプログラムや無効なプログラムを指定したボスは、どのバージョンでも同じように失敗します。


ファイル​

行動ファイルはplugins/EliteMobs/behaviors/に置きます。EliteMobsは、次の同梱ファイルが存在しない場合に書き出します。

plugins/
EliteMobs/
behaviors/
basic_melee.lua
modules/
target.lua
pursuit.lua
melee.lua
wander.lua
  • modulesという名前のフォルダ内にある.luaファイルはモジュールです。それ以外の.luaファイルはすべてプログラムです。
  • ボスはbehaviors/からの相対パスでプログラムを参照します。例:basic_melee.luaやguards/patrol_guard.lua。
  • EliteMobsはMindサービスの起動時に行動ファイルを読み込みます。検証に失敗したファイルはスキップされ、コンソールに理由とともにCould not load behavior <file>またはCould not load behavior module <file>が出力されます。
  • プログラムとモジュールのIDは、elitemobs:behavior/basic_meleeのようにelitemobs名前空間を使います。IDは小文字で、a-z、0-9、.、_、-を使え、コロンの後には/も使えます。2つのプログラムが同じIDを共有することはできず、各モジュールIDは1つのファイルでのみ宣言してください。
  • 1つの名前空間に含められるモジュールは最大256個です。モジュールが列挙できる依存関係は最大32個、プログラムが解決できるモジュールは最大64個で、各ソースファイルは1,000,000文字までに制限されます。

他のLuaスクリプトと同じサンドボックスのルールが適用されます。Luaサンドボックスを参照してください。プログラムを実行する各モブは独自のLua環境を持つため、ファイルローカルの変数はモブ間で共有されません。


プログラムファイル​

プログラムファイルはai.program { ... }を返します。

return ai.program {
id = 'elitemobs:behavior/basic_melee', revision = 1,
modules = {
'elitemobs:behavior/target', 'elitemobs:behavior/pursuit',
'elitemobs:behavior/melee', 'elitemobs:behavior/wander'
},
budget = {
callback_micros = 2000, entity_micros = 4000, server_micros = 5000,
max_callbacks = 20, max_instructions = 12000, max_action_requests = 2
}
}
フィールド型備考
idstring必須。名前空間付きのID。behaviors/内のファイルではelitemobs:...です。
revision正の整数必須。
modules文字列の配列任意。メモリ、センサー、ビヘイビアをプログラムに加えるモジュールのID。依存関係は、それを必要とするモジュールより先に読み込まれます。重複と依存関係の循環は拒否されます。
memories、sensors、behaviorsテーブル任意。プログラムはモジュールと同じ形式で独自のものを宣言できます。
budgetテーブル任意のソフトなスケジューリング制限。バジェットを参照してください。
runawayテーブル任意のコールバックごとのハードな制限。バジェットを参照してください。

モジュールファイル​

モジュールファイルはai.module { ... }を返し、再利用できるメモリ、センサー、ビヘイビアをまとめます。

フィールド型備考
idstring必須。名前空間付きのモジュールID。
revision正の整数必須。
dependencies文字列の配列任意。このモジュールが必要とする他のモジュールのID。
memoriesテーブル任意。メモリを参照してください。
sensors配列任意。ai.sensor { ... }のエントリー。
behaviors配列任意。ai.behavior { ... }のエントリー。

sensors、behaviors、modules、dependenciesは、欠番や名前付きキーのない単純な配列である必要があります。センサー、ビヘイビア、メモリの名前は、プログラム内のすべてのモジュールを通じて一意である必要があります。


メモリ​

メモリは、1体のモブについてセンサーとビヘイビアが共有する型付きの値です。それぞれ名前を付けて宣言します。

memories = {
candidate = { type = 'uuid', persistent = false },
next_attack = 'integer'
}
型Luaの値
string文字列
boolean真偽値
integer整数
number数値
uuidUUID文字列
position{ world = 'world', x = 0, y = 64, z = 0 }

コロンを含まない名前は、プログラムの名前空間に置かれます。persistentのデフォルトはfalseで、trueにするとそのメモリはMindの保存状態とともにシリアライズされる対象になります。メモリの読み書きにはc.memory:get(name)、c.memory:set(name, value, ttl_ticks)、c.memory:forget(name)、c.memory:contains(name)を使います。setの3番目の引数は省略可能で、指定するとその値はそのtick数の後に期限切れになります。宣言していない名前を使うとエラーになります。


センサー​

センサーは情報を収集し、通常はメモリに格納します。センサーはビヘイビアより先に実行されます。

ai.sensor {
id = 'elitemobs:behavior/find_target', interval = 20,
sense = function(c)
local target = c.perception:nearest_player(35)
if target then c.memory:set('candidate', target.uuid, 21)
else c.memory:forget('candidate') end
end
}
フィールド型デフォルト備考
idstring必須。
interval正の整数1実行間隔のtick数。
sensefunction必須。Mindコンテキストを受け取ります。

センサーはc.actuatorを使えません。センサーからアクチュエーターのメソッドを呼び出すとエラーになります。


ビヘイビア​

ビヘイビアは、宣言したコントロールを保持している間、モブに対して動作します。

ai.behavior {
id = 'elitemobs:behavior/attack', priority = 10,
controls = { ai.controls.attack },
can_start = function(c) return c.perception:current_target() ~= nil end,
can_continue = function(c) return c.perception:current_target() ~= nil end,
tick = function(c)
local target = c.perception:current_target()
if target then c.actuator:attack(target) end
end
}
フィールド型デフォルト備考
idstring必須。
priorityinteger0数値が小さいほど優先されます。
controlsarrayなしこのビヘイビアが実行中に確保するコントロール。
can_startfunction常にtruetrueまたはfalseを返す必要があります。
can_continuefunctioncan_startと同じtrueまたはfalseを返す必要があります。
startfunctionなしビヘイビアの開始時に1回実行されます。
tickfunction必須。ビヘイビアの実行中、毎tick実行されます。
stopfunctionなしfunction(c, reason)。ビヘイビアの停止時に実行されます。

ライフサイクル​

  1. 停止中、ビヘイビアはcan_startを確認します。trueが返り、宣言したすべてのコントロールを確保できると、startが実行されます。
  2. 実行中は開始したtickも含めて毎tick、まずcan_continueが実行されます。falseが返るとビヘイビアは理由completedで停止し、それ以外の場合はtickが実行されます。
  3. stop(c, reason)は、completed、preempted、program_replaced、entity_removed、callback_failed、handle_closedのいずれかを受け取ります。停止するとビヘイビアのコントロールが解放され、保持していた移動、ターゲット、攻撃が止まります。

can_continue、start、tickでLuaエラーが発生すると、ビヘイビアはcallback_failedで停止します。can_startやcan_continueから真偽値以外を返すとエラーになります。失敗ごとに、コンソールにMind <program> callback <callback> failed with ...が出力されます。

コントロール​

コントロール許可される操作
ai.controls.movec.actuator:move_to(...)、c.actuator:stop_moving()
ai.controls.lookc.actuator:look_at(...)
ai.controls.jumpc.actuator:jump()
ai.controls.targetc.actuator:set_target(...)、c.actuator:clear_target()
ai.controls.attackc.actuator:attack(...)
ai.controls.actionc.actions:request(...)
ai.controls.use_item予約済み。Luaのアクチュエーターにはアイテム用のメソッドがありません。

各コントロールは、一度に1つの実行中ビヘイビアだけが保持します。priorityの数値が小さいビヘイビアは、数値が大きいビヘイビアからコントロールを奪い、奪われた側は理由preemptedで停止します。数値が小さいビヘイビアが保持しているコントロールは奪えません。優先度が同じ場合は、idがアルファベット順で先になるビヘイビアがコントロールを得ます。コントロールを保持せずにアクチュエーターのメソッドを呼び出すとエラーになります。c.actuator:stop_all()は、そのビヘイビアが保持しているものだけを停止します。

同梱モジュールでは、ターゲット選択が優先度5、近接攻撃が10、追跡が20、待機中の徘徊が50を使います。そのため、ターゲットが存在するとすぐに追跡が徘徊から移動を奪います。

ボスのアクションの要求​

ai.controls.actionを保持しているビヘイビアは、c.actions:request(identifier, payload)を呼び出せます。EliteMobsはこの要求を、on_mind_actionを通じてボスのLuaパワーに送ります。識別子は'elitemobs:slam'のような、128文字以内の小文字の名前空間付きキーである必要があります。ペイロードに含められるエントリーは最大16個で、キーは64文字以内の小文字、文字列の値は256文字までに制限されます。無効な識別子やペイロードはエラーになります。呼び出しはaccepted、deferred、rejectedのいずれかを返し、1tick内でプログラムのmax_action_requestsを超えた要求はdeferredを返します。ペイロードの形式はMindアクションのコンテキストを参照してください。


バジェット​

budgetはソフトなスケジューリング制限を設定します。あるtickでモブがいずれかの制限に達すると、Mindランタイムは次のtickまでそのモブの残りのコールバックをスキップします。すでに実行中のコールバックは必ず最後まで実行されます。

キーデフォルト備考
callback_micros2000これより長く実行されたコールバックがあると、そのtickのモブのコールバックは終了します。
entity_micros4000モブ1体・1tickあたりのコールバックの合計時間。
server_micros20000すべてのMindプログラムの合計使用時間がこの値に達すると、そのtickのモブのコールバックは停止します。
max_callbacks128モブ1体・1tickあたりのコールバック数。
max_action_requests8モブ1体・1tickあたりのアクション要求数。最大64。

すべての値は正である必要があり、callback_microsはentity_microsを、entity_microsはserver_microsを超えられません。

runawayは、1つのコールバックを中断するハードな制限を設定します。

キーデフォルト備考
cpu_micros50000コールバックごとのスレッドCPU時間。
max_instructions50000コールバックごとのLua命令数。

同梱のbasic_melee.luaのように、budgetでもmax_instructionsを指定できます。budgetとrunawayのどちらか一方で宣言し、両方には書かないでください。runawayの制限を超えたコールバックは、他のコールバックエラーと同じように失敗します。


次のステップ​