M2过程:修改DBCField对象,更新WOW.Dev Wiki
在分析M2文件时,其中GlobalModelFlags是指向CreateureModelData.dbc的,这样不可避免的要先分析这个表。使用wxDeMPQ的查看DBC功能,发现wiki已经有些过时了,随便就更新了,参见 这里。
下图是wxDeMPQ分析DBC文件的图片,配合DBC的Field配置说明,查看DBC还是满方便的。
这里是DBC的Field配置文件,XML格式的,好理解的,不解释了:
下面是分析上面XML的代码,当前仅支持integer,string,float类型的Field,分析使用的是tinyxml,有兴趣的可以看看。
MPQDBCFieldObject.h
MPQDBCFieldObject.cpp
下图是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 >
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
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
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