Companion Dogs: Sổ tay modding
Cách tự dựng add-on của riêng bạn: một giống mới, hoặc cả một loài mới, dưới dạng mod Workshop riêng cắm vào Companion Dogs.
Sổ tay này dành cho người viết mod. Nếu bạn chỉ muốn chơi, hãy đọc hai sổ tay còn lại: Tính năng nói con chó làm được gì, và Giống chó nói về các giống.
Sổ tay giả định bạn đọc được Lua và đã có sẵn model có rig, có animation cho con vật của mình. Quy trình làm art không nằm ở đây. Mục 2 liệt kê những gì file model phải đáp ứng.
Mọi thứ được nêu tên trong sổ tay này là hợp đồng công khai và được làm ra để gọi từ ngoài mod. Thứ không nêu ở đây là nội bộ và có thể đổi ở bất kỳ bản phát hành nào mà không báo trước.
1. Add-on là gì
Add-on là một mod Workshop bình thường, khai báo require=CompanionDogs và gọi một hàm lúc nạp. Nó thêm một giống (hoặc vài giống, nếu chúng dùng chung thân) và không gì khác.
Mod nền giữ:
- máy trạng thái animation, bộ animation và bộ xương
- bám theo, tìm đường, chiến đấu, đi săn, chăn gia súc, canh gác, nhu cầu và chăm sóc
- toàn bộ giao diện: cửa sổ chó, vòng lệnh, menu chuột phải, chuồng, dấu trên bản đồ
- thuần hóa, gắn bó, sinh sản, chó con và chó lai
- các tùy chọn sandbox, và việc đồng bộ nhiều người chơi
Add-on của bạn giữ:
- các con số làm con vật của bạn khác con Chó cỏ
- model thân, texture, ảnh chân dung và, nếu có, icon moodle của nó
- nơi nó xuất hiện trong thế giới
- tên và mô tả của nó, ở mọi ngôn ngữ bạn phát hành
Hai màu lông hành xử y hệt nhau vẫn là hai giống đối với mod nền (hai cái tên, hai mục trong chuồng); bạn viết chúng từ một bảng dùng chung, như CD: Cats làm với năm bộ lông của nó.
2. Cần gì trước khi bắt đầu
Con vật của bạn cần file .glb skinned riêng đặt dưới media/models_X/Skinned/, với đủ bộ 21 clip animation Rac_*. Clip không kế thừa giữa các file model: model chỉ có mười lăm clip cho bạn một con vật đứng đơ ngay lần đầu bị đòi một trong sáu clip còn lại. Model cũng phải dưới 60 xương và có node trên cùng ở identity, nếu không engine ném lỗi mỗi khung hình và con vật hiện lên như một vệt đen. Có thêm hai clip tùy chọn, Rac_WalkLimpFront và Rac_WalkLimpBack (chu kỳ đi khập khiễng); chúng chỉ có tác dụng nếu bạn đặt limpAnim = true trong định nghĩa giống.
Nếu chưa có model, bạn vẫn viết và thử được mọi thứ còn lại bằng cách trỏ CD.applyDogModel vào một thân có sẵn của mod nền. Con vật trông như con Chó cỏ, nhưng mọi hệ thống trong sổ tay này đều chạy.
Bạn cũng cần một texture cho thân và một ảnh chân dung cho cửa sổ chuồng.
Hãy quyết định con vật của bạn là một giống hay một loài trước khi viết dòng code nào. Giống là con chó với các con số khác. Loài là con vật thiếu hẳn vài phần việc. Lựa chọn đó đổi các trường bạn phải viết; mục 6 nói về nó.
3. Các file của một add-on
Đây là CD: Pug, add-on nhỏ nhất đã xuất bản, với những phần đáng kể:
CompanionDogsPug/
42/
mod.info
icon.png
poster.png
media/
models_X/Skinned/Pug_Body.glb
scripts/models_pug.txt
textures/Body/Pug.png
textures/CDPortrait_pug.png
lua/shared/CompanionDogsPug_Breed.lua
lua/shared/Definitions/animal/PugDefinitions.lua
lua/shared/Definitions/animal/CompanionDogsPug_Parts.lua
lua/client/CompanionDogsPug_Moodle.lua
lua/shared/Translate/EN/IG_UI.json
lua/shared/Translate/PTBR/IG_UI.json
common/
Và mod.info:
id=CompanionDogsPug
name=CD: Pug
description=Pugs for Companion Dogs. REQUIRES the Companion Dogs mod (0.6.8 or newer).
poster=poster.png
icon=icon.png
require=CompanionDogs
modversion=0.1.0
pzversion=42.19.0
versionMin=42.18.0
require=CompanionDogs là dòng quan trọng. Nó bảo đảm toàn bộ Lua của mod nền chạy xong trước mọi file của bạn, ở mọi pha: shared trước, rồi client, rồi server. Thiếu nó, file của bạn có thể nạp trước và mọi lời gọi CD. đều là nil index.
versionMin không diễn đạt được ý "cần Companion Dogs 0.6.8". Trường đó chỉ chặn theo bản dựng của game, và mod.info không có trường nào cho phiên bản của mod phụ thuộc. Mức sàn của mod nền do chốt chặn ở mục sau lo, và được báo cho người chơi trong phần mô tả. Hãy viết rõ ở đó, bằng lời, nếu không thì triệu chứng duy nhất người chơi nhận được là con vật không bao giờ xuất hiện.
4. Chốt chặn phiên bản
Đặt đoạn này ở đầu mọi file Lua của add-on, với con số mà add-on của bạn cần:
local CD = CompanionDogs
if not (CD and CD.registerBreed and (CD.API_VERSION or 0) >= 3) then return end
Khi mod nền vắng mặt hoặc quá cũ, file trả về ngay ở dòng hai và add-on không làm gì: không giống, không spawn, không moodle, không một dòng log.
Chốt chặn đặt theo từng file, và mỗi file chặn theo thứ nó dùng. PugDefinitions.lua cần các helper model, nên nó chặn theo chúng:
if not (CompanionDogs and CompanionDogs.applyDogModel and CompanionDogs.DOG_SOUNDS) then return end
Đừng tạo biến toàn cục. CompanionDogs = CompanionDogs or {} trong add-on biến một mod nền vắng mặt thành cái bảng dựng dở, và mọi chốt chặn phía sau đều lọt trong khi lẽ ra phải chặn.
5. Đăng ký giống
Một lời gọi, trong một file shared:
CD.registerBreed({
key = "pug",
engineBreed = "pug",
typePrefix = "pug",
nameKey = "IGUI_PD_Breed_pug",
litter = { 1, 2 },
xpMult = { scent = 1.5, combat = 1, obedience = 2.0, hunt = 1.2, herding = 1.0 },
combatPower = 0.15,
lethalityCurve = { min = 0.40, max = 1.3 },
canKill = false,
canKnockdown = false,
combatStressMult = 0.9,
panicThreshold = 0.70,
bagMult = 0.6,
sentinelMult = 1.35,
barkNoiseMult = 1.5,
alertModeLocked = true,
loyaltyDecayMult = 0,
geneRange = {
strength = { 0.00, 0.10 },
aggressiveness = { 0.05, 0.20 },
resistance = { 0.00, 0.15 },
stress = { 0.55, 0.85 },
},
spawns = {
{ id = "pughouse", class = "house", suffix = "|pg", breed = "pug",
chance = function() return CD.strayChancePerHouse() / CD.PUG_HOUSE_RARITY end },
},
})
Lời gọi này chèn giống vào, đăng ký ba loại con vật của nó, dựng lại thứ tự sinh sản để con vật của bạn tham gia lai giống, và đăng ký các bước spawn.
Định nghĩa sai làm lời gọi trả về nil thay vì ném lỗi, nên việc nạp vẫn chạy tiếp. Mỗi lần bị từ chối đều in một dòng log có nêu tên.
Trường bắt buộc
| Trường | Nó là gì |
|---|---|
key |
định danh giống của bạn, duy nhất trên mọi mod. Đừng đổi sau khi phát hành. |
typePrefix |
tiền tố của ba loại con vật: <prefix>pup, <prefix>female, <prefix>male. Nó chọn mesh thân. |
nameKey |
khóa dịch của tên hiển thị. |
xpMult |
tốc độ học theo từng kỹ năng: scent, combat, obedience, hunt, herding. 1.0 là bình thường. |
combatPower |
nó đánh mạnh cỡ nào. Con Chó cỏ là 0.20, giống chuyên đánh nhau thì trên 1.0. |
lethalityCurve |
{ min, max }, sát thương lớn dần ra sao từ Chiến đấu 0 tới Chiến đấu 10. |
geneRange |
khoảng lúc sinh của bốn gene: strength, aggressiveness, resistance, stress. Mỗi cái là { low, high } nằm trong 0 tới 1. |
Trường tùy chọn
| Trường | Mặc định | Nó làm gì |
|---|---|---|
engineBreed |
chính key |
tên giống đưa cho engine. Nó chọn texture. Duy nhất theo từng giống. |
descKey |
IGUI_PD_BreedDesc_<key> |
khóa mô tả. Nhiều giống dùng chung được một khóa. |
litter |
giá trị nền | { min, max } chó con mỗi lứa. |
canKill |
true | false nghĩa là nó bào mòn zombie nhưng không bao giờ ra đòn kết liễu. |
canKnockdown |
false | true cho phép nó quật ngã zombie. |
combatStressMult |
1 | một trận đánh tốn của nó bao nhiêu căng thẳng. |
panicThreshold |
giá trị nền | mức căng thẳng khiến nó ngừng đánh. panicImmune = true nghĩa là nó không bao giờ ngừng. |
bagMult |
1 | hệ số sức chứa của túi yên. |
puppySize |
0.6 | tỉ lệ hình ảnh tuyệt đối của chó con. Giống nhỏ buộc phải đặt, nếu không chó con sinh ra to bằng con trưởng thành. |
sentinelMult |
1 | nhân vào bán kính canh gác cuối cùng. |
barkNoiseMult |
1 | co giãn bán kính và âm lượng của tiếng sủa báo động. Khi tùy chọn tiếng ồn trong sandbox tắt, không giống nào kéo zombie bằng tiếng sủa, giá trị bao nhiêu cũng vậy. |
loyaltyDecayMult |
1 | nhân vào mức hao trung thành mỗi ngày. 0 nghĩa là mối gắn bó không bao giờ phai. |
alertModeLocked |
false | con vật luôn ở mức cảnh giác cao nhất: chủ không đặt được chế độ Nhẹ tiếng hay Im lặng ở bất cứ đâu. |
huntFetchLevel |
6 | mức Săn mồi từ đó nó tha con mồi về cho chủ. |
huntDeliverTimeoutMin |
5 | số phút trong game nó còn cố mang về trước khi bỏ cuộc. |
distract |
tắt | { <kind> = { chance = 0..1, ... } }. Giống này tự chạy theo thứ nó thấy, không cần chế độ nào và không đòi cấp nào. |
idleAnimMs |
giá trị nền | độ dài cửa sổ animation đứng yên, tính bằng mili giây. Đặt nó khi clip của bạn ngắn hơn clip chó, nếu không vòng lặp khởi động lại và cắt ngang động tác. |
restAnim |
true | false giữ con vật đứng khi Đứng yên và Canh gác thay vì nằm xuống. |
restPoses |
nằm xuống | một danh sách tư thế nghỉ mà con vật rút ra mỗi lần nó nằm yên, với các chuyển tiếp và biến thể đứng yên tùy chọn. Cần clip và node animation của riêng bạn. |
limpAnim |
false | true làm con vật bị thương đi khập khiễng. Chỉ đặt khi model của bạn có hai clip tùy chọn Rac_WalkLimpFront và Rac_WalkLimpBack (chu kỳ đi 1.0 giây, cùng root motion với Rac_Walk). Thiếu clip thì con vật vừa đi vừa đứng đơ tại chỗ. |
bandSkin |
tắt | { base, front, back, cutFront, cutBack }, năm tên texture thân. Ở chân bị thương, con vật mang biến thể có vết cắt khi vết thương đang chảy máu và biến thể băng bó khi đã được băng. Tạo bốn biến thể bằng _dogrig/forge/_paw_band.py. Không có trường này thì con vật vẫn bị thương như thường, chỉ là không hiện dấu vết. |
voices |
âm thanh chó | { bark, growl, idle, wildbark, pet, whine, eat, drink }. |
diet |
các danh sách của chó | con vật không được ăn gì, thứ gì tính là thịt với nó, và nó tự ăn gì từ máng. |
maleChance |
0.5 | tỷ lệ sinh ra là đực, từ 0 đến 1. |
sterileMale |
false | true giữ con đực của giống đó ngoài việc sinh sản. |
species |
"dog" |
sinh sản khép kín theo loài. Mục 6. |
skills, canBreed, huntMaxPrey |
bật hết | các khối cấu trúc. Mục 6. |
Con số và cờ bạn thêm vào định nghĩa được đọc lại bằng CD.breedNumber(animal, field) và CD.breedFlag(animal, field), không phải bằng CD.getBreedDef(animal).field. Hai hàm đó xử lý được trường thiếu và vẫn chạy khi mod nền đổi.
Bản năng: distract
distract = {
prey = { chance = 0.25 },
},
Giống nào khai báo nó thì thỉnh thoảng sẽ để ý thấy thứ gì đó và chạy theo, bỏ dở việc đang làm. Nó làm vậy cả khi đang Đứng yên lẫn khi đang Đi theo. Trong lúc đó, mệnh lệnh bị trả về từ chối kèm thông báo distracted mà lượt tung vâng lời vẫn dùng. Lại đây là lệnh duy nhất lọt qua, và nó hủy cơn phân tâm.
Mọi loại đều nhận cùng bộ núm tùy chọn. Thứ bạn bỏ trống sẽ lấy mặc định của mod:
| Trường | Nó làm gì |
|---|---|
chance |
0..1, chỉ tung khi bộ kích hoạt của loại đó tìm được thứ gì. Viết 25 với ý "25%" sẽ bị từ chối kèm một dòng log có nêu tên |
radius |
số ô mà bộ kích hoạt quét, với loại nào có quét |
durationMin |
số phút trong game cửa sổ này kéo dài trước khi tự hết hạn |
cooldownMin |
số phút trong game trước khi cùng con vật đó phân tâm lại được |
Loại prey
Loại duy nhất mod nền phát hành. Con vật chạy theo thú hoang, và classes chọn con nào được tính:
distract = {
prey = { chance = 0.25, radius = 6, classes = { tiny = true, small = true } },
},
Hai giới hạn luôn áp dụng, bạn khai báo gì cũng vậy:
- Nó không bao giờ vượt
huntMaxPreycủa bạn: giống bị chặn ởsmallsẽ không đuổi hươu dù có khailarge. - Chốt chặn theo cấp chỉ bỏ qua với
tiny. Con vật vừa thuần hóa, Săn mồi 0, đã bắt được chuột. Khaismallthì giống đó đuổi thỏ ở mọi cấp, nhưng để hạ được vẫn cần đúng mức Săn mồi mà con Labrador cần.
Công tắc Săn mồi trong sandbox chỉ tác động tới cú hạ: con vật vẫn đuổi, nhưng con mồi chạy thoát.
Con mồi hạ theo cách này đi qua quy trình tha về bình thường, nên huntFetchLevel của giống quyết định nó có mang xác về cho chủ hay không. Ở 0 con vật giao từ ngày đầu, đó là cách con mèo mang cho bạn một con chuột chết. Việc giao sống lâu hơn cửa sổ phân tâm: khi con mồi đã chết, con vật nhận lệnh trở lại, và chặng về chạy theo huntDeliverTimeoutMin của chính nó.
Tự viết một loại
distract là một bộ điều phối. Hãy đăng ký loại của riêng bạn:
CD.registerDistraction("butterfly", {
gate = function(animal, cfg) return animal:isOutside() end, -- optional, cheap pre-check
find = function(animal, cfg) return findButterflyNear(animal, cfg.radius) end,
drive = function(animal, owner, d, cfg) return chaseIt(animal, d) end,
stop = function(animal, d) end, -- optional, cleanup
})
Rồi khai báo nó trên giống như mọi loại khác: distract = { butterfly = { chance = 0.10 } }.
gate chạy trước hạn mức quét toàn cục của mod. find chạy sau hạn mức đó và làm phần tìm kiếm tốn kém. drive trả về true khi nó còn đang điều khiển con vật và false khi xong, và điều đó đóng cửa sổ lại. Handler của bạn chạy trong pcall riêng. Nếu nó ném lỗi, mod ghi một dòng log có nêu tên, gỡ đăng ký loại đó cho cả phiên và để phần còn lại của con đồng hành chạy bình thường.
Các tên dành sẵn cho loại của mod nền sau này: drink, eat, play. Hôm nay bạn vẫn đăng ký được một loại dưới các tên đó, nhưng mod nền sẽ lấy lại tên khi nó phát hành loại của mình.
Tư thế nghỉ
Con vật đang nghỉ thì nằm xuống. restPoses thay tư thế duy nhất đó bằng một danh sách mà con vật rút ra mỗi lần nó nằm yên:
restPoses = {
"cdRest", -- the base lie-down
{ var = "cdSit", enter = "cdSitIn", exit = "cdSitOut",
variation = { "cdSitGroom", "cdSitGroom2" } },
},
Mỗi mục là tên một biến animation hoặc một bảng. var là boolean bật suốt cả quãng nghỉ. enter và exit là các xung phát một lần, khi con vật nằm yên và khi nó đứng dậy. variation là danh sách các xung phát một lần mà nó thỉnh thoảng phát trong lúc giữ tư thế, theo cùng đồng hồ với biến thể đứng yên. Chỉ var là bắt buộc.
Việc rút là đồng đều và xảy ra ở mỗi lần vào nghỉ, nên hai mục nghĩa là 50% mỗi mục và con vật có thể rút trúng cùng một mục hai lần liên tiếp. Nó không phải luân phiên.
Mỗi xung kéo dài đúng bằng những gì idleAnimMs nói cho biến đó, nên hãy truyền dạng bảng và cho mọi biến một độ dài, kể cả các biến đứng yên bạn đã có. Hãy ghi độ dài thật của clip.
idleAnimMs = { cdIdle2 = 3800, cdIdle3 = 3800, cdSitIn = 1375, cdSitOut = 1417,
cdSitGroom = 19833, cdSitGroom2 = 25167 },
Clip và node là của bạn, không phải của mod nền. Mỗi biến cần một file node trong add-on của bạn dưới media/AnimSets/raccoon/idle/, và clip mà m_AnimName của nó trỏ tới phải có trong model của bạn. Một node trỏ tới clip mà model không có sẽ thất bại trong im lặng và con vật chỉ đứng yên ở tư thế đứng yên của mod nền. Cho node tư thế một m_ConditionPriority là 10 như của mod nền, và một số cao hơn cho bất kỳ thứ gì phải phát đè lên nó: 11 cho một biến thể, 12 cho hai chuyển tiếp. Một node phát clip theo vòng lặp trừ khi bạn nói khác đi, nên mọi node được định phát một lần, cả hai chuyển tiếp lẫn mọi biến thể, đều cần <m_Looped>false</m_Looped>. Không có nó, clip khởi động lại ngay khi kết thúc và con vật giật ngược lại thấy rõ rồi làm lại lần nữa, vì biến chỉ tắt ở tick tiếp theo của server. Chỉ để chúng trong idle/. Một node tư thế trong pathfind/ phát clip không có root motion và đóng băng con vật ngay tại chỗ.
Giọng
Không có voices thì mọi giống dùng âm thanh chó, nên con mèo sẽ sủa. Trước hết hãy đăng ký âm thanh của bạn:
CD.registerVoices({
CDCatMeow = "bark", CDCatGrowl = "bark", CDCatHiss = "bark", CDCatPurr = "bark",
CDCatPet = "fx", CDCatMeowAmbient = "ambient",
})
Rồi trỏ giống vào chúng:
voices = { bark = "CDCatMeow", growl = "CDCatGrowl", idle = "CDCatPurr",
wildbark = "CDCatMeowAmbient", pet = "CDCatPet", whine = "CDCatHiss" },
Không có CD.registerVoices thì âm thanh vẫn phát, nhưng chúng phớt lờ thanh trượt theo hạng mục của người chơi và âm lượng hiệu ứng của game, và không dòng log nào chỉ ra chuyện đó. Khóa bạn bỏ trống trong voices sẽ lùi về âm thanh chó.
whine là tiếng con vật kêu khi bị thương hay đổ bệnh. eat và drink là tiếng ăn và uống. Tiếng của chó là vòng lặp mà bản gốc dừng khi con vật ăn xong; nếu của bạn cũng là vòng lặp, hãy thêm chúng vào CD.SOUND_LOOPED để bản gốc cũng dừng chúng khi người nghe đi ra khỏi tầm. Bản gốc cũ hơn API 11 bỏ qua ba khóa này và phát âm thanh chó.
Tham số thứ ba là tầm nghe của từng âm thanh, tính bằng ô. Nó nên khớp với distanceMax bạn viết trong script âm thanh của chính mình:
CD.registerVoices(map, nil, { CDCatMeow = 22, CDCatGrowl = 10 })
Trên server, mod nền chỉ gửi âm thanh tới những người chơi nằm trong tầm đó. Bỏ trống tầm thì giọng nhận một tầm chung theo hạng mục: tiếng rít vang xa mười ô sẽ tới tai mọi người trong ba mươi ô. Quá distanceMax, đường suy giảm nghịch đảo của FMOD ngừng làm nhỏ tiếng thay vì tắt hẳn, nên một file .ogg khai lỏng cứ phát mãi ở mức distanceMin / distanceMax âm lượng của nó, ở khoảng cách nào cũng vậy. Cũng vì lý do đó, hãy để distanceMin nhỏ ở những giọng to.
Khẩu phần
Không có diet thì mọi giống ăn như chó: cùng những món gây độc, cùng những món tính là thịt, và cùng những món nó gặm từ máng ăn. Trường này ghi đè ba danh sách đó, chỉ cho giống của bạn.
diet = {
bad = { Fruits = true }, -- fruit now makes it sick
badParts = { onion = false }, -- onion no longer does
protein = { Cheese = true }, -- cheese now counts as meat
proteinParts = { tuna = true }, -- and so does anything with "tuna" in its type
trough = { Vegetables = false }, -- it will not graze vegetables
troughItems = { ["Base.CatFoodOpen"] = true },
},
Có hai dạng vì hạng mục sẵn có của game chỉ đi được tới đó. Cheese là một FoodType thật, nên một khóa phủ mọi loại phô mai trong game và trong bất kỳ mod đồ ăn nào dùng lại hạng mục đó. Cá ngừ thì không: hộp đã mở là FoodType = Fish, chung với mọi loài cá khác, còn hộp chưa mở không khai loại đồ ăn nào cả. badParts và proteinParts là cách bạn với tới những thứ đó.
Mỗi trường là một bảng gồm <key> = true (thêm) hoặc <key> = false (bỏ thứ mod nền có sẵn). Giá trị không phải true hay false bị loại kèm một dòng log có nêu tên.
| Trường | Khóa của nó là gì |
|---|---|
bad |
FoodType của món làm con vật ốm, làm nó mất trung thành và hiện mục màu đỏ trong menu cho ăn |
badParts |
một mẩu của item type, viết thường, khớp ở bất cứ chỗ nào trong đó |
protein |
FoodType trả được món nợ thịt của con vật, món nợ mà moodle Yếu theo dõi |
proteinParts |
một mẩu của item type, khớp giống như badParts |
nonProtein |
FoodType mà bạn biết chắc không phải thịt. Nó chỉ dập dòng log mà mod nền ghi cho một loại đồ ăn nó chưa từng thấy |
trough |
FoodType và AnimalFeedType mà con vật tự ăn từ máng |
troughItems |
item type đầy đủ, cho món nằm trong máng mà không có loại thức ăn riêng |
replace = true bắt đầu từ danh sách rỗng thay vì danh sách của chó. Dùng nó khi con vật của bạn gần như không chung gì với chó; con mèo thường dễ viết hơn dưới dạng một nhúm dòng thêm và bớt.
Ba danh sách này đi theo con vật, nên con chó và con mèo đứng cùng một máng ăn hai thứ khác nhau. Cái bát của chính mod là ngoại lệ: nó lưu điểm thức ăn chứ không lưu món đã đổ vào, nên việc đổ đầy đi theo danh sách nền cho tất cả. Dù sao cũng không bỏ được thứ gây độc vào bát.
Giới tính khi sinh
Mỗi con vật được bốc đực hay cái khi xuất hiện, năm mươi năm mươi. maleChance là tỷ lệ sinh ra là đực, từ 0 đến 1, còn sterileMale giữ con đực của giống đó ngoài việc sinh sản.
maleChance = 0.00033,
sterileMale = true,
Cặp đó chính là mèo tam thể. Mảng màu cam và đen nằm trên nhiễm sắc thể X, nên mèo tam thể gần như luôn là cái, và con đực thi thoảng xuất hiện là XXY, khoảng một trên ba nghìn, và không thể có con. Con đực của giống đặt sterileMale không bao giờ được chọn làm bạn tình, và tùy chọn phối giống biến mất khỏi menu chuột phải của nó. Con cái sinh sản bình thường.
Con đực của giống như vậy mang nhãn "Vô sinh" ở mọi nơi trò chơi hiển thị giới tính của nó: bảng thông tin, menu chuột phải, lượt quét thú hoang và cũi, để người chơi biết vì sao nó không sinh sản.
Cả hai trường đều được đọc từ định nghĩa của giống, nên không có gì được ghi lên con vật và file lưu cũ không cần chuyển đổi. Cùng lượt bốc đó quyết định giới tính của con non khi chào đời, nên giống nào là cái ngoài thế giới thì trong lứa đẻ vẫn là cái.
6. Tắt hẳn một hệ thống
Năm kỹ năng chính là năm hệ thống:
| Kỹ năng | Là hệ thống nào |
|---|---|
scent |
lính gác: phát hiện zombie và báo cho bạn |
combat |
đánh nhau, chế độ Canh gác và tự vệ |
obedience |
cây trò |
hunt |
săn mồi, cộng với phần thưởng kiếm đồ mà nó cho chủ |
herding |
trông đàn vật nuôi trong chuồng |
Vậy nên một loài khai báo cái nó không có:
skills = { combat = false, herding = false },
canBreed = false,
huntMaxPrey = "tiny",
Không có mặt hoặc true nghĩa là con vật có kỹ năng đó.
Tắt một kỹ năng cũng khiến nó thôi nhận kinh nghiệm, và gỡ thanh của nó cùng các lệnh của nó khỏi giao diện.
canBreed = false tách khỏi bảng vì việc sinh sản không có thanh và không có kinh nghiệm. Con vật không thụ thai, không bao giờ được chọn làm bạn tình, và cũng không sinh sản với chính loài của nó.
Loài
Một addon thêm vào một con vật khác, thay vì thêm một con chó nữa, thì khai báo như sau:
CD.registerSpecies({ key = "cat",
nounKey = "IGUI_PD_SpeciesNoun_cat",
youngKey = "IGUI_PD_Young_cat" })
CD.registerBreed({ ..., species = "cat" })
Trường này vắng mặt ở mọi giống đã phát hành cho tới giờ, và vắng mặt nghĩa là "dog".
Việc sinh sản đóng theo loài: một cặp chỉ thụ thai khi cả hai bên cùng một loài, trong lệnh, trong lần gieo thụ động mỗi giờ và trong công cụ debug. Và giao diện thôi gọi con vật của bạn là chó: nounKey là danh từ trần lấp vào những câu như "%1 này đã thuộc về một người sống sót khác", còn youngKey là nhãn mà con non của loài bạn mang trong cửa sổ, menu chuột phải và cũi, chỗ mà một con chó ghi Chó con.
Hai danh từ đó chỉ phủ những câu dựng quanh một %1. Mọi câu khác có chữ chó viết thẳng vào trong đó ("Kiểm tra con chó", "Con chó của bạn đang đói", "Con chó sủa có chủ đích") từ API 7 trở đi lấy một khóa theo loài: hãy kèm IGUI_PD_ScanStray_cat trong các file dịch của bạn và bản gốc sẽ hiện nó thay cho IGUI_PD_ScanStray mỗi khi con vật trên màn hình là mèo. Một khóa bạn không kèm theo sẽ lùi về văn bản của chó. Các khóa nhận hậu tố: ScanStray, ScanTitle, PauseGrowthTip, BadFood, AlertFullDesc, AlertQuietDesc, AlertLockedTip, HuntModeDesc, mọi Trick*Desc, TrickDistractDone, TrickNeedsBag, TrickGotoPick, TrickSniffNoItem, TrickFetchNoItem, AlertGroup, DogLost, mọi Refused_*, KennelStatusNoData và các Moodle_*_desc của những moodle chăm sóc (Sick, Weak, Hunger, Thirst, Rested, Grief). Những câu không có con vật nào trên màn hình (thẻ danh sách, "Hãy làm quen với một con vật trước") thì trong bản gốc đã trung tính về loài rồi. Con mèo kèm đủ tất cả bằng mười bốn thứ tiếng; hãy chép IG_UI.json của nó làm mẫu.
group của con vật chỉ được menu spawn của chế độ debug và trình xem clip đọc tới, qua IGUI_Animal_Group_<group>. Hãy đặt t.group = "cat" sau hàm trợ giúp hành vi và kèm khóa đó, nếu không loài của bạn sẽ hiện ở đó dưới tên của chó.
Khai báo species mà không đăng ký nó thì không chết người: con vật của bạn vẫn từ chối sinh sản ngoài loài của nó, vì cửa chặn so sánh chuỗi thô. Chỉ hai danh từ lùi về của chó, và log nói rõ điều đó kèm tên.
Trên một bản gốc cũ hơn API 6, trường này bị bỏ qua mà không có dòng log nào, và con vật của bạn sinh sản như một con chó. Nếu nó tuyệt đối không được lai với chó, hãy chặn ở API 6, hoặc giữ canBreed = false khi bản gốc còn cũ, đó là điều con mèo làm.
huntMaxPrey giới hạn cỡ con mồi bên trong một cuộc săn vẫn còn tồn tại; nó không thay cho hunt = false. Nó nhận "tiny" (chuột nhắt, chuột cống, sóc), "small" (thỏ, gấu mèo) hoặc "large" (hươu, mặc định, không giới hạn). Con vật của bạn không đuổi và không chỉ hướng vào con mồi lớn hơn mức giới hạn. Một giá trị nằm ngoài thang đó sẽ lùi về "large" và in một dòng có tên vào log.
Một tùy chọn bị chặn sẽ biến khỏi vòng tròn, menu chuột phải và cửa sổ, còn server từ chối nó mà không báo gì. Không trường nào trong số này thêm một khóa dịch, nên hãy giải thích các giới hạn trong phần mô tả giống của bạn.
7. Định nghĩa con vật
Engine gắn mesh vào type con vật chứ không phải vào giống, nên giống của bạn cần ba type của riêng nó. Đường ngắn nhất là chép file của một addon đã có rồi đổi tên.
Ba phần, trong một file shared dưới Definitions/animal/:
AnimalDefinitions.stages["pug"] = {}
AnimalDefinitions.stages["pug"].stages = {}
AnimalDefinitions.stages["pug"].stages["pugpup"] = {}
AnimalDefinitions.stages["pug"].stages["pugpup"].ageToGrow = 3 * 30
AnimalDefinitions.stages["pug"].stages["pugpup"].nextStage = "pugfemale"
AnimalDefinitions.stages["pug"].stages["pugpup"].nextStageMale = "pugmale"
AnimalDefinitions.breeds["pug"].breeds["pug"].texture = "Pug"
AnimalDefinitions.breeds["pug"].breeds["pug"].textureMale = "Pug"
AnimalDefinitions.breeds["pug"].breeds["pug"].rottenTexture = "Raccoon_Rotting"
AnimalDefinitions.breeds["pug"].breeds["pug"].invIconMale = "CDDogPaw_64"
AnimalDefinitions.breeds["pug"].breeds["pug"].invIconMaleDead = "CDDogPawDead_64"
local pugfemale = {}
CD.applyDogModel(pugfemale, "Pug_Body")
CD.applyDogBehaviour(pugfemale)
pugfemale.female = true
pugfemale.babyType = "pugpup"
pugfemale.minSize = 1.5
pugfemale.maxSize = 2.0
pugfemale.minWeight = 5
pugfemale.maxWeight = 8
pugfemale.wildFleeTimeUntilDeadTimer = CD.STRAY_NO_BLEEDOUT
pugfemale.breeds = AnimalDefinitions.breeds["pug"].breeds
pugfemale.stages = AnimalDefinitions.stages["pug"].stages
pugfemale.genes = AnimalDefinitions.genome["dog"].genes
AnimalDefinitions.animals["pugfemale"] = pugfemale
Các hàm trợ giúp mà bản gốc cho bạn:
| Hàm trợ giúp | Điền vào những gì |
|---|---|
CD.applyCompanionModel(t, "Body_Model") |
model thân, bộ xương, texture lúc mổ và bộ animation |
CD.applyCompanionBehaviour(t) |
mọi cờ hành vi của engine mà một con vật đồng hành cần |
CD.applyCompanionAvatar(t) |
camera chân dung cho cửa sổ con vật |
CD.COMPANION_SOUNDS |
bảng tiếng chân và tiếng động dùng chung |
CD.defineGenome("species") |
bộ gen của một loài mới, với danh sách gen chuẩn (API 7) |
CD.STRAY_NO_BLEEDOUT |
giá trị ngăn một con hoang đang sợ chảy máu đến chết |
CD.defineCompanionParts(typePrefix, engineBreed, meat) |
các phần mổ xẻ của cả ba giai đoạn. meat không bắt buộc: { item, minNb, maxNb, pupMinNb, pupMaxNb }, và không có nó thì con vật cho ra thịt chó của bản gốc. Engine nhân cả số lượng lẫn độ no của từng miếng với cỡ xác, nên một loài có cỡ lớn (con mèo dùng 2.5 đến 3.5 làm thang hình ảnh) cần vật phẩm riêng với độ no gốc nhỏ hơn và số lượng thấp |
Các tên trung tính về loài đến cùng API 7. Những tên cũ hơn, CD.applyDogModel, CD.applyDogBehaviour, CD.applyDogAvatar, CD.DOG_SOUNDS, CD.defineDogParts và CD.DogMoodles, chính là những hàm và bảng đó dưới cái tên đầu tiên của chúng. Một addon muốn nạp được trên bản gốc cũ hơn 0.7.3 thì chặn ở tên cũ và lấy tên mới khi nó tồn tại: local applyModel = CD.applyCompanionModel or CD.applyDogModel.
Bộ animation phải giữ nguyên là "raccoon". Một bộ animation tách nhánh không nạp máy trạng thái của nó, và con vật đứng đơ tại chỗ.
Hãy dùng lại bộ gen. Một giống chó trỏ vào danh sách của bản gốc: AnimalDefinitions.genome["dog"].genes. Một loài mới gọi CD.defineGenome("cat") một lần và trao cho mọi giai đoạn cái bảng mà nó trả về. Engine chỉ đọc danh sách genes của từng giai đoạn, còn khóa bộ gen chỉ là quy ước, nên loài của bạn có mục riêng mà không cần danh sách gen của riêng nó.
Đừng khai báo mate. Có nó thì engine chạy phần giao phối gốc của chính nó bên trong bất kỳ vùng động vật nào, phần đó bỏ qua khối sinh sản của mod và các tùy chọn sandbox của mod, và cho ra chó con không có mối gắn bó. Bản gốc xóa trường này lúc khởi động, nhưng đừng dựa vào đó.
Các phần mổ xẻ là bắt buộc. Ba dòng trong file của riêng chúng:
if CompanionDogs and CompanionDogs.defineDogParts then
CompanionDogs.defineDogParts("pug", "pug")
end
Thiếu chúng, việc mổ con vật của bạn làm sập code gốc của game, vì nó tra định nghĩa phần mổ theo type và giống rồi đụng phải nil.
Mức phóng chân dung trong CD.applyDogAvatar được canh cho một con chó, và mức phóng của avatar là độ phóng đại: con vật càng nhỏ thì con số càng lớn. Hãy chia mức phóng cho tỉ lệ cỡ so với chó và nhân các offset với tỉ lệ đó, nếu không con vật của bạn sẽ ngồi bé xíu ở đáy bức chân dung của chính nó.
8. Script của model
Một file dưới media/scripts/ báo cho game biết model của bạn tồn tại:
module Base
{
model Pug_Body
{
mesh = Skinned/Pug_Body,
shader = animalEffect,
static = false,
animationsMesh = PugAnim,
attachment head
{
offset = -0.0061 0.1671 0.0507,
rotate = -179.0 -5.0 95.0,
bone = Dummy01,
}
}
animationsMesh PugAnim
{
meshFile = Skinned/Pug_Body,
keepMeshAnimations = true,
}
}
keepMeshAnimations = true giữ cho các clip nằm trong file model của bạn còn dùng được. Không có nó, model nạp lên và không bao giờ chạy animation.
Điểm gắn head là chỗ mũ nón và những thứ tương tự ngồi lên. Nếu bạn muốn túi yên vừa với con vật của mình, hãy thêm saddlebags_l, saddlebags_r và saddlebags_c y như vậy, trên xương sống. Tìm những con số đó bằng cách nhìn con vật trong game và nhích dần. Giá trị đo từ model đặt cái túi vào tâm hình học của mesh, và đó không phải chỗ trông hợp mắt trên thân con vật.
9. Con vật xuất hiện ở đâu
Chó hoang được gieo theo từng tòa nhà, từng chunk, vào lần đầu chunk đó nạp. Bạn mô tả các lần gieo của mình bằng một danh sách các bước, hoặc đặt trong định nghĩa giống dưới tên spawns, hoặc dùng CD.registerStraySpawns(list).
spawns = {
{ id = "pughouse", class = "house", suffix = "|pg", breed = "pug", indoor = 85,
chance = function() return CD.strayChancePerHouse() / CD.PUG_HOUSE_RARITY end },
{ id = "pugpetvet", class = "petvet", suffix = "|pv", breed = "pug",
chance = function() return CD.PUG_PETVET_CHANCE * CD.dogSpawnMultiplier() end },
},
| Khóa | Là gì |
|---|---|
id |
tên của bước, dùng cho log của chính bạn |
class |
lớp tòa nhà mà bước này gieo trên đó |
chance |
một hàm trả về phần trăm, nhờ vậy nó đọc được hệ số sandbox ngay lúc gieo. |
suffix |
khóa của kho lưu lâu dài. Không trùng với bất kỳ mod nào, và không bao giờ đổi. |
breed |
khóa của giống sẽ xuất hiện |
gate |
hàm không bắt buộc, trả về đúng sai, được kiểm trước khi gieo. Husky dùng CD.isWinter. |
indoor |
phần trăm khả năng sinh ra bên trong tòa nhà thay vì ngoài đường. Mặc định 35. |
Hãy nhân tỉ lệ của bạn với CD.dogSpawnMultiplier(), hoặc chia CD.strayChancePerHouse() cho một độ hiếm của riêng bạn. Cả hai cách đều giữ cho thiết lập sandbox của người chơi còn tác dụng.
indoor chỉ là mong muốn: một tòa nhà không còn ô trống bên trong ở chunk đó sẽ lùi về một ô ngoài trời.
Các lớp tòa nhà
Bản gốc đăng ký bốn lớp:
| Lớp | Khớp với |
|---|---|
house |
nhà ở không phải cửa hàng |
police |
đồn cảnh sát và những nơi tương tự |
petvet |
cửa hàng thú cưng và phòng khám thú y |
farm |
công trình nông trại, và được phép nằm ngoài thị trấn |
Nếu không lớp nào hợp, hãy đăng ký lớp của bạn:
CD.registerBuildingClass("mineshaft", function(def) return def:isX() end,
{ skipUrbanGate = true })
Hàm khớp nhận định nghĩa tòa nhà và chạy trong một lời gọi được bảo vệ, nên lỗi trong đó không làm dừng việc nạp chunk. skipUrbanGate cho phép lớp gieo trong một chunk không phải đô thị, điều mà một nông trại hay một căn chòi trong rừng cần đến. Đừng đặt exclusive. Các lớp gốc loại trừ lẫn nhau, còn lớp của addon thì khớp chồng lên chúng.
Những hậu tố đã có người dùng
Hậu tố là một phần của khóa lưu "tòa nhà này đã gieo rồi". Hai mod dùng chung một hậu tố sẽ làm hỏng kết quả gieo của nhau.
Mọi hậu tố đều bắt đầu bằng một dấu gạch đứng. Những cái đang được dùng:
- Bản gốc: hậu tố rỗng, và
g,h,hv,bc,gh,hh,bh - Rottweiler:
rw,r - Doberman:
db,dm,dh - Labrador:
lb,lk - Chó Pug:
pg,pv - Chó Malinois:
ml,mm,mh - Mèo: mọi hậu tố bắt đầu bằng
ct,cvhoặccs(mỗi màu lông một bộ)
10. Moodle của giống
Moodle là một file phía client. Bạn nối một bảng vào CD.DogMoodles, và bản gốc lo vẽ nó, theo dõi nó và dọn nó đi:
CD.DogMoodles[#CD.DogMoodles + 1] = {
id = "shadow",
breed = "pug",
nameKey = "IGUI_PD_Moodle_Shadow",
descKey = "IGUI_PD_Moodle_Shadow_desc",
icon = "CD_Moodle_Shadow",
fg = "CD_MoodShadowFG",
tintR = 0.92, tintG = 0.52, tintB = 0.68,
condition = function(player, dog)
if not dog or dog:isDead() then return 0 end
if CD.getBreed(dog) ~= "pug" then return 0 end
if CD.isDisloyal(dog) then return 0 end
return 1
end,
apply = function(player, dog, elapsedMin)
CD.relieveMood(player, CD.moodleReliefPerMin() * elapsedMin)
end,
}
condition trả về cấp độ, hoặc 0 nghĩa là "không hiện". apply nhận số phút trong game kể từ lần gọi trước, nên hãy nhân hiệu ứng của bạn với elapsedMin.
Hãy kèm icon ở sáu kích cỡ, từ 32 đến 128 pixel. Giao diện chọn kích cỡ theo mức phóng của người chơi, và một kích cỡ thiếu sẽ hiện thành ô vuông rỗng. Icon xuất hiện ở dải riêng của mod, không nằm chung với các moodle gốc của game.
11. Hook
Hai danh sách hàm mà bản gốc gọi trên server. Hãy nối vào chúng từ một file shared. Mỗi handler chạy trong lời gọi được bảo vệ của riêng nó, nên lỗi ở một addon không làm dừng bản gốc.
CD.onHuntDelivered, có từ API 2, được gọi ngay sau khi con vật thả con mồi xuống chân chủ:
CD.onHuntDelivered[#CD.onHuntDelivered + 1] = function(animal, owner)
-- server side, so this is the right place to write mod data
end
CD.onUpkeepStress, có từ API 3, được gọi mỗi chu kỳ chăm sóc, sau khi bản gốc đã cộng phần căng thẳng từ những nhu cầu chưa được đáp ứng và trước khi ghi nó xuống. Hãy trả về một con số, nó sẽ được cộng vào tổng:
CD.onUpkeepStress[#CD.onUpkeepStress + 1] = function(animal, needsStress)
return CD.pugHeatRatio(animal) * CD.PUG_HEAT_STRESS_MAX
end
Chu kỳ chăm sóc tính lại và ghi đè giá trị này mỗi vòng, nên mọi thứ ghi từ bên ngoài đều mất ở tick sau. Hãy dùng hook cho một điều kiện đến từ môi trường, như nóng, lạnh hay mưa.
Trong nhiều người chơi, client không bao giờ ghi mod data. Một lần ghi từ phía client sẽ đè lên bản của server ở lần đồng bộ kế tiếp, và triệu chứng lộ ra sau đó vài phút, ở một chỗ chẳng liên quan. Hãy làm việc đó trong một file phía server, hoặc trong một trong các hook này.
Các con số trong bảng SERVER TUNING là hằng số CD.* bình thường, và một add-on có thể gán một hằng từ file shared hoặc server lúc nạp. Từ API 9, bảng lấy giá trị đang có hiệu lực khi server nạp xong làm mặc định của núm đó: nó giữ nguyên cho tới khi admin gõ đè lên, nút reset quay về nó, và bảng hiện nó như mặc định. Trên mod nền cũ hơn, bảng ghi lại giá trị gốc mỗi lần khởi động. Hãy gán lúc nạp, không phải từ một sự kiện về sau, nếu không lần đổi tiếp theo ở bất kỳ núm nào sẽ đặt lại giá trị gốc.
12. Khóa dịch thuật
Hãy kèm một IG_UI.json cho mỗi thư mục ngôn ngữ, trong media/lua/shared/Translate/<LANG>/. Bản gốc kèm mười bốn: EN, PTBR, CH, CN, DE, ES, FR, IT, JP, KO, RU, TH, UA, VI.
Các khóa mà một giống cần:
| Khóa | Hiện ở đâu |
|---|---|
IGUI_PD_Breed_<key> |
tên giống, ở mọi chỗ trong giao diện của mod |
IGUI_PD_BreedDesc_<key> |
mô tả trên thẻ của con vật |
IGUI_Breed_<engineBreed> |
tên giống trong các màn hình của chính game |
IGUI_AnimalType_<type> |
một khóa cho mỗi type trong ba type của bạn |
| các khóa loài của bạn | nounKey và youngKey bạn đã truyền cho CD.registerSpecies |
| các khóa moodle của bạn | tên và phần mô tả |
{
"IGUI_Breed_pug": "Pug",
"IGUI_AnimalType_pugmale": "Pug (male)",
"IGUI_AnimalType_pugfemale": "Pug (female)",
"IGUI_AnimalType_pugpup": "Pug (puppy)",
"IGUI_PD_Breed_pug": "Pug",
"IGUI_PD_BreedDesc_pug": "The house dog: the first companion whose worth is not fighting."
}
Một dấu phần trăm để trần trong chuỗi đã dịch sẽ làm sập màn hình hiện nó, vì bộ định dạng đọc nó như một chỗ giữ chỗ. Một file ngôn ngữ có byte order mark thì không biên dịch được, và lỗi lại gọi tên một file khác chứ không phải file hỏng.
13. Những gì file save ghi nhớ
Ba trong số các định danh của bạn được ghi vào file save và đọc lại mãi mãi:
key, định danh giống được lưu trên mọi con vật của bạntypePrefix, thứ tạo nên các type con vật mà engine lưu lạisuffix, khóa của kho "đã gieo rồi", mỗi bước xuất hiện một cái
Không cái nào trong ba cái đó đổi tên được sau khi phát hành. Đổi tên key làm mọi con vật còn sống của giống đó thành mồ côi. Đổi tên suffix khiến mọi tòa nhà trong mọi file save hiện có gieo lại, và một thế giới đã chơi hàng tháng sẽ đầy con vật của bạn.
Một hậu tố mới cũng chính là cách một giống mới đến được với những thế giới đang chạy dở. CD: Cats cho bốn màu lông mới của nó những hậu tố mới, nên chúng bắt đầu xuất hiện trong các file save đang có, còn con mèo đen ban đầu vẫn giữ hậu tố cũ và không gieo lại.
Gỡ một addon khỏi file save còn con vật sống của giống đó sẽ mất chúng. Engine bỏ đi một con vật mà nó không còn biết type. Bản gốc không sập, và mối gắn bó lẫn cái cũi đều xuống cấp một cách gọn gàng. Hãy nói rõ điều đó trên trang Workshop của bạn.
Nếu addon của bạn không có mặt, bản gốc lùi về giống mặc định cho mọi thứ nó được hỏi, nên một file save mở ra mà không có mod của bạn vẫn đọc được.
14. Trước khi đăng
- Lớp bảo vệ có mặt trong mọi file Lua, và gọi đúng tên API bạn thật sự dùng.
- Sàn phiên bản của bản gốc được viết trong phần mô tả, bằng chữ.
versionMinkhông nói được điều đó. - Bạn đã đọc log ở lần nạp đầu tiên. Nếu không,
CD.registerBreedtừ chối trong im lặng, mà mỗi lần từ chối đều in ra một dòng có tên. CD.defineDogPartsđã được gọi. Hãy mổ một con vật của bạn và xem nó không sập.key,typePrefixvà các hậu tố xuất hiện của bạn là duy nhất, và bạn sẽ không cần đổi chúng.- Giống nhỏ con thì đặt
puppySize, và bạn đã tận mắt thấy một con chó con để chứng minh. - Nếu là loài khác,
CD.registerVoicesđã được gọi vàvoicesđã điền, có cảwhinetrong đó, không thì nó sẽ sủa và rên ư ử như chó. - Icon moodle có đủ cả sáu kích cỡ.
- Mọi thư mục ngôn ngữ bạn kèm theo đều có đủ mọi khóa. Một khóa thiếu sẽ hiện khóa thô lên màn hình.
- Bạn đã thử trong nhiều người chơi, không chỉ một mình. Vị trí, quyền sở hữu và mod data đều hành xử khác ở đó.
- Trang Workshop của bạn cảnh báo về việc gỡ addon khỏi file save còn con vật sống.
15. Lỗi thường gặp
| Triệu chứng | Nó là gì |
|---|---|
| "Con vật của tôi chẳng bao giờ xuất hiện." | Gần như luôn là chốt kiểm tra: add-on cần một API mà mod nền đang cài không có, nên nó thoát ra ngay và không đăng ký gì cả. |
| "Nó xuất hiện, nhưng đứng cứng." | Bộ animation không phải "raccoon", hoặc model thiếu clip. |
| "Nó hiện ra như một vệt đen và log tràn lỗi." | Model có hơn 60 xương. |
| "Mổ nó thì game sập." | Chưa gọi CD.defineDogParts. |
| "Con non sinh ra to bằng con trưởng thành." | Một giống nhỏ không đặt puppySize. Giá trị này là tuyệt đối và được áp lại ở mỗi lượt quét, nên khoảng kích cỡ của kiểu không bao được nó. |
| "Hai giống của tôi cứ biến thành nhau." | Chúng dùng chung một engineBreed. Tiền tố chọn mesh và có thể dùng chung trong một họ. Còn engineBreed chọn texture và phân biệt các giống trong họ đó, nên nó phải là duy nhất cho mỗi giống. |
| "Âm thanh có phát nhưng phớt lờ thanh âm lượng." | Chưa gọi CD.registerVoices cho âm thanh đó. |
| "Chơi đơn thì ổn, lên server lại lỗi." | Có gì đó đang ghi ModData ở phía client. Hãy chuyển nó sang server. |
| "Nó đánh nhau với zombie dù tôi đã tắt chiến đấu." | Mod nền nó đang chạy trên đó cũ hơn API 5. Mod nền đó không biết trường này và bỏ qua nó. Chốt kiểm tra phải chặn trên mod nền này, thay vì cứ nạp khi thiếu trường. |
Có gì trong sổ tay này sai, hoặc còn thiếu? Hãy nói ở Discord.