0x00 前言
所谓的「外观」就是游戏人物在穿上不同的服饰后、在游戏中形象发生改变的结果。
而在 RO 中,人物形象的改变,需要有对应的「图档」文件作为支持,可以简单认为与现代网游中的「皮肤」是同一个概念。
这些图档存储的位置一般都在客户端根目录的 GRF 里面,例如「卡浩之角」,它在 System/iteminfo.lub
中被设定的名称为 肺靛墨龋狼辉
,因此只需要在 GRF 中搜索这个名称就可以找到对应的图档:
所有道具和装备都有图档,但是能对人物外在形象产生视觉影响的,目前只有两类:
- 头饰: 包括 头上、头中、头下 三个位置
- 披肩: 常见如 翅膀、背包
在 RO 早期其实只有头饰能在外观中体现出来,后来增加了披肩。
再后来增加了时装,时装属于人物的第二装备,也有头饰和披肩,在配置上其实和普通装备是大同小异的;唯一的区别是,当同一个位置同时穿着时装和普通装备时,时装的外观会覆盖普通装备的外观,可以简单认为与现代网游中的「幻化」是同一个概念。
武器其实也存在「攻击外观」,即只有攻击时才可以看到外观,但因为和「防具外观」略有不同,故不列入本篇的讨论范围内,后面会另外起个专题解读
0x10 外观
还是以「卡浩之角」为例,它在服务端的道具库 db/re/item_db_equip.yml
中设定如下:
- Id: 5013
AegisName: Horn_Of_Lord_Kaho
Name: 卡浩之角
Type: Armor
Buy: 20
Weight: 100
Defense: 30
Locations:
Head_Top: true
ArmorLevel: 1
Refineable: true
View: 99
Script: |
bonus bMdef,10;
bonus bStr,5;
bonus bAgiVit,10;
bonus bInt,5;
bonus bLuk,20;
itemskill "NPC_HELLJUDGEMENT",10;
其中 View: 99
就是外观 ID。
如果是时装,
Locations
的位置会多一个Costume_
前缀,例如Costume_Head_Top
同样地,它在客户端道具描述 System/itemInfo.lub
中设定如下:
[5013] = {
unidentifiedDisplayName = "头饰",
unidentifiedResourceName = "府夯",
unidentifiedDescriptionName = {
"尚未鉴定, 可使用^990099[放大镜]^000000进行鉴定"
},
identifiedDisplayName = "卡浩之角",
identifiedResourceName = "肺靛墨龋狼辉",
identifiedDescriptionName = {
"怪物卡浩专用饰品。",
"STR+5 , INT+5",
"VIT+10 , AGI+10",
"LUK+20 , MDEF+10",
"系列: ^777777头具^000000 防御: ^77777730^000000",
"位置: ^777777上^000000 重量: ^77777710^000000",
"装备: ^777777全职业^000000"
},
slotCount = 0,
ClassNum = 99
},
其中:
- 图档名称(鉴定后):
identifiedResourceName = "肺靛墨龋狼辉"
- 外观 ID:
ClassNum = 99
如果是时装,会多一个属性
costume = true
这里可以看出服务端和客户端的道具关系:
属性 | 服务端 | 客户端 |
---|---|---|
道具 ID | Id: 5013 |
[5013] |
图档名称 | 无 | identifiedResourceName = "肺靛墨龋狼辉" |
外观 ID | View: 99 |
ClassNum = 99 |
这个表其实想说明的是:
决定服务端的一个「道具/装备」本身长什么样(在背包中、在地上的样子),其逻辑关系链为:
- 通过「道具 ID」关联到客户端的「道具池」
System/iteminfo.lub
- 再关联到道具本身的图档名称
identifiedResourceName
- 最后查找到 GRF 中的
bmp
图档文件,在游戏中渲染
而决定服务端的一件装备「着装」后人物长什么样,其逻辑关系链为:
- 通过「外观 ID」关联到客户端的「外观池」
- 在外观池中找到「外观 ID」对应的图档名称
- 最后查找到 GRF 中的
spr
和act
图档文件,在游戏中渲染
相信「道具池」System/iteminfo.lub
很多同学都经常在用了;但是「外观池」是什么?估计很多人就不了解了。
「道具池」和「外观池」都是我为了简化理解而创造出来的概念,官方文档应该是没有这两个概念的
0x30 外观池
所谓的外观池,试想一下,有一堆外观图档在一个池子里,当某个装备要渲染外观时,就拿着外观 ID 从池子里面捞一个外观出来用。这也是为什么你时常在游戏中会看到不同的装备穿上身之后,渲染出来的样子却是一样的原因 —— 外观不需要和特定装备绑定。
在 RO 中,外观池又分为两种:「头饰外观池」和「披肩外观池」。
时装和普通装备的外观池是共用的
头饰外观池是由客户端这两个文件控制的:
- 定义「头饰唯一代码」和「头饰外观 ID」的关系:
data/luafiles514/lua files/datainfo/accessoryid.lub
- 定义「头饰唯一代码」和「头饰图档名称」的关系:
data/luafiles514/lua files/datainfo/accname.lub
这两个文件是通过「头饰唯一代码」作为内部变量关联起来的,这个代码可以自定义为任意英文字符串,只需要全局唯一即可。因为代码是唯一的,不难推理出「头饰外观 ID」和「头饰外观图档」是一一对应的关系。
从数据结构看,它们的关系其实就是先定义了一个常量表,再以常量表为 key 定义了一个 hash 表,伪代码类似于:
const int XXX_KEY = view_id;
Map hash_table = {
XXX_KEY = "外观图档名称";
}
0x40 外观 ID 范围
官方在池子里默认放了一些外观,我们也可以根据自己的需要在池子里添加外观。
默认的外观 ID 范围是 1 ~ 2000,超过这个范围的外观 ID,即使放到池子里也会被无视掉,即这个外观不生效。
如果制作了很多特色外观,池子里已经放不下了,这时可以通过 DIFF 扩展外观 ID 上限解决:
- 通过 Nemo 找到
Increase Headgear ViewID
选项 - 修改为上限值
32000
但是据我实测,至少在 2022-04-06 之后的登陆器已经取消了外观 ID 上限的限制。
DIFF 的方法可参考《从零开始 DIFF Ragnarok 登入器教程》
0x50 外观图档位置
上文多次提到外观图档需要在 GRF 里面搜索。其实在 data.grf 中,有 5 个目录是和头饰的外观图档相关的:
- 道具在地上/拖拽时的图档:
data/sprite/酒捞袍
- 道具栏的小图图档:
data/texture/蜡历牢磐其捞胶/item
- 道具详情的大图图档:
data/texture/蜡历牢磐其捞胶/collection
- 男生头饰外观的图档:
data/sprite/厩技荤府/巢
- 女生头饰外观的图档:
data/sprite/厩技荤府/咯
当客户端获取到道具/装备后,就会根据实际的场景从上述对应的目录中搜索其图档。
关于客户端目录结构,可以参考这篇文章 《客户端目录结构及功能说明》
0x60 实例
最后依然用「卡浩之角」作为例子,从头帮大家捋一下外观的渲染逻辑。
从「卡浩之角」被魔物掉落在地上开始,客户端已经在执行图档的捞取动作了:
首先客户端会拿到它在道具池中设定的图档名称 identifiedResourceName = "肺靛墨龋狼辉"
,
然后在 GRF 的 data/sprite/酒捞袍
目录下搜索其在地上显示的外观:
当玩家捡起它之后,又会在 data/texture/蜡历牢磐其捞胶/item
目录下搜索其在道具栏中显示的外观:
如果玩家右击它查看道具详情,就会在 data/texture/蜡历牢磐其捞胶/collection
目录下搜索其在详情中显示的外观:
待玩家装备它之后,客户端会:
- 根据外观 ID
View: 99
在外观池data/luafiles514/lua files/datainfo/accessoryid.lub
捞出其「头饰唯一代码」ACCESSORY_HORN_OF_LORD_KAHO
- 根据「头饰唯一代码」
ACCESSORY_HORN_OF_LORD_KAHO
再在外观池data/luafiles514/lua files/datainfo/accname.lub
中捞出外观图档名称_肺靛墨龋狼辉
乍一看好像和
identifiedResourceName
的图档名一样,其实多了一个前缀符号_
以示区别。外观和道具的图档名完全不一样、甚至没有_
都是可以的,这没有限制。之所以会演变成现在这种约定的格式,是为了方便做关联检索。
这里注意的是,在 RO 头饰中,同一件装备,外观渲染是会区分性别的(披肩不会区分性别,所以没有 _
),其中性别的韩文为:
- 男生:
巢
- 女生:
咯
从外观池捞出的图档名称 _肺靛墨龋狼辉
,会根据当前玩家的性别,自动拼接一个性别前缀、动态构造一个图档名称:
- 男生重新构造的图档名称:
巢_肺靛墨龋狼辉
- 女生重新构造的图档名称:
咯_肺靛墨龋狼辉
然后才会使用构造的图档名称、搜索 GRF 对应的目录、得到着装后的外观:
- 男生着装外观的图档目录:
data/sprite/厩技荤府/巢
- 女生着装外观的图档目录:
data/sprite/厩技荤府/咯
当你完全理解上述的外观原理之后,就可以轻易地让「卡浩之角」渲染为「太阳神头盔」的外观:
其实真的非常简单,只需要找到「太阳神头盔」的外观 ID 为 138,然后修改「卡浩之角」的两处地方即可:
- 服务端
View: 99 -> View: 138
- 客户端
ClassNum = 99 -> ClassNum = 138