Otclient  14/8/2020
thingtypemanager.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2010-2020 OTClient <https://github.com/edubart/otclient>
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a copy
5  * of this software and associated documentation files (the "Software"), to deal
6  * in the Software without restriction, including without limitation the rights
7  * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8  * copies of the Software, and to permit persons to whom the Software is
9  * furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice shall be included in
12  * all copies or substantial portions of the Software.
13  *
14  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20  * THE SOFTWARE.
21  */
22 
23 #include "thingtypemanager.h"
24 #include "spritemanager.h"
25 #include "thing.h"
26 #include "thingtype.h"
27 #include "itemtype.h"
28 #include "creature.h"
29 #include "creatures.h"
30 #include "game.h"
31 
35 #include <framework/xml/tinyxml.h>
36 #include <framework/otml/otml.h>
37 
39 
41 {
42  m_nullThingType = ThingTypePtr(new ThingType);
43  m_nullItemType = ItemTypePtr(new ItemType);
44  m_datSignature = 0;
45  m_contentRevision = 0;
46  m_otbMinorVersion = 0;
47  m_otbMajorVersion = 0;
48  m_datLoaded = false;
49  m_xmlLoaded = false;
50  m_otbLoaded = false;
51  for(auto &m_thingType: m_thingTypes)
52  m_thingType.resize(1, m_nullThingType);
53  m_itemTypes.resize(1, m_nullItemType);
54 }
55 
57 {
58  for(auto &m_thingType: m_thingTypes)
59  m_thingType.clear();
60  m_itemTypes.clear();
61  m_reverseItemTypes.clear();
62  m_nullThingType = nullptr;
63  m_nullItemType = nullptr;
64 }
65 
66 void ThingTypeManager::saveDat(std::string fileName)
67 {
68  if(!m_datLoaded)
69  stdext::throw_exception("failed to save, dat is not loaded");
70 
71  try {
72  FileStreamPtr fin = g_resources.createFile(fileName);
73  if(!fin)
74  stdext::throw_exception(stdext::format("failed to open file '%s' for write", fileName));
75 
76  fin->cache();
77 
78  fin->addU32(m_datSignature);
79 
80  for(auto &m_thingType: m_thingTypes)
81  fin->addU16(m_thingType.size() - 1);
82 
83  for(int category = 0; category < ThingLastCategory; ++category) {
84  uint16 firstId = 1;
85  if(category == ThingCategoryItem)
86  firstId = 100;
87 
88  for(uint16 id = firstId; id < m_thingTypes[category].size(); ++id)
89  m_thingTypes[category][id]->serialize(fin);
90  }
91 
92 
93  fin->flush();
94  fin->close();
95  } catch(std::exception& e) {
96  g_logger.error(stdext::format("Failed to save '%s': %s", fileName, e.what()));
97  }
98 }
99 
100 bool ThingTypeManager::loadDat(std::string file)
101 {
102  m_datLoaded = false;
103  m_datSignature = 0;
104  m_contentRevision = 0;
105  try {
106  file = g_resources.guessFilePath(file, "dat");
107 
108  FileStreamPtr fin = g_resources.openFile(file);
109 
110  m_datSignature = fin->getU32();
111  m_contentRevision = static_cast<uint16_t>(m_datSignature);
112 
113  for(auto &m_thingType: m_thingTypes) {
114  int count = fin->getU16() + 1;
115  m_thingType.clear();
116  m_thingType.resize(count, m_nullThingType);
117  }
118 
119  for(int category = 0; category < ThingLastCategory; ++category) {
120  uint16 firstId = 1;
121  if(category == ThingCategoryItem)
122  firstId = 100;
123  for(uint16 id = firstId; id < m_thingTypes[category].size(); ++id) {
124  ThingTypePtr type(new ThingType);
125  type->unserialize(id, (ThingCategory)category, fin);
126  m_thingTypes[category][id] = type;
127  }
128  }
129 
130  m_datLoaded = true;
131  g_lua.callGlobalField("g_things", "onLoadDat", file);
132  return true;
133  } catch(stdext::exception& e) {
134  g_logger.error(stdext::format("Failed to read dat '%s': %s'", file, e.what()));
135  return false;
136  }
137 }
138 
139 bool ThingTypeManager::loadOtml(std::string file)
140 {
141  try {
142  file = g_resources.guessFilePath(file, "otml");
143 
145  for(const OTMLNodePtr& node : doc->children()) {
146  ThingCategory category;
147  if(node->tag() == "creatures")
148  category = ThingCategoryCreature;
149  else if(node->tag() == "items")
150  category = ThingCategoryItem;
151  else if(node->tag() == "effects")
152  category = ThingCategoryEffect;
153  else if(node->tag() == "missiles")
154  category = ThingCategoryMissile;
155  else {
156  throw OTMLException(node, "not a valid thing category");
157  }
158 
159  for(const OTMLNodePtr& node2 : node->children()) {
160  uint16 id = stdext::safe_cast<uint16>(node2->tag());
161  ThingTypePtr type = getThingType(id, category);
162  if(!type)
163  throw OTMLException(node2, "thing not found");
164  type->unserializeOtml(node2);
165  }
166  }
167  return true;
168  } catch(std::exception& e) {
169  g_logger.error(stdext::format("Failed to read dat otml '%s': %s'", file, e.what()));
170  return false;
171  }
172 }
173 
174 void ThingTypeManager::loadOtb(const std::string& file)
175 {
176  try {
177  FileStreamPtr fin = g_resources.openFile(file);
178 
179  uint signature = fin->getU32();
180  if(signature != 0)
181  stdext::throw_exception("invalid otb file");
182 
183  BinaryTreePtr root = fin->getBinaryTree();
184  root->skip(1); // otb first byte is always 0
185 
186  signature = root->getU32();
187  if(signature != 0)
188  stdext::throw_exception("invalid otb file");
189 
190  uint8 rootAttr = root->getU8();
191  if(rootAttr == 0x01) { // OTB_ROOT_ATTR_VERSION
192  uint16 size = root->getU16();
193  if(size != 4 + 4 + 4 + 128)
194  stdext::throw_exception("invalid otb root attr version size");
195 
196  m_otbMajorVersion = root->getU32();
197  m_otbMinorVersion = root->getU32();
198  root->skip(4); // buildNumber
199  root->skip(128); // description
200  }
201 
202  BinaryTreeVec children = root->getChildren();
203  m_reverseItemTypes.clear();
204  m_itemTypes.resize(children.size() + 1, m_nullItemType);
205  m_reverseItemTypes.resize(children.size() + 1, m_nullItemType);
206 
207  for(const BinaryTreePtr& node : children) {
208  ItemTypePtr itemType(new ItemType);
209  itemType->unserialize(node);
210  addItemType(itemType);
211 
212  uint16 clientId = itemType->getClientId();
213  if(unlikely(clientId >= m_reverseItemTypes.size()))
214  m_reverseItemTypes.resize(clientId + 1);
215  m_reverseItemTypes[clientId] = itemType;
216  }
217 
218  m_otbLoaded = true;
219  g_lua.callGlobalField("g_things", "onLoadOtb", file);
220  } catch(std::exception& e) {
221  g_logger.error(stdext::format("Failed to load '%s' (OTB file): %s", file, e.what()));
222  }
223 }
224 
225 void ThingTypeManager::loadXml(const std::string& file)
226 {
227  try {
228  if(!isOtbLoaded())
229  stdext::throw_exception("OTB must be loaded before XML");
230 
231  TiXmlDocument doc;
232  doc.Parse(g_resources.readFileContents(file).c_str());
233  if(doc.Error())
234  stdext::throw_exception(stdext::format("failed to parse '%s': '%s'", file, doc.ErrorDesc()));
235 
236  TiXmlElement* root = doc.FirstChildElement();
237  if(!root || root->ValueTStr() != "items")
238  stdext::throw_exception("invalid root tag name");
239 
240  for(TiXmlElement *element = root->FirstChildElement(); element; element = element->NextSiblingElement()) {
241  if(unlikely(element->ValueTStr() != "item"))
242  continue;
243 
244  uint16 id = element->readType<uint16>("id");
245  if(id != 0) {
246  std::vector<std::string> s_ids = stdext::split(element->Attribute("id"), ";");
247  for(const std::string& s : s_ids) {
248  std::vector<int32> ids = stdext::split<int32>(s, "-");
249  if(ids.size() > 1) {
250  int32 i = ids[0];
251  while(i <= ids[1])
252  parseItemType(i++, element);
253  } else
254  parseItemType(atoi(s.c_str()), element);
255  }
256  } else {
257  std::vector<int32> begin = stdext::split<int32>(element->Attribute("fromid"), ";");
258  std::vector<int32> end = stdext::split<int32>(element->Attribute("toid"), ";");
259  if(begin[0] && begin.size() == end.size()) {
260  size_t size = begin.size();
261  for(size_t i = 0; i < size; ++i)
262  while(begin[i] <= end[i])
263  parseItemType(begin[i]++, element);
264  }
265  }
266  }
267 
268  doc.Clear();
269  m_xmlLoaded = true;
270  g_logger.debug("items.xml read successfully.");
271  } catch(std::exception& e) {
272  g_logger.error(stdext::format("Failed to load '%s' (XML file): %s", file, e.what()));
273  }
274 }
275 
277 {
278  ItemTypePtr itemType = nullptr;
279 
280  bool s;
281  int d;
282 
283  if(g_game.getClientVersion() < 960) {
284  s = serverId > 20000 && serverId < 20100;
285  d = 20000;
286  } else {
287  s = serverId > 30000 && serverId < 30100;
288  d = 30000;
289  }
290 
291  if(s) {
292  serverId -= d;
293  itemType = ItemTypePtr(new ItemType);
294  itemType->setServerId(serverId);
295  addItemType(itemType);
296  } else
297  itemType = getItemType(serverId);
298 
299  itemType->setName(elem->Attribute("name"));
300  for(TiXmlElement* attrib = elem->FirstChildElement(); attrib; attrib = attrib->NextSiblingElement()) {
301  std::string key = attrib->Attribute("key");
302  if(key.empty())
303  continue;
304 
305  stdext::tolower(key);
306  if(key == "description")
307  itemType->setDesc(attrib->Attribute("value"));
308  else if(key == "weapontype")
309  itemType->setCategory(ItemCategoryWeapon);
310  else if(key == "ammotype")
312  else if(key == "armor")
313  itemType->setCategory(ItemCategoryArmor);
314  else if(key == "charges")
315  itemType->setCategory(ItemCategoryCharges);
316  else if(key == "type") {
317  std::string value = attrib->Attribute("value");
318  stdext::tolower(value);
319 
320  if(value == "key")
321  itemType->setCategory(ItemCategoryKey);
322  else if(value == "magicfield")
324  else if(value == "teleport")
326  else if(value == "door")
327  itemType->setCategory(ItemCategoryDoor);
328  }
329  }
330 }
331 
333 {
334  uint16 id = itemType->getServerId();
335  if(unlikely(id >= m_itemTypes.size()))
336  m_itemTypes.resize(id + 1, m_nullItemType);
337  m_itemTypes[id] = itemType;
338 }
339 
341 {
342  if(id == 0 || id >= m_reverseItemTypes.size())
343  return m_nullItemType;
344 
345  if(m_reverseItemTypes[id])
346  return m_reverseItemTypes[id];
347  else
348  return m_nullItemType;
349 }
350 
352 {
353  for(const ItemTypePtr& it : m_itemTypes)
354  if(it->getName() == name)
355  return it;
356  return m_nullItemType;
357 }
358 
360 {
361  ItemTypeList ret;
362  for(const ItemTypePtr& it : m_itemTypes)
363  if(it->getName() == name)
364  ret.push_back(it);
365  return ret;
366 }
367 
369 {
370  ItemTypeList ret;
371  for(const ItemTypePtr& it : m_itemTypes)
372  if(it->getName().find(name) != std::string::npos)
373  ret.push_back(it);
374  return ret;
375 }
376 
378 {
379  if(category >= ThingLastCategory || id >= m_thingTypes[category].size()) {
380  g_logger.error(stdext::format("invalid thing type client id %d in category %d", id, category));
381  return m_nullThingType;
382  }
383  return m_thingTypes[category][id];
384 }
385 
387 {
388  if(id >= m_itemTypes.size() || m_itemTypes[id] == m_nullItemType) {
389  g_logger.error(stdext::format("invalid thing type, server id: %d", id));
390  return m_nullItemType;
391  }
392  return m_itemTypes[id];
393 }
394 
396 {
397  ThingTypeList ret;
398  for(const ThingTypePtr& type : m_thingTypes[category])
399  if(type->hasAttr(attr))
400  ret.push_back(type);
401  return ret;
402 }
403 
405 {
406  ItemTypeList ret;
407  for(const ItemTypePtr& type : m_itemTypes)
408  if(type->getCategory() == category)
409  ret.push_back(type);
410  return ret;
411 }
412 
414 {
415  ThingTypeList ret;
416  if(category >= ThingLastCategory)
417  stdext::throw_exception(stdext::format("invalid thing type category %d", category));
418  return m_thingTypes[category];
419 }
420 
421 /* vim: set ts=4 sw=4 et: */
binarytree.h
ItemTypeList
std::vector< ItemTypePtr > ItemTypeList
Definition: declarations.h:82
thingtypemanager.h
ThingTypeManager::loadDat
bool loadDat(std::string file)
Definition: thingtypemanager.cpp:100
ThingTypeManager::findItemTypesByString
ItemTypeList findItemTypesByString(std::string name)
Definition: thingtypemanager.cpp:368
ItemType::unserialize
void unserialize(const BinaryTreePtr &node)
Definition: itemtype.cpp:36
TiXmlNode::NextSiblingElement
const TiXmlElement * NextSiblingElement() const
Definition: tinyxml.cpp:476
ThingCategoryMissile
@ ThingCategoryMissile
Definition: thingtype.h:46
OTMLException
All OTML errors throw this exception.
Definition: otmlexception.h:29
unlikely
#define unlikely(x)
Definition: compiler.h:71
FileStream::close
void close()
Definition: filestream.cpp:78
otml.h
FileStream::addU32
void addU32(uint32 v)
Definition: filestream.cpp:377
ItemCategoryMagicField
@ ItemCategoryMagicField
Definition: itemtype.h:40
ThingTypeManager::findItemTypeByName
const ItemTypePtr & findItemTypeByName(std::string name)
Definition: thingtypemanager.cpp:351
ThingTypeManager::loadOtml
bool loadOtml(std::string file)
Definition: thingtypemanager.cpp:139
OTMLDocument::parse
static OTMLDocumentPtr parse(const std::string &fileName)
Parse OTML from a file.
Definition: otmldocument.cpp:36
TiXmlDocument::ErrorDesc
const char * ErrorDesc() const
Contains a textual (english) description of the error if one occurs.
Definition: tinyxml.h:1380
TiXmlDocument::Parse
virtual const char * Parse(const char *p, TiXmlParsingData *data=0, TiXmlEncoding encoding=TIXML_DEFAULT_ENCODING)
Definition: tinyxmlparser.cpp:708
ThingLastCategory
@ ThingLastCategory
Definition: thingtype.h:48
TiXmlNode::ValueTStr
const TIXML_STRING & ValueTStr() const
Definition: tinyxml.h:504
LuaInterface::callGlobalField
void callGlobalField(const std::string &global, const std::string &field, const T &... args)
Definition: luainterface.h:445
ItemTypePtr
stdext::shared_object_ptr< ItemType > ItemTypePtr
Definition: declarations.h:74
resourcemanager.h
tinyxml.h
Logger::error
void error(const std::string &what)
Definition: logger.h:54
Game::getClientVersion
int getClientVersion()
Definition: game.h:316
ThingTypeManager::getItemType
const ItemTypePtr & getItemType(uint16 id)
Definition: thingtypemanager.cpp:386
OTMLNode::children
OTMLNodeList children()
Definition: otmlnode.cpp:170
ItemCategoryTeleport
@ ItemCategoryTeleport
Definition: itemtype.h:39
ThingType::unserializeOtml
void unserializeOtml(const OTMLNodePtr &node)
Definition: thingtype.cpp:356
g_game
Game g_game
Definition: game.cpp:37
ItemType::getClientId
uint16 getClientId()
Definition: itemtype.h:141
ItemType::setDesc
void setDesc(const std::string &desc)
Definition: itemtype.h:149
ThingCategoryEffect
@ ThingCategoryEffect
Definition: thingtype.h:45
stdext::format
std::string format()
Definition: format.h:82
ThingTypeManager::getThingTypes
const ThingTypeList & getThingTypes(ThingCategory category)
Definition: thingtypemanager.cpp:413
ItemType::setServerId
void setServerId(uint16 serverId)
Definition: itemtype.h:137
creature.h
TiXmlElement::Attribute
std::string Attribute(const std::string &name) const
Definition: tinyxml.cpp:558
uint16
uint16_t uint16
Definition: types.h:36
ThingTypeManager::loadXml
void loadXml(const std::string &file)
Definition: thingtypemanager.cpp:225
ThingType::unserialize
void unserialize(uint16 clientId, ThingCategory category, const FileStreamPtr &fin)
Definition: thingtype.cpp:134
g_resources
ResourceManager g_resources
Definition: resourcemanager.cpp:32
uint
unsigned int uint
Definition: types.h:31
FileStream::cache
void cache()
Definition: filestream.cpp:58
TiXmlNode::Clear
void Clear()
Delete all the children of this node. Does not affect 'this'.
Definition: tinyxml.cpp:169
ThingCategoryCreature
@ ThingCategoryCreature
Definition: thingtype.h:44
FileStream::getU16
uint16 getU16()
Definition: filestream.cpp:199
FileStream::getBinaryTree
BinaryTreePtr getBinaryTree()
Definition: filestream.cpp:334
g_logger
Logger g_logger
Definition: logger.cpp:35
spritemanager.h
TiXmlDocument
Definition: tinyxml.h:1310
int32
int32_t int32
Definition: types.h:39
g_lua
LuaInterface g_lua
Definition: luainterface.cpp:31
ItemCategoryWeapon
@ ItemCategoryWeapon
Definition: itemtype.h:35
TiXmlNode::FirstChildElement
const TiXmlElement * FirstChildElement() const
Convenience function to get through elements.
Definition: tinyxml.cpp:446
ItemCategory
ItemCategory
Definition: itemtype.h:31
ItemType::getServerId
uint16 getServerId()
Definition: itemtype.h:138
ThingTypeManager::isOtbLoaded
bool isOtbLoaded()
Definition: thingtypemanager.h:73
ThingTypeManager::findItemTypeByClientId
const ItemTypePtr & findItemTypeByClientId(uint16 id)
Definition: thingtypemanager.cpp:340
ThingCategoryItem
@ ThingCategoryItem
Definition: thingtype.h:43
ThingTypeManager::findItemTypeByCategory
ItemTypeList findItemTypeByCategory(ItemCategory category)
Definition: thingtypemanager.cpp:404
ThingTypeManager::getThingType
const ThingTypePtr & getThingType(uint16 id, ThingCategory category)
Definition: thingtypemanager.cpp:377
ItemType
Definition: itemtype.h:130
ThingTypeManager::init
void init()
Definition: thingtypemanager.cpp:40
ItemType::setName
void setName(const std::string &name)
Definition: itemtype.h:146
ThingAttr
ThingAttr
Definition: thingtype.h:51
ThingType
Definition: thingtype.h:123
ThingTypePtr
stdext::shared_object_ptr< ThingType > ThingTypePtr
Definition: declarations.h:73
ItemCategoryArmor
@ ItemCategoryArmor
Definition: itemtype.h:37
stdext::throw_exception
void throw_exception(const std::string &what)
Throws a generic exception.
Definition: exception.h:43
ItemCategoryCharges
@ ItemCategoryCharges
Definition: itemtype.h:38
ResourceManager::openFile
FileStreamPtr openFile(const std::string &fileName)
Definition: resourcemanager.cpp:232
ResourceManager::readFileContents
std::string readFileContents(const std::string &fileName)
Definition: resourcemanager.cpp:185
stdext::split
std::vector< std::string > split(const std::string &str, const std::string &separators)
Definition: string.cpp:273
filestream.h
stdext::exception::what
virtual const char * what() const
Definition: exception.h:37
ItemType::setCategory
void setCategory(ItemCategory category)
Definition: itemtype.h:143
Logger::debug
void debug(const std::string &what)
Definition: logger.h:51
ThingTypeManager
Definition: thingtypemanager.h:32
ThingTypeManager::loadOtb
void loadOtb(const std::string &file)
Definition: thingtypemanager.cpp:174
stdext::shared_object_ptr< FileStream >
BinaryTreeVec
std::vector< BinaryTreePtr > BinaryTreeVec
Definition: declarations.h:47
ThingTypeList
std::vector< ThingTypePtr > ThingTypeList
Definition: declarations.h:81
itemtype.h
ThingTypeManager::addItemType
void addItemType(const ItemTypePtr &itemType)
Definition: thingtypemanager.cpp:332
ThingTypeManager::parseItemType
void parseItemType(uint16 id, TiXmlElement *elem)
Definition: thingtypemanager.cpp:276
FileStream::getU32
uint32 getU32()
Definition: filestream.cpp:215
FileStream::flush
void flush()
Definition: filestream.cpp:90
ItemCategoryKey
@ ItemCategoryKey
Definition: itemtype.h:42
ThingTypeManager::findThingTypeByAttr
ThingTypeList findThingTypeByAttr(ThingAttr attr, ThingCategory category)
Definition: thingtypemanager.cpp:395
game.h
ThingCategory
ThingCategory
Definition: thingtype.h:42
TiXmlElement
Definition: tinyxml.h:943
thing.h
TiXmlDocument::Error
bool Error() const
Definition: tinyxml.h:1377
ThingTypeManager::findItemTypesByName
ItemTypeList findItemTypesByName(std::string name)
Definition: thingtypemanager.cpp:359
creatures.h
thingtype.h
ThingTypeManager::terminate
void terminate()
Definition: thingtypemanager.cpp:56
ResourceManager::createFile
FileStreamPtr createFile(const std::string &fileName)
Definition: resourcemanager.cpp:250
ThingTypeManager::saveDat
void saveDat(std::string fileName)
Definition: thingtypemanager.cpp:66
stdext::tolower
void tolower(std::string &str)
Definition: string.cpp:216
ItemCategoryDoor
@ ItemCategoryDoor
Definition: itemtype.h:45
ItemCategoryAmmunition
@ ItemCategoryAmmunition
Definition: itemtype.h:36
g_things
ThingTypeManager g_things
Definition: thingtypemanager.cpp:38
uint8
uint8_t uint8
Definition: types.h:37
ResourceManager::guessFilePath
std::string guessFilePath(const std::string &filename, const std::string &type)
Definition: resourcemanager.cpp:352
FileStream::addU16
void addU16(uint16 v)
Definition: filestream.cpp:365
stdext::exception
Definition: exception.h:31