ManaPlus
emotedb.cpp
Go to the documentation of this file.
1 /*
2  * The ManaPlus Client
3  * Copyright (C) 2009 Aethyra Development Team
4  * Copyright (C) 2011-2019 The ManaPlus Developers
5  *
6  * This file is part of The ManaPlus Client.
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License as published by
10  * the Free Software Foundation; either version 2 of the License, or
11  * any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program. If not, see <http://www.gnu.org/licenses/>.
20  */
21 
22 #include "resources/db/emotedb.h"
23 
24 #include "client.h"
25 
26 #include "configuration.h"
27 
28 #include "utils/checkutils.h"
29 
30 #include "resources/beingcommon.h"
31 #include "resources/emoteinfo.h"
32 #include "resources/emotesprite.h"
33 
35 
36 #include "debug.h"
37 
38 namespace
39 {
43  bool mLoaded = false;
44  int mLastEmote = 0;
45 } // namespace
46 
48 {
49  if (mLoaded)
50  unload();
51 
52  logger->log1("Initializing emote database...");
53 
54  EmoteSprite *const unknownSprite = new EmoteSprite;
56  "sprites"), paths.getStringValue(
57  "spriteErrorFile")),
58  0);
59  unknownSprite->name = "unknown";
60  unknownSprite->id = 0;
61  mUnknown.sprites.push_back(unknownSprite);
62 
63  mLastEmote = 0;
65  loadXmlFile(paths.getStringValue("emotesPatchFile"), SkipError_true);
66  loadXmlDir("emotesPatchDir", loadXmlFile)
67  loadSpecialXmlFile("graphics/sprites/manaplus_emotes.xml",
69 
70  mLoaded = true;
71 }
72 
73 void EmoteDB::loadXmlFile(const std::string &fileName,
74  const SkipError skipError)
75 {
76  XML::Document doc(fileName, UseVirtFs_true, skipError);
77  XmlNodePtrConst rootNode = doc.rootNode();
78 
79  if ((rootNode == nullptr) || !xmlNameEqual(rootNode, "emotes"))
80  {
81  logger->log("Emote Database: Error while loading %s!",
82  fileName.c_str());
83  return;
84  }
85 
86  // iterate <emote>s
87  for_each_xml_child_node(emoteNode, rootNode)
88  {
89  if (xmlNameEqual(emoteNode, "include"))
90  {
91  const std::string name = XML::getProperty(emoteNode, "name", "");
92  if (!name.empty())
93  loadXmlFile(name, skipError);
94  continue;
95  }
96  else if (!xmlNameEqual(emoteNode, "emote"))
97  {
98  continue;
99  }
100 
101  const int id = XML::getProperty(emoteNode, "id", -1);
102  // skip hight images
103  if (id > 19 || (Client::isTmw() && id > 13))
104  continue;
105 
106  if (id == -1)
107  {
108  reportAlways("Emote Database: Emote with missing ID in %s!",
109  paths.getStringValue("emotesFile").c_str())
110  continue;
111  }
112  EmoteInfo *currentInfo = nullptr;
113  if (mEmoteInfos.find(id) != mEmoteInfos.end())
114  currentInfo = mEmoteInfos[id];
115  else
116  currentInfo = new EmoteInfo;
117  if (currentInfo == nullptr)
118  continue;
119  currentInfo->time = XML::getProperty(emoteNode, "time", 500);
120  currentInfo->effectId = XML::getProperty(emoteNode, "effect", -1);
121 
122  for_each_xml_child_node(spriteNode, emoteNode)
123  {
124  if (!XmlHaveChildContent(spriteNode))
125  continue;
126 
127  if (xmlNameEqual(spriteNode, "sprite"))
128  {
129  EmoteSprite *const currentSprite = new EmoteSprite;
130  currentSprite->sprite = AnimatedSprite::load(pathJoin(
131  paths.getStringValue("sprites"),
132  XmlChildContent(spriteNode)),
133  XML::getProperty(spriteNode, "variant", 0));
134  currentSprite->name = XML::langProperty(
135  spriteNode, "name", "");
136  currentSprite->id = id;
137  currentInfo->sprites.push_back(currentSprite);
138  }
139  else if (xmlNameEqual(spriteNode, "particlefx"))
140  {
141  currentInfo->particles.push_back(XmlChildContent(spriteNode));
142  }
143  }
144  mEmoteInfos[id] = currentInfo;
145  if (id > mLastEmote)
146  mLastEmote = id;
147  }
148 }
149 
150 void EmoteDB::loadSpecialXmlFile(const std::string &fileName,
151  const SkipError skipError)
152 {
153  XML::Document doc(fileName, UseVirtFs_true, skipError);
154  XmlNodePtrConst rootNode = doc.rootNode();
155 
156  if ((rootNode == nullptr) || !xmlNameEqual(rootNode, "emotes"))
157  {
158  logger->log1("Emote Database: Error while loading"
159  " manaplus_emotes.xml!");
160  return;
161  }
162 
163  // iterate <emote>s
164  for_each_xml_child_node(emoteNode, rootNode)
165  {
166  if (xmlNameEqual(emoteNode, "include"))
167  {
168  const std::string name = XML::getProperty(emoteNode, "name", "");
169  if (!name.empty())
170  loadSpecialXmlFile(name, skipError);
171  continue;
172  }
173  else if (!xmlNameEqual(emoteNode, "emote"))
174  {
175  continue;
176  }
177 
178  const int id = XML::getProperty(emoteNode, "id", -1);
179  if (id == -1)
180  {
181  reportAlways("Emote Database: Emote with missing ID in "
182  "manaplus_emotes.xml!")
183  continue;
184  }
185  const int altId = XML::getProperty(emoteNode, "altid", -1);
186 
187  EmoteInfo *currentInfo = nullptr;
188  if (mEmoteInfos.find(id) != mEmoteInfos.end())
189  currentInfo = mEmoteInfos[id];
190  if (currentInfo == nullptr)
191  currentInfo = new EmoteInfo;
192  currentInfo->time = XML::getProperty(emoteNode, "time", 500);
193  currentInfo->effectId = XML::getProperty(emoteNode, "effect", -1);
194 
195  for_each_xml_child_node(spriteNode, emoteNode)
196  {
197  if (!XmlHaveChildContent(spriteNode))
198  continue;
199 
200  if (xmlNameEqual(spriteNode, "sprite"))
201  {
202  EmoteSprite *const currentSprite = new EmoteSprite;
203  currentSprite->sprite = AnimatedSprite::load(pathJoin(
204  paths.getStringValue("sprites"),
205  XmlChildContent(spriteNode)),
206  XML::getProperty(spriteNode, "variant", 0));
207  currentSprite->name = XML::langProperty(
208  spriteNode, "name", "");
209  currentSprite->id = id;
210  currentInfo->sprites.push_back(currentSprite);
211  }
212  else if (xmlNameEqual(spriteNode, "particlefx"))
213  {
214  currentInfo->particles.push_back(XmlChildContent(spriteNode));
215  }
216  }
217  mEmoteInfos[id] = currentInfo;
218  if (altId != -1)
219  mEmotesAlt[altId] = id;
220 
221  if (id > mLastEmote)
222  mLastEmote = id;
223  }
224 }
225 
227 {
228  logger->log1("Unloading emote database...");
229  FOR_EACH (EmoteInfos::const_iterator, i, mEmoteInfos)
230  {
231  if (i->second != nullptr)
232  {
233  std::list<EmoteSprite*> &sprites = i->second->sprites;
234  while (!sprites.empty())
235  {
236  delete sprites.front()->sprite;
237  delete sprites.front();
238  sprites.pop_front();
239  }
240  delete i->second;
241  }
242  }
243 
244  mEmoteInfos.clear();
245 
246  std::list<EmoteSprite*> &sprites = mUnknown.sprites;
247  while (!sprites.empty())
248  {
249  delete sprites.front()->sprite;
250  delete sprites.front();
251  sprites.pop_front();
252  }
253 
254  mLoaded = false;
255 }
256 
257 const EmoteInfo *EmoteDB::get(const int id, const bool allowNull)
258 {
259  const EmoteInfos::const_iterator i = mEmoteInfos.find(id);
260 
261  if (i == mEmoteInfos.end())
262  {
263  if (allowNull)
264  return nullptr;
265  reportAlways("EmoteDB: Warning, unknown emote ID %d requested",
266  id)
267  return &mUnknown;
268  }
269  return i->second;
270 }
271 
272 const EmoteInfo *EmoteDB::get2(int id, const bool allowNull)
273 {
274  const EmoteToEmote::const_iterator it = mEmotesAlt.find(id);
275  if (it != mEmotesAlt.end())
276  id = (*it).second;
277 
278  const EmoteInfos::const_iterator i = mEmoteInfos.find(id);
279 
280  if (i == mEmoteInfos.end())
281  {
282  if (allowNull)
283  return nullptr;
284  reportAlways("EmoteDB: Warning, unknown emote ID %d requested",
285  id)
286  return &mUnknown;
287  }
288  return i->second;
289 }
290 
291 const EmoteSprite *EmoteDB::getSprite(const int id, const bool allowNull)
292 {
293  const EmoteInfo *const info = get(id, allowNull);
294  if (info == nullptr)
295  return nullptr;
296 
297  return info->sprites.front();
298 }
299 
300 const int &EmoteDB::getLast()
301 {
302  return mLastEmote;
303 }
304 
306 {
307  return static_cast<signed int>(mEmoteInfos.size());
308 }
309 
310 int EmoteDB::getIdByIndex(const int index)
311 {
312  if (index < 0 || index >= static_cast<signed int>(mEmoteInfos.size()))
313  return 0;
314  EmoteInfos::const_iterator it = mEmoteInfos.begin();
315  for (int f = 0; f < index; f ++)
316  ++ it;
317  return (*it).first;
318 }
SkipError
bool SkipError
Definition: skiperror.h:29
EmoteDB::getSprite
const EmoteSprite * getSprite(const int id, const bool allowNull)
Definition: emotedb.cpp:291
EmoteInfos
std::map< int, EmoteInfo * > EmoteInfos
Definition: emotedb.h:33
reportAlways
#define reportAlways(...)
Definition: checkutils.h:252
anonymous_namespace{emotedb.cpp}::mUnknown
EmoteInfo mUnknown
Definition: emotedb.cpp:42
emotedb.h
anonymous_namespace{emotedb.cpp}::mEmotesAlt
EmoteToEmote mEmotesAlt
Definition: emotedb.cpp:41
SkipError_true
const bool SkipError_true
Definition: skiperror.h:29
EmoteDB::getLast
const int & getLast() A_CONST
Definition: emotedb.cpp:300
Client::isTmw
static bool isTmw()
Definition: client.cpp:837
anonymous_namespace{emotedb.cpp}::mEmoteInfos
EmoteInfos mEmoteInfos
Definition: emotedb.cpp:40
Net::unload
void unload()
Definition: net.cpp:179
EmoteDB::load
void load()
Definition: emotedb.cpp:47
EmoteDB::loadSpecialXmlFile
void loadSpecialXmlFile(const std::string &fileName, const SkipError skipError)
Definition: emotedb.cpp:150
paths
Configuration paths
Definition: configuration.cpp:55
AttributesEnum::get
AttributesT get(const std::string &key)
Definition: attributesstrings.cpp:32
SkipError_false
const bool SkipError_false
Definition: skiperror.h:29
AnimatedSprite::load
static AnimatedSprite * load(const std::string &filename, const int variant)
Definition: animatedsprite.cpp:71
pathJoin
std::string pathJoin(std::string str1, const std::string &str2)
Definition: stringutils.cpp:1036
XML::Document
Definition: libxml.h:52
XML::getProperty
int getProperty(const xmlNodePtr node, const char *const name, int def)
Definition: libxml.cpp:173
animatedsprite.h
logger
Logger * logger
Definition: logger.cpp:88
Actions::info
bool info(InputEvent &event)
Definition: commands.cpp:56
fileName
std::string fileName
Definition: testmain.cpp:38
emoteinfo.h
loadXmlDir
#define loadXmlDir(name, function)
Definition: beingcommon.h:38
checkutils.h
EmoteDB::loadXmlFile
void loadXmlFile(const std::string &fileName, const SkipError skipError)
Definition: emotedb.cpp:73
beingcommon.h
EmoteInfo::effectId
int effectId
Definition: emoteinfo.h:47
loadXmlFile
static void loadXmlFile(const std::string &file, const std::string &name, BadgesInfos &arr, const SkipError skipError)
Definition: badgesdb.cpp:42
UseVirtFs_true
const bool UseVirtFs_true
Definition: usevirtfs.h:29
EmoteSprite::sprite
const AnimatedSprite * sprite
Definition: emotesprite.h:41
Configuration::getStringValue
std::string getStringValue(const std::string &key) const
Definition: configuration.cpp:487
anonymous_namespace{emotedb.cpp}::mLoaded
bool mLoaded
Definition: emotedb.cpp:43
emotesprite.h
XML::langProperty
std::string langProperty(const xmlNodePtr node, const char *const name, const std::string &def)
Definition: libxml.cpp:257
Logger::log1
void log1(const char *const log_text)
Definition: logger.cpp:237
EmoteDB::get2
const EmoteInfo * get2(int id, const bool allowNull)
Definition: emotedb.cpp:272
EmoteSprite::name
std::string name
Definition: emotesprite.h:43
EmoteDB::size
int size()
Definition: emotedb.cpp:305
EmoteDB::unload
void unload()
Definition: emotedb.cpp:226
EmoteToEmote
std::map< int, int > EmoteToEmote
Definition: emotedb.h:36
EmoteSprite::id
int id
Definition: emotesprite.h:42
configuration.h
anonymous_namespace{emotedb.cpp}::mLastEmote
int mLastEmote
Definition: emotedb.cpp:44
EmoteSprite
Definition: emotesprite.h:31
EmoteDB::getIdByIndex
int getIdByIndex(const int index)
Definition: emotedb.cpp:310
XML::Document::rootNode
xmlNodePtr rootNode()
Definition: libxml.cpp:168
EmoteInfo
Definition: emoteinfo.h:33
EmoteInfo::time
int time
Definition: emoteinfo.h:46
EmoteInfo::sprites
std::list< EmoteSprite * > sprites
Definition: emoteinfo.h:44
for_each_xml_child_node
#define for_each_xml_child_node(var, parent)
Definition: libxml.h:160
EmoteInfo::particles
StringVect particles
Definition: emoteinfo.h:45
client.h
Logger::log
void log(const char *const log_text,...)
Definition: logger.cpp:268
FOR_EACH
#define FOR_EACH(type, iter, array)
Definition: foreach.h:24
debug.h
EmoteDB::get
const EmoteInfo * get(const int id, const bool allowNull)
Definition: emotedb.cpp:257