跳至主要內容

Lua 腳本:行為程式

webapp_banner.jpg

行為程式會以 Lua 行為取代生物的原生 AI,由這些行為決定生物要往哪裡移動、看向何處、以哪個實體為目標,以及何時攻擊。EliteMobs 透過 MagmaCore 的 Mind 執行階段,在 Minecraft 原生的 Brain 系統上執行這些程式。

行為程式不是 Lua 能力。Lua 能力會回應 on_boss_damaged_by_player 等 Boss 事件;行為程式則每個 tick 執行一次,並掌控生物的移動控制權。一個 Boss 可以同時使用兩者:行為可以透過 on_mind_action 請 Boss 的能力執行某個動作。

選擇程式

在自訂 Boss 檔案中設定 behavior(詳見建立 Boss),或在該實體類型的生物屬性檔案中設定。behavior: native 會保留原版 AI。若伺服器版本不支援原生 Mind,EliteMobs 會在啟動時記錄 Native Mind interface is unavailable on this Minecraft version.。此時選擇了程式的自訂 Boss 不會生成,並記錄 Cannot spawn <boss file>: ...。若 Boss 的 behavior 指向不存在或無效的程式,無論在哪個版本都會以相同方式失敗。


檔案​

行為檔案位於 plugins/EliteMobs/behaviors/。以下隨附檔案不存在時,EliteMobs 會將其寫入:

plugins/
EliteMobs/
behaviors/
basic_melee.lua
modules/
target.lua
pursuit.lua
melee.lua
wander.lua
  • 位於任何名為 modules 之資料夾內的 .lua 檔案是模組。其他所有 .lua 檔案都是程式。
  • Boss 以相對於 behaviors/ 的路徑參照程式,例如 basic_melee.lua 或 guards/patrol_guard.lua。
  • EliteMobs 會在其 Mind 服務啟動時載入行為檔案。驗證失敗的檔案會被略過,主控台會記錄 Could not load behavior <file> 或 Could not load behavior module <file> 以及原因。
  • 程式與模組 ID 使用 elitemobs 命名空間,例如 elitemobs:behavior/basic_melee。ID 為小寫,可包含 a-z、0-9、.、_ 與 -,冒號之後還可使用 /。兩個程式不能共用同一個 ID,而每個模組 ID 都應只由一個檔案宣告。
  • 一個命名空間最多容納 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
}
}
欄位型別說明
id字串必填。含命名空間的 ID;位於 behaviors/ 的檔案使用 elitemobs:...。
revision正整數必填。
modules字串陣列選填。要加入程式的模組 ID,其記憶、感測器與行為都會併入程式。依賴項會在需要它們的模組之前載入。重複項目與循環依賴會被拒絕。
memories、sensors、behaviors表選填。程式可以宣告自己的這些項目,格式與模組相同。
budget表選填的軟性排程限制。請參閱預算。
runaway表選填的單一回呼硬性限制。請參閱預算。

模組檔案​

模組檔案會回傳 ai.module { ... },用來將可重複使用的記憶、感測器與行為組合在一起:

欄位型別說明
id字串必填。含命名空間的模組 ID。
revision正整數必填。
dependencies字串陣列選填。此模組所需的其他模組 ID。
memories表選填。請參閱記憶。
sensors陣列選填。ai.sensor { ... } 項目。
behaviors陣列選填。ai.behavior { ... } 項目。

sensors、behaviors、modules 與 dependencies 必須是沒有空缺也沒有具名鍵的純陣列。感測器、行為與記憶的名稱,在程式的所有模組之間都必須是唯一的。


記憶​

記憶是具有型別的值,供感測器與行為針對同一隻生物共用。請以名稱逐一宣告:

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 的第三個參數是選填的;有提供時,該值會在經過指定的 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
}
欄位型別預設值說明
id字串必填。
interval正整數1兩次執行之間的 tick 數。
sense函式必填。接收 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
}
欄位型別預設值說明
id字串必填。
priority整數0數字越小越優先。
controls陣列無此行為執行期間租用的控制權。
can_start函式一律為 true必須回傳 true 或 false。
can_continue函式與 can_start 相同必須回傳 true 或 false。
start函式無行為開始時執行一次。
tick函式必填。行為執行期間每個 tick 執行一次。
stop函式無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 致動器沒有物品方法。

每個控制權同一時間只屬於一個執行中的行為。priority 數字較小的行為會從數字較大的行為手中奪取控制權,被奪取的行為會以原因 preempted 停止。它無法奪取數字較小之行為所持有的控制權。優先度相同時,id 依字母順序排在前面的行為會取得控制權。在未持有對應控制權的情況下呼叫致動器方法會引發錯誤。c.actuator:stop_all() 只會停止該行為所持有的項目。

在隨附模組中,目標選擇使用優先度 5、近戰攻擊 10、追擊 20、閒置遊蕩 50,因此只要有目標存在,追擊就會從遊蕩手中取得移動控制權。

請求 Boss 動作​

持有 ai.controls.action 的行為可以呼叫 c.actions:request(identifier, payload)。EliteMobs 會透過 on_mind_action 將請求傳送給 Boss 的 Lua 能力。識別碼必須是不超過 128 個字元的小寫命名空間鍵,例如 'elitemobs:slam'。承載資料最多可有 16 個項目,鍵為不超過 64 個字元的小寫字串,字串值的上限為 256 個字元;無效的識別碼或承載資料會引發錯誤。此呼叫會回傳 accepted、deferred 或 rejected;在同一個 tick 內超過程式 max_action_requests 的請求會回傳 deferred。承載資料格式請參閱 Mind 動作上下文。


預算​

budget 設定軟性排程限制。當某隻生物在一個 tick 內達到其中一項限制時,Mind 執行階段會略過該生物在此 tick 剩餘的回呼,直到下一個 tick。已在執行中的回呼一定會執行完畢。

鍵預設值說明
callback_micros2000執行時間超過此值的回呼,會結束該生物在此 tick 的回呼。
entity_micros4000每隻生物每個 tick 的回呼總時間。
server_micros20000所有 Mind 程式合計用掉這麼多時間後,該生物在此 tick 的回呼就會停止。
max_callbacks128每隻生物每個 tick 的回呼次數。
max_action_requests8每隻生物每個 tick 的動作請求次數;最多 64。

所有值都必須為正數,且 callback_micros 不得超過 entity_micros,entity_micros 也不得超過 server_micros。

runaway 設定會中斷單一回呼的硬性限制:

鍵預設值說明
cpu_micros50000每個回呼的執行緒 CPU 時間。
max_instructions50000每個回呼的 Lua 指令數。

budget 也接受 max_instructions,如隨附的 basic_melee.lua 所示。請在 budget 或 runaway 其中之一宣告,不要兩者都宣告。超過 runaway 限制的回呼,會像其他回呼錯誤一樣失敗。


後續步驟​