Otclient  14/8/2020
creatures.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 "creatures.h"
24 #include "creature.h"
25 #include "map.h"
26 
27 #include <framework/xml/tinyxml.h>
29 
31 
32 static bool isInZone(const Position& pos/* placePos*/,
33  const Position& centerPos,
34  int radius)
35 {
36  if(radius == -1)
37  return true;
38  return ((pos.x >= centerPos.x - radius) && (pos.x <= centerPos.x + radius) &&
39  (pos.y >= centerPos.y - radius) && (pos.y <= centerPos.y + radius)
40  );
41 }
42 
44 {
45  clearSpawns();
46  clear();
47  m_nullCreature = nullptr;
48 }
49 
51 {
52  Position centerPos;
53  centerPos.x = node->readType<int>("centerx");
54  centerPos.y = node->readType<int>("centery");
55  centerPos.z = node->readType<int>("centerz");
56 
57  setCenterPos(centerPos);
58  setRadius(node->readType<int32>("radius"));
59 
60  CreatureTypePtr cType(nullptr);
61  for(TiXmlElement* cNode = node->FirstChildElement(); cNode; cNode = cNode->NextSiblingElement()) {
62  if(cNode->ValueStr() != "monster" && cNode->ValueStr() != "npc")
63  stdext::throw_exception(stdext::format("invalid spawn-subnode %s", cNode->ValueStr()));
64 
65  std::string cName = cNode->Attribute("name");
66  stdext::tolower(cName);
67  stdext::trim(cName);
68  stdext::ucwords(cName);
69 
70  if (!(cType = g_creatures.getCreatureByName(cName)))
71  continue;
72 
73  cType->setSpawnTime(cNode->readType<int>("spawntime"));
75  int16 dir_ = cNode->readType<int16>("direction");
76  if(dir_ >= Otc::East && dir_ <= Otc::West)
77  dir = (Otc::Direction)dir_;
78  cType->setDirection(dir);
79 
80  Position placePos;
81  placePos.x = centerPos.x + cNode->readType<int>("x");
82  placePos.y = centerPos.y + cNode->readType<int>("y");
83  placePos.z = cNode->readType<int>("z");
84 
85  cType->setRace(cNode->ValueStr() == "npc" ? CreatureRaceNpc : CreatureRaceMonster);
86  addCreature(placePos, cType);
87  }
88 }
89 
91 {
92  const Position& c = getCenterPos();
93  node->SetAttribute("centerx", c.x);
94  node->SetAttribute("centery", c.y);
95  node->SetAttribute("centerz", c.z);
96 
97  node->SetAttribute("radius", getRadius());
98 
99  TiXmlElement* creatureNode = nullptr;
100 
101  for(const auto& pair : m_creatures) {
102  const CreatureTypePtr& creature = pair.second;
103  if(!(creatureNode = new TiXmlElement(creature->getRace() == CreatureRaceNpc ? "npc" : "monster")))
104  stdext::throw_exception("Spawn::save: Ran out of memory while allocating XML element! Terminating now.");
105 
106  creatureNode->SetAttribute("name", creature->getName());
107  creatureNode->SetAttribute("spawntime", creature->getSpawnTime());
108  creatureNode->SetAttribute("direction", creature->getDirection());
109 
110  const Position& placePos = pair.first;
111  assert(placePos.isValid());
112 
113  creatureNode->SetAttribute("x", placePos.x - c.x);
114  creatureNode->SetAttribute("y", placePos.y - c.y);
115  creatureNode->SetAttribute("z", placePos.z);
116 
117  node->LinkEndChild(creatureNode);
118  }
119 }
120 
121 void Spawn::addCreature(const Position& placePos, const CreatureTypePtr& cType)
122 {
123  const Position& centerPos = getCenterPos();
124  int m_radius = getRadius();
125  if(!isInZone(placePos, centerPos, m_radius)) {
126  g_logger.warning(stdext::format("cannot place creature at %s (spawn's center position: %s, spawn radius: %d) (increment radius)",
127  stdext::to_string(placePos), stdext::to_string(centerPos),
128  m_radius
129  ));
130  return;
131  }
132 
133  g_map.addThing(cType->cast(), placePos, 4);
134  m_creatures.insert(std::make_pair(placePos, cType));
135 }
136 
138 {
139  auto iterator = m_creatures.find(pos);
140  if(iterator != m_creatures.end()) {
141  assert(iterator->first.isValid());
142  assert(g_map.removeThingByPos(iterator->first, 4));
143  m_creatures.erase(iterator);
144  }
145 }
146 
147 std::vector<CreatureTypePtr> Spawn::getCreatures()
148 {
149  std::vector<CreatureTypePtr> creatures;
150  for (auto p : m_creatures)
151  creatures.push_back(p.second);
152  return creatures;
153 }
154 
156 {
157  CreaturePtr ret(new Creature);
158 
159  std::string cName = getName();
160  stdext::tolower(cName);
161  stdext::trim(cName);
162  stdext::ucwords(cName);
163  ret->setName(cName);
164 
165  ret->setDirection(getDirection());
166  ret->setOutfit(getOutfit());
167  return ret;
168 }
169 
171 {
172  m_nullCreature = CreatureTypePtr(new CreatureType);
173 }
174 
176 {
177  for(auto pair : m_spawns)
178  pair.second->clear();
179  m_spawns.clear();
180 }
181 
182 void CreatureManager::loadMonsters(const std::string& file)
183 {
184  TiXmlDocument doc;
185  doc.Parse(g_resources.readFileContents(file).c_str());
186  if(doc.Error())
187  stdext::throw_exception(stdext::format("cannot open monsters file '%s': '%s'", file, doc.ErrorDesc()));
188 
189  TiXmlElement* root = doc.FirstChildElement();
190  if(!root || root->ValueStr() != "monsters")
191  stdext::throw_exception("malformed monsters xml file");
192 
193  for(TiXmlElement* monster = root->FirstChildElement(); monster; monster = monster->NextSiblingElement()) {
194  std::string fname = file.substr(0, file.find_last_of('/')) + '/' + monster->Attribute("file");
195  if(fname.substr(fname.length() - 4) != ".xml")
196  fname += ".xml";
197 
198  loadSingleCreature(fname);
199  }
200 
201  doc.Clear();
202  m_loaded = true;
203 }
204 
205 void CreatureManager::loadSingleCreature(const std::string& file)
206 {
208 }
209 
210 void CreatureManager::loadNpcs(const std::string& folder)
211 {
212  std::string tmp = folder;
213  if(!stdext::ends_with(tmp, "/"))
214  tmp += "/";
215 
216  if(!g_resources.directoryExists(tmp))
217  stdext::throw_exception(stdext::format("NPCs folder '%s' was not found.", folder));
218 
219  const auto& fileList = g_resources.listDirectoryFiles(tmp);
220  for(const std::string& file : fileList)
222 }
223 
224 void CreatureManager::loadSpawns(const std::string& fileName)
225 {
226  if(!isLoaded()) {
227  g_logger.warning("creatures aren't loaded yet to load spawns.");
228  return;
229  }
230 
231  if(m_spawnLoaded) {
232  g_logger.warning("attempt to reload spawns.");
233  return;
234  }
235 
236  try {
237  TiXmlDocument doc;
238  doc.Parse(g_resources.readFileContents(fileName).c_str());
239  if(doc.Error())
240  stdext::throw_exception(stdext::format("cannot load spawns xml file '%s: '%s'", fileName, doc.ErrorDesc()));
241 
242  TiXmlElement* root = doc.FirstChildElement();
243  if(!root || root->ValueStr() != "spawns")
244  stdext::throw_exception("malformed spawns file");
245 
246  for(TiXmlElement* node = root->FirstChildElement(); node; node = node->NextSiblingElement()) {
247  if(node->ValueTStr() != "spawn")
248  stdext::throw_exception("invalid spawn node");
249 
250  SpawnPtr spawn(new Spawn);
251  spawn->load(node);
252  m_spawns.insert(std::make_pair(spawn->getCenterPos(), spawn));
253  }
254  doc.Clear();
255  m_spawnLoaded = true;
256  } catch(std::exception& e) {
257  g_logger.error(stdext::format("Failed to load '%s': %s", fileName, e.what()));
258  }
259 }
260 
261 void CreatureManager::saveSpawns(const std::string& fileName)
262 {
263  try {
264  TiXmlDocument doc;
265  doc.SetTabSize(2);
266 
267  TiXmlDeclaration* decl = new TiXmlDeclaration("1.0", "UTF-8", "");
268  doc.LinkEndChild(decl);
269 
270  TiXmlElement* root = new TiXmlElement("spawns");
271  doc.LinkEndChild(root);
272 
273  for(auto pair : m_spawns) {
274  TiXmlElement* elem = new TiXmlElement("spawn");
275  pair.second->save(elem);
276  root->LinkEndChild(elem);
277  }
278 
279  if(!doc.SaveFile("data"+fileName))
280  stdext::throw_exception(stdext::format("failed to save spawns XML %s: %s", fileName, doc.ErrorDesc()));
281  } catch(std::exception& e) {
282  g_logger.error(stdext::format("Failed to save '%s': %s", fileName, e.what()));
283  }
284 }
285 
286 void CreatureManager::loadCreatureBuffer(const std::string& buffer)
287 {
288  TiXmlDocument doc;
289  doc.Parse(buffer.c_str());
290  if(doc.Error())
291  stdext::throw_exception(stdext::format("cannot load creature buffer: %s", doc.ErrorDesc()));
292 
293  TiXmlElement* root = doc.FirstChildElement();
294  if(!root || (root->ValueStr() != "monster" && root->ValueStr() != "npc"))
295  stdext::throw_exception("invalid root tag name");
296 
297  std::string cName = root->Attribute("name");
298  stdext::tolower(cName);
299  stdext::trim(cName);
300  stdext::ucwords(cName);
301 
302  CreatureTypePtr newType(new CreatureType(cName));
303  for(TiXmlElement* attrib = root->FirstChildElement(); attrib; attrib = attrib->NextSiblingElement()) {
304  if(attrib->ValueStr() != "look")
305  continue;
306 
307  internalLoadCreatureBuffer(attrib, newType);
308  break;
309  }
310 
311  doc.Clear();
312 }
313 
315 {
316  if(std::find(m_creatures.begin(), m_creatures.end(), m) != m_creatures.end())
317  return;
318 
319  Outfit out;
320 
321  int32 type = attrib->readType<int32>("type");
322  if(type > 0) {
324  out.setId(type);
325  } else {
327  out.setAuxId(attrib->readType<int32>("typeex"));
328  }
329 
330  {
331  out.setHead(attrib->readType<int>(("head")));
332  out.setBody(attrib->readType<int>(("body")));
333  out.setLegs(attrib->readType<int>(("legs")));
334  out.setFeet(attrib->readType<int>(("feet")));
335  out.setAddons(attrib->readType<int>(("addons")));
336  out.setMount(attrib->readType<int>(("mount")));
337  }
338 
339  m->setOutfit(out);
340  m_creatures.push_back(m);
341 }
342 
344 {
345  stdext::tolower(name);
346  stdext::trim(name);
347  stdext::ucwords(name);
348  auto it = std::find_if(m_creatures.begin(), m_creatures.end(),
349  [=] (const CreatureTypePtr& m) -> bool { return m->getName() == name; });
350  if(it != m_creatures.end())
351  return *it;
352  g_logger.warning(stdext::format("could not find creature with name: %s", name));
353  return m_nullCreature;
354 }
355 
357 {
358  auto findFun = [=] (const CreatureTypePtr& c) -> bool
359  {
360  const Outfit& o = c->getOutfit();
361  return o.getId() == look || o.getAuxId() == look;
362  };
363  auto it = std::find_if(m_creatures.begin(), m_creatures.end(), findFun);
364  if(it != m_creatures.end())
365  return *it;
366  g_logger.warning(stdext::format("could not find creature with looktype: %d", look));
367  return m_nullCreature;
368 }
369 
371 {
372  auto it = m_spawns.find(centerPos);
373  if(it != m_spawns.end())
374  return it->second;
375  g_logger.debug(stdext::format("failed to find spawn at center %s",stdext::to_string(centerPos)));
376  return nullptr;
377 }
378 
380 {
381  for (const auto& pair : m_spawns) {
382  const Position& centerPos = pair.first;
383  const SpawnPtr& spawn = pair.second;
384 
385  if (isInZone(pos, centerPos, spawn->getRadius()))
386  return spawn;
387  }
388 
389  return nullptr;
390 }
391 
392 SpawnPtr CreatureManager::addSpawn(const Position& centerPos, int radius)
393 {
394  auto iter = m_spawns.find(centerPos);
395  if(iter != m_spawns.end()) {
396  if(iter->second->getRadius() != radius)
397  iter->second->setRadius(radius);
398  return iter->second;
399  }
400 
401  SpawnPtr ret(new Spawn);
402 
403  ret->setRadius(radius);
404  ret->setCenterPos(centerPos);
405 
406  m_spawns.insert(std::make_pair(centerPos, ret));
407  return ret;
408 }
409 
411 {
412  const Position& centerPos = spawn->getCenterPos();
413  auto it = m_spawns.find(centerPos);
414  if(it != m_spawns.end())
415  m_spawns.erase(it);
416 }
417 
418 std::vector<SpawnPtr> CreatureManager::getSpawns()
419 {
420  std::vector<SpawnPtr> spawns;
421  for (auto p : m_spawns)
422  spawns.push_back(p.second);
423  return spawns;
424 }
425 
426 /* vim: set ts=4 sw=4 et: */
Spawn::getCenterPos
Position getCenterPos()
Definition: creatures.h:62
ResourceManager::listDirectoryFiles
std::list< std::string > listDirectoryFiles(const std::string &directoryPath="")
Definition: resourcemanager.cpp:268
CreatureManager::getCreatureByLook
const CreatureTypePtr & getCreatureByLook(int look)
Definition: creatures.cpp:356
CreatureType::setRace
void setRace(CreatureRace race)
Definition: creatures.h:97
Spawn::getRadius
int32 getRadius()
Definition: creatures.h:59
g_map
Map g_map
Definition: map.cpp:36
CreatureType
Definition: creatures.h:79
CreatureManager::clearSpawns
void clearSpawns()
Definition: creatures.cpp:175
Outfit::setBody
void setBody(int body)
Definition: outfit.h:44
CreatureRaceNpc
@ CreatureRaceNpc
Definition: creatures.h:42
TiXmlNode::NextSiblingElement
const TiXmlElement * NextSiblingElement() const
Definition: tinyxml.cpp:476
Proto::CreatureType
CreatureType
Definition: protocolcodes.h:276
Outfit::setFeet
void setFeet(int feet)
Definition: outfit.h:46
CreatureManager::getCreatureByName
const CreatureTypePtr & getCreatureByName(std::string name)
Definition: creatures.cpp:343
Outfit::getId
int getId() const
Definition: outfit.h:53
Outfit::setAddons
void setAddons(int addons)
Definition: outfit.h:47
Otc::North
@ North
Definition: const.h:162
TiXmlNode::ValueStr
const std::string & ValueStr() const
Definition: tinyxml.h:501
CreatureType::setDirection
void setDirection(Otc::Direction dir)
Definition: creatures.h:94
Position::x
int x
Definition: position.h:243
stdext::ucwords
void ucwords(std::string &str)
Definition: string.cpp:245
Position::isValid
bool isValid() const
Definition: position.h:182
CreatureType::getRace
CreatureRace getRace()
Definition: creatures.h:98
Creature::setDirection
void setDirection(Otc::Direction direction)
Definition: creature.cpp:659
TiXmlNode::LinkEndChild
TiXmlNode * LinkEndChild(TiXmlNode *addThis)
Definition: tinyxml.cpp:186
Creature
Definition: creature.h:37
ResourceManager::directoryExists
bool directoryExists(const std::string &directoryName)
Definition: resourcemanager.cpp:163
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
TiXmlDeclaration
Definition: tinyxml.h:1202
CreatureType::getName
std::string getName()
Definition: creatures.h:89
resourcemanager.h
tinyxml.h
Logger::error
void error(const std::string &what)
Definition: logger.h:54
Outfit::setCategory
void setCategory(ThingCategory category)
Definition: outfit.h:49
Spawn::addCreature
void addCreature(const Position &placePos, const CreatureTypePtr &cType)
Definition: creatures.cpp:121
CreatureType::setSpawnTime
void setSpawnTime(int32 spawnTime)
Definition: creatures.h:85
Spawn::setCenterPos
void setCenterPos(const Position &pos)
Definition: creatures.h:61
CreatureManager
Definition: creatures.h:106
Position::y
int y
Definition: position.h:244
Spawn
Definition: creatures.h:52
CreatureRaceMonster
@ CreatureRaceMonster
Definition: creatures.h:43
stdext::format
std::string format()
Definition: format.h:82
CreatureManager::deleteSpawn
void deleteSpawn(const SpawnPtr &spawn)
Definition: creatures.cpp:410
g_creatures
CreatureManager g_creatures
Definition: creatures.cpp:30
creature.h
Outfit::setAuxId
void setAuxId(int id)
Definition: outfit.h:42
Position::z
short z
Definition: position.h:245
TiXmlElement::Attribute
std::string Attribute(const std::string &name) const
Definition: tinyxml.cpp:558
Spawn::setRadius
void setRadius(int32 r)
Definition: creatures.h:58
CreatureManager::CreatureManager
CreatureManager()
Definition: creatures.cpp:170
TiXmlDocument::SetTabSize
void SetTabSize(int _tabsize)
Definition: tinyxml.h:1421
g_resources
ResourceManager g_resources
Definition: resourcemanager.cpp:32
Otc::Direction
Direction
Definition: const.h:161
Outfit
Definition: outfit.h:29
CreatureManager::saveSpawns
void saveSpawns(const std::string &fileName)
Definition: creatures.cpp:261
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
CreatureType::cast
CreaturePtr cast()
Definition: creatures.cpp:155
g_logger
Logger g_logger
Definition: logger.cpp:35
TiXmlDocument::SaveFile
bool SaveFile() const
Save a file using the current document value. Returns true if successful.
Definition: tinyxml.cpp:763
TiXmlDocument
Definition: tinyxml.h:1310
int32
int32_t int32
Definition: types.h:39
Otc::West
@ West
Definition: const.h:165
CreatureManager::terminate
void terminate()
Definition: creatures.cpp:43
Outfit::setId
void setId(int id)
Definition: outfit.h:41
Map::addThing
void addThing(const ThingPtr &thing, const Position &pos, int stackPos=-1)
Definition: map.cpp:107
Position
Definition: position.h:33
TiXmlNode::FirstChildElement
const TiXmlElement * FirstChildElement() const
Convenience function to get through elements.
Definition: tinyxml.cpp:446
CreatureManager::getSpawns
std::vector< SpawnPtr > getSpawns()
Definition: creatures.cpp:418
Creature::setName
void setName(const std::string &name)
Definition: creature.cpp:631
Outfit::setHead
void setHead(int head)
Definition: outfit.h:43
CreatureManager::loadNpcs
void loadNpcs(const std::string &folder)
Definition: creatures.cpp:210
CreatureTypePtr
stdext::shared_object_ptr< CreatureType > CreatureTypePtr
Definition: declarations.h:77
Spawn::save
void save(TiXmlElement *node)
Definition: creatures.cpp:90
CreatureManager::loadCreatureBuffer
void loadCreatureBuffer(const std::string &buffer)
Definition: creatures.cpp:286
Outfit::setMount
void setMount(int mount)
Definition: outfit.h:48
ThingCategoryItem
@ ThingCategoryItem
Definition: thingtype.h:43
TiXmlElement::SetAttribute
void SetAttribute(const std::string &name, const std::string &_value)
Definition: tinyxml.cpp:594
CreatureType::setOutfit
void setOutfit(const Outfit &o)
Definition: creatures.h:91
CreatureType::getSpawnTime
int32 getSpawnTime()
Definition: creatures.h:86
map.h
stdext::trim
void trim(std::string &str)
Definition: string.cpp:226
Spawn::getCreatures
std::vector< CreatureTypePtr > getCreatures()
Definition: creatures.cpp:147
TiXmlElement::readType
T readType(const std::string &str) const
Definition: tinyxml.h:953
stdext::throw_exception
void throw_exception(const std::string &what)
Throws a generic exception.
Definition: exception.h:43
stdext::ends_with
bool ends_with(const std::string &str, const std::string &test)
Definition: string.cpp:258
ResourceManager::readFileContents
std::string readFileContents(const std::string &fileName)
Definition: resourcemanager.cpp:185
stdext::to_string
std::string to_string(const T &t)
Definition: string.h:35
CreatureManager::loadSpawns
void loadSpawns(const std::string &fileName)
Definition: creatures.cpp:224
CreatureManager::isLoaded
bool isLoaded()
Definition: creatures.h:130
CreatureManager::getSpawnForPlacePos
SpawnPtr getSpawnForPlacePos(const Position &pos)
Definition: creatures.cpp:379
CreatureType::getOutfit
Outfit getOutfit()
Definition: creatures.h:92
CreatureManager::clear
void clear()
Definition: creatures.h:110
Logger::debug
void debug(const std::string &what)
Definition: logger.h:51
CreatureManager::loadMonsters
void loadMonsters(const std::string &file)
Definition: creatures.cpp:182
Outfit::getAuxId
int getAuxId() const
Definition: outfit.h:54
stdext::shared_object_ptr< CreatureType >
Otc::East
@ East
Definition: const.h:163
CreatureType::getDirection
Otc::Direction getDirection()
Definition: creatures.h:95
Map::removeThingByPos
bool removeThingByPos(const Position &pos, int stackPos)
Definition: map.cpp:212
CreatureManager::getSpawn
SpawnPtr getSpawn(const Position &centerPos)
Definition: creatures.cpp:370
CreatureManager::loadSingleCreature
void loadSingleCreature(const std::string &file)
Definition: creatures.cpp:205
TiXmlElement
Definition: tinyxml.h:943
CreatureManager::internalLoadCreatureBuffer
void internalLoadCreatureBuffer(TiXmlElement *attrib, const CreatureTypePtr &m)
Definition: creatures.cpp:314
TiXmlDocument::Error
bool Error() const
Definition: tinyxml.h:1377
creatures.h
int16
int16_t int16
Definition: types.h:40
stdext::tolower
void tolower(std::string &str)
Definition: string.cpp:216
Creature::setOutfit
void setOutfit(const Outfit &outfit)
Definition: creature.cpp:665
Spawn::removeCreature
void removeCreature(const Position &pos)
Definition: creatures.cpp:137
Spawn::load
void load(TiXmlElement *node)
Definition: creatures.cpp:50
CreatureManager::addSpawn
SpawnPtr addSpawn(const Position &centerPos, int radius)
Definition: creatures.cpp:392
Outfit::setLegs
void setLegs(int legs)
Definition: outfit.h:45
Logger::warning
void warning(const std::string &what)
Definition: logger.h:53