在分析M2文件时,其中GlobalModelFlags是指向CreateureModelData.dbc的,这样不可避免的要先分析这个表。使用wxDeMPQ的查看DBC功能,发现wiki已经有些过时了,随便就更新了,参见
这里。
下图是wxDeMPQ分析DBC文件的图片,配合DBC的Field配置说明,查看DBC还是满方便的。
这里是DBC的Field配置文件,XML格式的,好理解的,不解释了:
1 <?xml version="1.0" encoding="UTF-8"?>
2 <DBCFile version="1.0">
3 <File name="GameTables.dbc" version="1.0">
4 <Note>GameTables</Note>
5 <Fields>
6 <Field position="0" type="string" size="0">FieldA</Field>
7 <Field position="1" type="integer" size="4">FieldB</Field>
8 <Field position="2" type="integer" size="4">FieldC</Field>
9 </Fields>
10 </File>
11 <File name="CreatureModelData.dbc" version="1.0">
12 <Note></Note>
13 <Fields>
14 <Field position="0" type="integer" size="4">ID</Field>
15 <Field position="1" type="integer" size="4">UnknownA</Field>
16 <Field position="2" type="string">ModulePath</Field>
17 <Field position="3" type="integer" size="4">UnknownB</Field>
18 <Field position="4" type="integer">UnknownC</Field>
19 <Field position="5" type="float">AnimationSpeed</Field>
20 <Field position="6" type="integer">UnknownD</Field>
21 <Field position="7" type="integer">UnknownE</Field>
22 <Field position="8" type="float">UnknownF</Field>
23 <Field position="9" type="float">UnknownG</Field>
24 <Field position="10" type="float">Unknown?</Field>
25 <Field position="11" type="integer">UnknownH</Field>
26 <Field position="12" type="integer">UnknownI</Field>
27 <Field position="13" type="integer">Unknown?1</Field>
28 <Field position="14" type="integer">GroupID</Field>
29 <Field position="15" type="float">Collision</Field>
30 <Field position="16" type="float">UnknownK</Field>
31 <Field position="17" type="float">UnknownL</Field>
32 <Field position="18" type="float">UnknownM</Field>
33 <Field position="19" type="float">UnknownN</Field>
34 <Field position="20" type="float">UnknownO</Field>
35 <Field position="21" type="float">UnknownP</Field>
36 <Field position="22" type="float">UnknownQ</Field>
37 <Field position="23" type="float">UnknownR</Field>
38 <Field position="24" type="float">UnknownS</Field>
39 <Field position="25" type="float">UnknownT</Field>
40 </Fields>
41 </File>
42 <File name="b.dbc" version="1.0">
43 <Note>this is a sample.</Note>
44 <Fields>
45 <Field position="0" type="string" size="0">FieldA</Field>
46 <Field position="1" type="integer" size="4">FieldB</Field>
47 <Field position="2" type="refid" size="4" refdbc="ref.dbc" reffield="0">FieldC</Field>
48 <Field position="3" type="array of integer" size="4" number="10">FieldD</Field>
49 </Fields>
50 </File>
51 </DBCFile>
下面是分析上面XML的代码,当前仅支持integer,string,float类型的Field,分析使用的是tinyxml,有兴趣的可以看看。
MPQDBCFieldObject.h
1 #ifndef __MPQDBCFIELDOBJECT_H__
2 #define __MPQDBCFIELDOBJECT_H__
3
4 #include <string>
5 #include <map>
6
7 #include "FileBuffer.h"
8
9 namespace DBCField
10 {
11 class CField;
12 }
13
14 class CMPQDBCFieldManager
15 {
16 public:
17 typedef std::map<int, DBCField::CField*> TFieldMap;
18 typedef std::map<std::string, TFieldMap> TDBCMap;
19 struct FieldAttr_t
20 {
21 std::string m_strTitle;
22 int m_iPos;
23 std::string m_strType;
24 int m_iSize;
25 std::string m_strRefDBC;
26 int m_iRefPos;
27 int m_iNumber;
28 };
29 public:
30 CMPQDBCFieldManager();
31 virtual ~CMPQDBCFieldManager();
32
33 int Load(const std::string& xml, bool reload = false);
34 const TFieldMap* FindDBCFields(const std::string& dbc) const;
35 private:
36 int ParseXML(const std::string& xml);
37 DBCField::CField* MakeDBCField(const FieldAttr_t& attr) const;
38 void Destory();
39 private:
40 TDBCMap _mapDBC;
41 };
42
43
44 namespace DBCField
45 {
46
47 enum FieldType { FT_INTEGER, FT_STRING, FT_FLOAT };
48
49 class CField
50 {
51 public:
52 CField(FieldType type, const std::string& title, int pos, int size)
53 : m_strTitle(title), m_iPos(pos), m_eType(type), m_iSize(size)
54 {
55 }
56 virtual ~CField() {}
57
58 virtual int Data2String(std::string& str, CFileBuffer& fb, int offset, int strpos = -1) const;
59 public:
60 FieldType m_eType;
61 std::string m_strTitle;
62 int m_iPos;
63 int m_iSize;
64 };
65
66 class CIntegerField : public CField
67 {
68 public:
69 CIntegerField(const std::string& title, int pos, int size)
70 : CField(FT_INTEGER, title, pos, size)
71 {
72 }
73 };
74
75 class CStringField : public CField
76 {
77 public:
78 CStringField(const std::string& title, int pos, int size)
79 : CField(FT_STRING, title, pos, size)
80 {
81 }
82 virtual int Data2String(std::string& str, CFileBuffer& fb, int offset, int strpos = -1) const;
83 };
84
85 class CFloatField : public CField
86 {
87 public:
88 CFloatField(const std::string& title, int pos, int size)
89 : CField(FT_FLOAT, title, pos, size)
90 {
91 }
92 virtual int Data2String(std::string& str, CFileBuffer& fb, int offset, int strpos = -1) const;
93 };
94
95 }
96 #endif
MPQDBCFieldObject.cpp
1 #include "tinyxml.h"
2
3 #include "Toolkit.h"
4
5 #include "MPQDBCFieldObject.h"
6
7 CMPQDBCFieldManager::CMPQDBCFieldManager()
8 {
9 }
10
11 CMPQDBCFieldManager::~CMPQDBCFieldManager()
12 {
13 Destory();
14 }
15
16 void CMPQDBCFieldManager::Destory()
17 {
18 TDBCMap::iterator it = _mapDBC.begin();
19 while(it != _mapDBC.end())
20 {
21 TFieldMap::iterator i = it->second.begin();
22 while(i != it->second.end())
23 {
24 delete i->second;
25 it->second.erase(i++);
26 }
27 _mapDBC.erase(it ++);
28 }
29 }
30
31 int CMPQDBCFieldManager::Load(const std::string &xml, bool reload)
32 {
33 if(reload)
34 {
35 Destory();
36 }
37 return ParseXML(xml);
38 }
39
40 const CMPQDBCFieldManager::TFieldMap* CMPQDBCFieldManager::FindDBCFields(const std::string& dbc) const
41 {
42 TDBCMap::const_iterator it = _mapDBC.find(dbc);
43 if(it == _mapDBC.end())
44 return NULL;
45 return &it->second;
46 }
47
48 int CMPQDBCFieldManager::ParseXML(const std::string &xml)
49 {
50 TiXmlDocument doc;
51 if(!doc.LoadFile(xml.c_str()))
52 return -1;
53
54 std::string name;
55
56 const TiXmlElement* root = doc.RootElement();
57 if(root->ValueStr() != "DBCFile")
58 return -1;
59 const TiXmlElement* file = root->FirstChildElement();
60 while(file != NULL)
61 {
62 //File Attribute
63 name.clear();
64 const TiXmlAttribute* attr = file->FirstAttribute();
65 while(attr != NULL)
66 {
67 if(attr->NameTStr() == "name")
68 name = attr->ValueStr();
69 attr = attr->Next();
70 }
71 if(!name.empty())
72 {
73 TDBCMap::iterator it = _mapDBC.insert(std::make_pair(name, TFieldMap())).first;
74 if(it == _mapDBC.end())
75 return -1;
76
77 const TiXmlElement* fields = file->FirstChildElement("Fields");
78 if(fields != NULL)
79 {
80 const TiXmlElement * field = fields->FirstChildElement("Field");
81 while(field != NULL)
82 {
83 FieldAttr_t data;
84 data.m_iPos = -1;
85 data.m_strType.clear();
86 data.m_strTitle = field->GetText();
87 data.m_iSize = 4;
88 attr = field->FirstAttribute();
89 while(attr != NULL)
90 {
91 if(attr->NameTStr() == "position")
92 data.m_iPos = attr->IntValue();
93 else if(attr->NameTStr() == "type")
94 data.m_strType = attr->ValueStr();
95 else if(attr->NameTStr() == "size")
96 data.m_iSize = attr->IntValue();
97 else if(attr->NameTStr() == "refdbc")
98 data.m_strRefDBC = attr->ValueStr();
99 else if(attr->NameTStr() == "reffield")
100 data.m_iRefPos = attr->IntValue();
101 else if(attr->NameTStr() == "number")
102 data.m_iNumber = attr->IntValue();
103
104 attr = attr->Next();
105 }
106 DBCField::CField* dbcfield = MakeDBCField(data);
107 if(dbcfield != NULL)
108 {
109 TFieldMap::iterator i = it->second.find(data.m_iPos);
110 if(i == it->second.end())
111 {
112 it->second.insert(std::make_pair(dbcfield->m_iPos, dbcfield));
113 }
114 else
115 {
116 delete i->second;
117 i->second = dbcfield;
118 }
119 }
120
121 field = field->NextSiblingElement();
122 }
123 }
124 }
125 file = file->NextSiblingElement();
126 }
127
128 return 0;
129 }
130
131 DBCField::CField* CMPQDBCFieldManager::MakeDBCField(const CMPQDBCFieldManager::FieldAttr_t &attr) const
132 {
133 if(attr.m_iPos == -1 || attr.m_strType.empty())
134 return NULL;
135 if(attr.m_strType == "integer")
136 return new DBCField::CIntegerField(attr.m_strTitle, attr.m_iPos, attr.m_iSize);
137 else if(attr.m_strType == "string")
138 return new DBCField::CStringField(attr.m_strTitle, attr.m_iPos, attr.m_iSize);
139 else if(attr.m_strType == "float")
140 return new DBCField::CFloatField(attr.m_strTitle, attr.m_iPos, attr.m_iSize);
141 return NULL;
142 }
143
144 //////
145 namespace DBCField
146 {
147
148 int CField::Data2String(std::string& str, CFileBuffer &fb, int offset, int strpos) const
149 {
150 int data = 0;
151 fb.Seek(offset);
152 fb.Read(data);
153
154 Toolkit::StringOf<int>(data, str);
155
156 return fb.Good() ? 0 : -1;
157 }
158
159 //
160 int CStringField::Data2String(std::string& str, CFileBuffer &fb, int offset, int strpos) const
161 {
162 int data = 0;
163 fb.Seek(offset);
164 fb.Read(data);
165
166 fb.Seek(data + strpos);
167 fb.Read(str);
168
169 return fb.Good() ? 0 : -1;
170 }
171
172 //
173 int CFloatField::Data2String(std::string& str, CFileBuffer &fb, int offset, int strpos) const
174 {
175 float data = 0.0f;
176 fb.Seek(offset);
177 fb.Read(data);
178
179 Toolkit::StringOf<float>(data, str);
180
181 return fb.Good() ? 0 : -1;
182 }
183
184 }
185