寵物行為模組
寵物行為模組是一個 Lua 檔案,用來告訴寵物該做什麼:跟隨主人、漂移、繞著營火打轉、螫刺。每個寵物物種檔案會列出其寵物執行的模組,並為它們提供設定。本頁寫給想修改模組或撰寫新模組的生物作者。若要使用並調整內附的模組,請參閱寵物。
模組使用與 EliteMobs 行為程式相同的 Lua 語法:ai.module、ai.behavior、ai.sensor、ai.controls、具型別的記憶,以及 c.memory、c.perception、c.actuator 和 c.entity 上下文。共用的規則請見該頁。本頁則說明寵物額外提供的部分:模組檔案、c.pet、c.settings,以及寵物執行時受到的限制。
檔案
- 模組位於
plugins/FreeMinecraftModels/pet_behaviors/,可放在該資料夾或任何子資料夾中。其中每個.lua檔案都是一個模組。 - 模組的名稱是去掉
.lua的檔名,並轉為小寫。只能使用字母、數字、.、_和-。寵物檔案以這個名稱列出模組。 - 模組的
id必須是fmm:pet/加上它的名稱,因此pet_behaviors/mine/slow_drift.lua要宣告id = 'fmm:pet/slow_drift'。id 與檔名不符的模組會被略過並顯示警告。 - 當兩個檔案同名時,路徑排序在前的會被載入,主控台會針對另一個發出
Duplicate content filename警告。位元組完全相同的副本會被靜默略過。 - 連結到
pet_behaviors/之外的檔案或資料夾會被略過。 - 對於內附的 15 個模組,只要資料夾中任何位置都沒有同名檔案,FreeMinecraftModels 就會寫入該模組。被刪除的模組會在下次載入時以目前內附的版本回來。已經存在的檔案永遠不會被覆寫,不論是否編輯過,即使你把它移到子資料夾也一樣,所以它會保留你的變更,同時也會錯過內附模組之後的更新。
/fmm reload會重新讀取每個模組和寵物檔案,把寵物收起來,再讓牠們以新的模組回來。牠們的記憶會從空白開始。編輯模組之後,不需要提高它的revision。
從副本開始
內附的模組是最好的範例:drift.lua 讓飛行型移動,wander.lua 讓步行型行走,night_glow.lua 是單一個感測器,sting.lua 則有兩個。請從最接近你需求的那個開始。
- 以新名稱複製它,例如從
drift.lua複製成pet_behaviors/mine/slow_drift.lua。 - 把它的
id改為fmm:pet/slow_drift。 - 重新命名它的記憶、行為和感測器,讓它們以新名稱開頭:
drift_to變成slow_drift_to,在memories和每個c.memory呼叫中都要改,而行為的id = 'fmm:pet/drift'變成fmm:pet/slow_drift。同一隻生物上的兩個模組不能共用記憶名稱、行為 id 或感測器 id;列在後面的那個會被排除並顯示警告。重新命名可以讓副本與原件並存。 - 在寵物檔案中以它取代原件:
- slow_drift,或帶設定的- slow_drift: { speed: 0.03 }。 - 執行
/fmm reload並檢查主控台。
直接編輯內附模組也可以,但這會改變所有列出它的物種。
模組檔案
這個模組很小但完整。夜間,寵物會在其錨點附近固定停在一個位置而不是漂移,並且從選定該位置的那一刻起,每 10 秒播放一次動畫。
-- At night: settles on one spot near its anchor (its owner, or home when wild) and plays an animation now and then.
return ai.module {
id = 'fmm:pet/night_rest', revision = 1,
-- radius: blocks around the anchor. speed: blocks per tick for a flyer, at species speed 1.
settings = { radius = 3, speed = 0.04, animation = 'interact' },
memories = { night_rest_to = 'position', night_rest_retry = 'integer' },
behaviors = {
ai.behavior {
id = 'fmm:pet/night_rest', priority = 12, probe_interval = 10,
controls = { ai.controls.move, ai.controls.look },
can_start = function(c)
return c.pet.night and not c.pet.staying and c.pet.anchor ~= nil
and c.tick >= (c.memory:get('night_rest_retry') or 0)
end,
can_continue = function(c)
return c.pet.night and not c.pet.staying and c.memory:contains('night_rest_to')
end,
start = function(c)
local anchor = c.pet.anchor
local to = anchor and c.pet:rest_point(anchor, c.settings.radius)
if to ~= nil then
c.memory:set('night_rest_to', to)
else
-- Nothing fits here: look again in 5 seconds instead of every tick.
c.memory:set('night_rest_retry', c.tick + 100)
end
end,
tick = function(c)
local to = c.memory:get('night_rest_to')
if to ~= nil then c.pet:steer_to(to, c.settings.speed * c.pet.species.speed) end
end,
stop = function(c)
c.memory:forget('night_rest_to')
c.pet:stop()
end
}
},
sensors = {
ai.sensor {
id = 'fmm:pet/night_rest_animation', interval = 200,
sense = function(c)
if c.memory:contains('night_rest_to') then c.pet:play_animation(c.settings.animation) end
end
}
}
}
寵物檔案接著以 - night_rest 列出它,或寫成 - night_rest: { radius: 5, animation: idle }。
| 欄位 | 說明 |
|---|---|
id | 必填。fmm:pet/ 加上檔名 |
revision | 必填。任何正整數 |
settings | 選填。寵物檔案可以更改的預設值。每個預設值的型別就是寵物檔案必須給的型別:數字、true/false、文字,或文字清單。請參閱設定值 |
memories | 選填。模組為每隻寵物記住的內容,以名稱和型別宣告:integer、number、boolean、string、uuid 或 position。請讓每個名稱都以模組的名稱開頭。請參閱記憶 |
dependencies | 選填。此模組需要的 pet_behaviors/ 中其他模組的 id。它們會在每隻列出此模組的生物上執行,除非寵物檔案也列出它們,否則使用預設設定 |
behaviors | 選填。ai.behavior { ... } 項目,用來移動或轉動寵物 |
sensors | 選填。ai.sensor { ... } 項目,永遠不會移動寵物 |
return 之上的程式碼,例如區域函式和常數,是允許的;wander.lua 和 idle_look.lua 就有一些。
回呼會得到什麼
| 名稱 | 說明 |
|---|---|
c.pet | 寵物,唯讀。請參閱 c.pet |
c.settings | 此模組的設定:它的預設值,再加上寵物檔案和變體的值,如 c.settings.radius。每隻寵物都有自己的副本,因此寫入它只會改變該隻寵物 |
c.memory | 針對 memories 中名稱的 get(name)、set(name, value)、forget(name) 和 contains(name)。每隻寵物都有自己的記憶 |
c.tick | 目前的遊戲 tick,用於計時器 |
c.perception、c.actuator、c.entity | MagmaCore 的 Mind 上下文,與 EliteMobs 行為程式相同。c.entity 是隱藏的本體,不是模型。請參閱 Mind 程式上下文。idle_look.lua 使用 c.perception:nearest_player(range) 和 c.actuator:look_at(point) |
c.pet
點是一個含有 x、y、z,以及選填的 world 的表,如 c.pet.position。沒有 world 的點位於寵物所在的世界。位於另一個世界的點視為不存在:方法會回應 nil、false 或 0,而 distance_to 會回應 math.huge。c.pet 回傳的點一律位於寵物所在的世界,而會在別處的點讀取時為 nil。
- 方法以冒號呼叫:
c.pet:distance_to(point)。 - 數字引數必須是有限數字。半徑、深度、高度、強度等級、持續時間和其他範圍都有如下列出的上限。沒有任何方法會載入區塊。
c.pet和c.pet.species是唯讀的。對它們賦值會引發錯誤;請把每隻寵物自己的值存放在c.memory。- 屬性和
route_target()是快照:每個 tick 每隻寵物只讀取一次,並在該 tick 的所有回呼中保持不變。c.pet:teleport_near_owner和c.pet:stop會更新它們。以其他方式進行的移動,例如c.entity:teleport,會在下一個 tick 顯示。speed是例外,它永遠是即時讀取的。 - 每次讀取位置都會得到一個新的表,模組可以修改它。
屬性
| 名稱 | 型別 | 值 |
|---|---|---|
wild | bool | 野生寵物為 true,已被擁有的為 false |
staying | bool | 已被告知待命 |
settled | bool | 未待命,且為野生或位於其主人的 follow.distance 之內 |
baby | bool | 是幼崽 |
migrating | bool | 正沿著夜間遷徙路線飛行 |
model | string | 其變體的模型。穿著 babyModel 的幼崽讀到的仍是它的變體 |
position | point | 它的本體所在位置 |
home | point/nil | 野生寵物居住的地方;已被擁有的寵物為 nil |
anchor | point/nil | 它圍繞活動的對象:它的主人,野生寵物則是它的家,沒有家時為它所在的位置。主人離線或位於另一個世界時為 nil |
stay_anchor | point/nil | 它被告知待命的位置;未待命時為 nil |
owner_location | point/nil | 野生寵物,或主人離線、死亡或位於另一個世界時為 nil |
owner_distance | number | 到主人的方塊數;這個世界中沒有主人時為 math.huge |
night、day | bool | day 只在一般世界的白天為真;黃昏、黎明、地獄和終界都算 night |
raining | bool | 雨落在寵物身上,最多每 10 個 tick 檢查一次 |
speed | number | 它的本體目前的速度,單位為方塊每 tick |
route_cruise | number | 遷徙時其遷徙群的巡航速度,否則為 0 |
species | table | 寵物檔案中的數字,如下 |
c.pet.species 包含:
| 欄位 | 寵物檔案的鍵 |
|---|---|
id | species |
speed | follow.speed |
hover_height | float.hoverHeight |
hover_variance | float.hoverVariance |
roam_radius | follow.roamRadius |
follow_distance | follow.distance |
leash_distance | follow.leashDistance |
teleport_distance | follow.teleportDistance |
scale | scale |
baby_scale | babyScale |
移動
只能在行為的 start、tick 或 stop 中呼叫這些方法,且該行為的 controls 必須列出它們需要的控制權。從 can_start 或感測器呼叫 steer_to 和 stop,會引發一個指出它們該用在哪裡的錯誤。
| 方法 | 回傳 | 作用 |
|---|---|---|
steer_to(point, cruise) | bool | 朝該點前進一個 tick,所以每個 tick 都要呼叫。需要 move 和 look。飛行型以每 tick cruise 個方塊(0 到 4)的速度飛行,抵達時減速。步行型或游泳型則以其本體類型移動速度的 4 × cruise 倍原生尋路前往,且絕不低於該移動速度的四分之一;cruise 為 0 時會讓它停下並回傳 false。無法前往時回傳 false |
stop() | nil | 停止移動。需要 move |
teleport_near_owner(radius) | bool | 在它自己的介質中,把本體放到主人身旁 radius 個方塊之內(最多 64);游泳型會在 radius 與 6 個方塊兩者中較大者的範圍內尋找水。步行型或游泳型會降落在離主人至少一個方塊之外。主人不在、位於另一個世界、沒有合適的位置,或該位置沒有比寵物目前的位置至少近主人一個方塊時,回傳 false。它不需要任何控制權,但請從持有 move 的行為中呼叫它(follow_owner 就是這樣做的),這樣才不會把寵物從另一個行為手中拉走 |
位置與距離
這些可以在任何回呼中使用。回傳點的方法在沒有合適位置或區塊未載入時會回傳 nil。半徑最多到 64。
| 方法 | 回傳 | 作用 |
|---|---|---|
hover_point(center, radius) | point/nil | radius 之內、位於它懸浮區間的一個點 |
rest_point(center, radius) | point/nil | 一個在它自己介質中的休息位置:飛行型是懸浮區間,步行型或固定本體是可站立的地面,游泳型是水中(center 在水中時與 center 同高,否則在水面下 0.5 到 2 個方塊),兩棲型則是地面,沒有地面時才是水 |
ground_point(center, radius) | point/nil | 一個可站立的位置,從 center 下方約 5 個方塊到上方 4 個方塊。位於液體或高處落差之上時為 nil |
water_point(center, radius, min_depth, max_depth) | point/nil | 水面下介於兩個深度(0 到 16)之間的一個游泳位置 |
ground_below(point, depth) | number/nil | 向下 depth 個方塊(1 到 64)之內的地面頂部高度。除非物種是 AQUATIC,否則水面或岩漿表面算作地面。範圍內沒有地面時,回傳該點的高度減去 depth |
trail_point(back, height) | point/nil | 主人面向方向後方 back 個方塊處,FLYING 物種在其腳部上方 height 處,其他物種則在其腳部。主人不在或位於另一個世界時為 nil |
distance_to(point) | number | 到它的本體的方塊數 |
route_target() | point/nil | 它的遷徙路線在這個 tick 希望它前往的位置。未在遷徙或路線已結束時為 nil |
find_perch(height, radius) | point/nil | 在它下方最近的樹葉上方 height 個方塊(0 到 8),最多向側邊 radius 個方塊(0 到 4),或在它正下方的地面上方。已被擁有的寵物只會得到位於其主人 follow.distance 之內的棲息處 |
nearest_campfire(radius, keep_ticks, blocks, soul_variants, height) | point/nil | radius(1 到 32)之內、它可以使用的最近已點燃火源的方塊。blocks 列出它接受的火源種類,CAMPFIRE、SOUL_CAMPFIRE 或兩者,兩者都未列出的清單視為兩者皆可;soul_variants 列出只接受靈魂營火的模型,其他所有模型則只接受一般營火。已被擁有的寵物只會使用火源上方 height 處的位置與其主人的距離在 follow.distance 減 1 之內的火源。每個區塊的搜尋結果會保留 keep_ticks(20 到 1200),並由所有寵物共用 |
campfire_usable(fire, blocks, soul_variants, height) | bool | 之前找到的火源是否仍然點燃且仍然合適 |
效果
這些可以在任何回呼中使用;通常放在感測器中。
| 方法 | 回傳 | 作用 |
|---|---|---|
set_glow(light, lantern_bone, animation) | nil | 以 light(0 到 15)照亮模型的顯示骨骼,供 Java 玩家使用。有名為 lantern_bone 骨骼的模型也會循環播放 animation。後兩個參數是選填的 |
clear_glow() | nil | 恢復為世界光線,並結束該動畫 |
scale_toward(target, span, ticks, elapsed) | nil | 讓本體的大小逐漸趨近其基準大小的 target 倍。從 1 到 span 的完整變化需要 ticks(至少 2);elapsed 是自上次呼叫以來的 tick 數。倍率為 0.1 到 16 |
sting_contacts(on, effect, duration, amplifier, damage, cooldown) | number | 螫刺過去一秒內觸碰到野生寵物模型的玩家,不會螫刺創造或旁觀模式的玩家,並回傳螫刺的人數。即使 on 為 false,它也會清除這些觸碰記錄。已被擁有的寵物不會記錄觸碰 |
sting_enemies(reach, effect, duration, amplifier, damage, cooldown) | number | 螫刺模型碰撞箱 reach 個方塊(0 到 4)之內的敵對生物,絕不螫刺玩家或寵物,並回傳螫刺的數量 |
drizzle(depth, chance) | bool | 當寵物靜止懸浮在 depth 個方塊(1 到 8)之內的作物上方時,產生水粒子,並有 chance(0 到 1)的機率讓作物成長一個階段。位於作物上方時回傳 true |
owner_effect(effect, duration, amplifier, range) | bool | 當主人位於 range 個方塊之內時,給予主人該藥水效果 duration 個 tick(1 到 6000),且不顯示粒子。主人已有的效果若至少同樣強且持續時間至少同樣長,則不會動它。主人不在、位於另一個世界或超出範圍,或效果不存在時,回傳 false |
play_animation(name) | bool | 播放模型的其中一個動畫一次。模型沒有該動畫時回傳 false |
對於這兩種螫刺,effect 是藥水效果名稱或 NONE,duration 以 tick 為單位(1 到 6000),amplifier 為 0 時是第 I 級(最高 255),damage 以半顆心為單位,cooldown 是這隻寵物能再次螫同一個受害者之前的 tick 數(至少 1)。螫刺會顯示火花並播放蜜蜂螫刺的音效,成年寵物則播放它的 attack 動畫。不存在的藥水效果名稱,每個物種和名稱只會警告一次,並且不會套用任何效果。
行為與感測器
- 行為會移動或轉動寵物。它列出自己需要的控制權,
c.pet的移動呼叫需要ai.controls.move和ai.controls.look,而且每項控制權同一時間只由一個行為持有。行為停止時,MagmaCore 會詢問它的can_start。當它回傳true且控制權空閒時,行為就會取得控制權並執行start,接著只要can_continue回傳true,就每個 tick 執行tick(沒有can_continue時由can_start決定),最後執行stop。請參閱生命週期。 priority數字較小的優先。行為會從數字較大的執行中行為手中奪取控制權,被奪取者的stop隨後執行。範例中的12讓它排在跟隨和待命之後,並排在漂移和懸浮之前,但也排在campfire之前,所以同時列出兩者的寵物在夜間永遠不會去拜訪火源。大於15的數字才會讓火源勝出。- 行為只會爭奪它列出的控制權。
idle_look只取得look,所以只在沒有其他行為持有look時執行;每個內附的移動行為也都會取得look,因此移動永遠優先於它。 - 寵物檔案無法更改優先度。若要重新排序,請複製模組並在其中更改數字。
probe_interval是選填的,單位為 tick:行為停止期間,只會每隔這麼多個 tick 詢問一次can_start,每隻寵物各有自己的相位。當有許多寵物在外時,這能節省伺服器時間,代價是行為最多會晚這麼多個 tick 才開始。預設為1,超過200的值視為200。執行中的行為仍然每個 tick 執行。- 感測器永遠不會移動寵物。它在寵物本體第一次被 tick 的那個 tick 執行
sense,之後每隔interval個 tick 在寵物自己的相位上執行,不論行為正在做什麼。發光、膨脹、螫刺、毛毛雨和主人效果都是感測器。
內附的模組使用:
| 模組 | 優先度 | probe_interval | 感測器 interval |
|---|---|---|---|
migrate | 1 | 10 | |
stay | 5 | 4 | |
follow_owner | 10 | 4 | |
campfire | 15 | 10 | |
day_perch | 18 | 10 | |
rain_bloom | 19 | 10 | 4(膨脹) |
drift、wander、swim | 20 | 10 | |
hover | 30 | 4 | |
idle_look | 30 | 10 | |
night_glow | 40 | ||
sting | 4(玩家)、10(生物) | ||
crop_drizzle | 20 | ||
owner_effect | 20 |
規則
- 只能在行為的
start、tick或stop中呼叫steer_to和stop,且該行為必須列出它們需要的控制權。 - 把每隻寵物自己的狀態存放在
c.memory,在memories下宣告,名稱以模組的名稱開頭。 - 不要寫入
c.pet;對它賦值會引發錯誤。 - 讓回呼保持簡短。每隻寵物都在下列固定限制下執行,模組和寵物檔案都無法更改:
| 限制 | 值 |
|---|---|
| 單一回呼 | 1.5 毫秒 |
| 單隻寵物在一個 tick 內的回呼 | 3 毫秒,最多 32 個回呼 |
| 所有寵物在一個 tick 內的回呼 | 10 毫秒 |
| 單一回呼的 CPU 時間,硬性限制 | 20 毫秒 |
| 單一回呼的 Lua 指令數,硬性限制 | 20,000 |
當寵物達到前三項限制之一時,它剩餘的回呼會等到下一個 tick。超過硬性限制的回呼會被中止,並像錯誤一樣失敗。請參閱預算。
出問題時
這裡的問題都不會讓伺服器或其他生物停止運作。在主控台中搜尋 pet behavior、pet_behaviors 和 .pet.yml,即可找到這些警告。
- 模組沒有載入。 無法編譯、id 與檔名不符,或檔名含有其他字元的模組,會被略過並顯示指出該檔案的警告,若是 Lua 錯誤則還會指出行號。其他所有模組仍會載入。
- 寵物檔案列出了不存在的模組。 警告會指出該寵物檔案,並在有模組名稱只差一兩個字母時建議最接近的名稱。生物會在沒有該模組的情況下載入。當模組存在但載入失敗時,警告會指向關於其檔案的警告。
- 設定有誤。 模組沒有的設定,或型別錯誤的值,會連同寵物檔案的名稱一起回報,並保留預設值。請參閱設定值。
- 兩個模組衝突。 當同一隻生物上的兩個模組宣告了相同的記憶名稱、行為 id 或感測器 id 時,生物會保留清單中的第一個,並在沒有另一個的情況下執行,同時顯示警告。
- 寵物執行時回呼失敗。 每個程式、回呼和失敗類型在下次重新載入之前只會記錄一次。程式的名稱為
fmm:pet/creature/<species>/<variant>,回呼則以其行為或感測器 id 命名,例如fmm:pet/drift.tick。失敗的行為會被停止或不啟動,並從下個 tick 起再試一次;只要它持續失敗,優先度數字較大、會移動或轉動寵物的行為可能不會執行。失敗的感測器會在下一個間隔再次執行。 c.pet呼叫在 FreeMinecraftModels 內部失敗。 原因會連同堆疊追蹤,每個物種和呼叫只記錄一次,而回呼會以c.pet:<method> failed; the server log has the cause失敗。- 藥水效果名稱不存在。 每個物種和名稱只會警告一次,且該呼叫不會套用任何效果。
修正之後,請執行 /fmm reload。