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