Mangos源码分析(一)(DBC文件分析)


(2008-01-24 22:57:57)

标签:mangos
【Mangos源码分析(一)(DBC文件分析)】一、DBC文件结构

文件头文件头(4字节“WDBC”)|记录数(4字节)|记录字段数(4字节)|每条记录字节数(4字节)|字符串表总字节数(4字节)
记录1字段1|字段2|...|字段N
记录2字段1|字段2|...|字段N
字符串表字符串1|字符串2|...|字符串N

示例:打开从中国WOW客户端2.3.2解出来的DBC文件Weather.dbc,图1、图2是UE的截图(16进制),图3为DBC工具的截图(10进制)

Mangos源码分析(一)(DBC文件分析)
文章图片

图1、文件头及记录
55 44 42 43 | 15 00 00 00 | 07 00 00 00 | 1C 00 00 00 | 39 00 00 00
文件头“WDBC”| 记录数20| 字段数7| 每记录字节数28 | 字符串表总字节数57
5B 00 00 00 | 00 00 00 00 | 01 00 00 00 | 00 00 80 3F | 00 00 80 3F | 00 00 80 3F | 01 00 00 00
91| 0| 1| 1065353216| 1065353216| 1065353216| 1
......

Mangos源码分析(一)(DBC文件分析)
文章图片

图2、字符串表,以NULL(/0)即00分割字符串,记录所含有的字符串字段保存的数据是在字符串表中的偏移值

Mangos源码分析(一)(DBC文件分析)
文章图片

图3、用DBC工具打开文件的数据显示,Index列为DBC工具自动加入的索引

二、DBC文件分析

1、DBC文件的字段类型
在Mangos项目的dbcfile.h文件枚举了DBC文件的常见字段类型:
enum
{
FT_NA='x',//没有使用或者未知类型,4字节
FT_NA_BYTE='X', //没有使用或者未知类型,单字节
FT_STRING='s',//sizeof(char*),字符串指针32位机4字节
FT_FLOAT='f',//float,4字节
FT_INT='i',//uint32,4字节
FT_BYTE='b',//uint8,单字节
FT_SORT='d',//索引字段,但不计入记录字段,4字节
FT_IND='n',//记录的索引字段,4字节
...
};

2、DBC文件的记录格式
DBCfmt.cpp文件中定义了DBC文件中的记录保存格式:
...
const char DurabilityCostsfmt[]="niiiiiiiiiiiiiiiiiiiiiiiiiiiii";
const char DurabilityQualityfmt[]="nf"; //表示DurabilityQualityfmt.dbc中包含2个字段,类型为n和f,程序加载DBC文件时以该格式解析数据然后保存到数组
const char EmoteEntryfmt[]="nxixxxxxxxxxxxxxxxx";
...

3、加载数据库和DBC文件初始化WOW模拟服务端示例
(1)World.cpp中:
...
objmgr.LoadSpellLearnSkills(); //可以学习的技能
...
(2)ObjectMgr.cpp的LoadSpellLearnSkills()函数:
//从mangos数据库的spell_learn_skill数据表先加载到mSpellLearnSkills(类型std::map)
QueryResult *result = WorldDatabase.PQuery("SELECT `entry`, `SkillID`, `Value`, `MaxValue` FROM `spell_learn_skill`");
//将从数据库取得全部数据逐个检查
Field *fields = result->Fetch();
uint32 spell_id = fields[0].GetUInt32(); //0表示数据库的entry字段
//从DBC文件中检查是否存在此数据不存在则报错
if(!sSpellStore.LookupEntry(spell_id))
{
sLog.outErrorDb("Spell %u listed in `spell_learn_skill` does not exist",spell_id);
continue;
}
(3)sSpellStore对象加载Spell.dbc
·DBCStores.cpp文件中:
LoadDBC(bar,bad_dbc_files,sSpellStore, dataPath+"dbc/Spell.dbc");
LoadDBC(...){...}该函数调用了storage.Load(filename.c_str()),storage为传入的sSpellStore,filename.c_str()则是Spell.dbc的完整文件名
·找到DBCStores.h中的Load函数定义:
bool Load(char const* fn)
{
dbc = new DBCFile; //DBC文件类,见dbcfile.h和dbcfile.cpp文件
bool res = dbc->Load(fn, fmt); //fn为DBC文件名,fmt为DBC文件字段格式,这里是//SpellEntryfmt="niixii...";
if (res)
{
fieldCount = dbc->GetCols();
indexTable=(T **) dbc->AutoProduceData(fmt,&nCount,data); //返回每条记录的地址表
}
...
return res;
}

示例说明:从上面的代码分析可以看到在运行服务端mangosd.exe从控制台看到“Loading Spell Learn Skills...”时,Spell.dbc文件已经加载到内存,并且在把从mangos数据库取得的技能数组mSpellLearnSkills和Spell.dbc文件中对应的数据比较,如果数据库和DBC文件的数据不一样,则提示出错如:“Spell 技能ID listed in `spell_learn_skill` does not exist”。
 
附在线源代码:http://www.mangosproject.org/trac/browser/trunk/src

待续...(time)

    推荐阅读