跳至主要內容

寵物行為模組

寵物行為模組是一個 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 則有兩個。請從最接近你需求的那個開始。

  1. 以新名稱複製它,例如從 drift.lua 複製成 pet_behaviors/mine/slow_drift.lua。
  2. 把它的 id 改為 fmm:pet/slow_drift。
  3. 重新命名它的記憶、行為和感測器,讓它們以新名稱開頭:drift_to 變成 slow_drift_to,在 memories 和每個 c.memory 呼叫中都要改,而行為的 id = 'fmm:pet/drift' 變成 fmm:pet/slow_drift。同一隻生物上的兩個模組不能共用記憶名稱、行為 id 或感測器 id;列在後面的那個會被排除並顯示警告。重新命名可以讓副本與原件並存。
  4. 在寵物檔案中以它取代原件:- slow_drift,或帶設定的 - slow_drift: { speed: 0.03 }。
  5. 執行 /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.entityMagmaCore 的 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 是例外,它永遠是即時讀取的。
  • 每次讀取位置都會得到一個新的表,模組可以修改它。

屬性​

名稱型別值
wildbool野生寵物為 true,已被擁有的為 false
stayingbool已被告知待命
settledbool未待命,且為野生或位於其主人的 follow.distance 之內
babybool是幼崽
migratingbool正沿著夜間遷徙路線飛行
modelstring其變體的模型。穿著 babyModel 的幼崽讀到的仍是它的變體
positionpoint它的本體所在位置
homepoint/nil野生寵物居住的地方;已被擁有的寵物為 nil
anchorpoint/nil它圍繞活動的對象:它的主人,野生寵物則是它的家,沒有家時為它所在的位置。主人離線或位於另一個世界時為 nil
stay_anchorpoint/nil它被告知待命的位置;未待命時為 nil
owner_locationpoint/nil野生寵物,或主人離線、死亡或位於另一個世界時為 nil
owner_distancenumber到主人的方塊數;這個世界中沒有主人時為 math.huge
night、dayboolday 只在一般世界的白天為真;黃昏、黎明、地獄和終界都算 night
rainingbool雨落在寵物身上,最多每 10 個 tick 檢查一次
speednumber它的本體目前的速度,單位為方塊每 tick
route_cruisenumber遷徙時其遷徙群的巡航速度,否則為 0
speciestable寵物檔案中的數字,如下

c.pet.species 包含:

欄位寵物檔案的鍵
idspecies
speedfollow.speed
hover_heightfloat.hoverHeight
hover_variancefloat.hoverVariance
roam_radiusfollow.roamRadius
follow_distancefollow.distance
leash_distancefollow.leashDistance
teleport_distancefollow.teleportDistance
scalescale
baby_scalebabyScale

移動​

只能在行為的 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/nilradius 之內、位於它懸浮區間的一個點
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/nilradius(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
migrate110
stay54
follow_owner104
campfire1510
day_perch1810
rain_bloom19104(膨脹)
drift、wander、swim2010
hover304
idle_look3010
night_glow40
sting4(玩家)、10(生物)
crop_drizzle20
owner_effect20

規則​

  • 只能在行為的 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。