The Battle for Wesnoth  1.13.4+dev
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
info.cpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2012 - 2016 by Ignacio Riquelme Morelle <[email protected]>
3  Part of the Battle for Wesnoth Project http://www.wesnoth.org/
4 
5  This program is free software; you can redistribute it and/or modify
6  it under the terms of the GNU General Public License as published by
7  the Free Software Foundation; either version 2 of the License, or
8  (at your option) any later version.
9  This program is distributed in the hope that it will be useful,
10  but WITHOUT ANY WARRANTY.
11 
12  See the COPYING file for more details.
13 */
14 
15 #include "addon/info.hpp"
16 
17 #include "addon/manager.hpp"
18 #include "game_config.hpp"
19 #include "config.hpp"
20 #include "gettext.hpp"
21 #include "image.hpp"
22 #include "log.hpp"
24 
25 static lg::log_domain log_addons_client("addons-client");
26 #define ERR_AC LOG_STREAM(err , log_addons_client)
27 #define LOG_AC LOG_STREAM(info, log_addons_client)
28 
29 namespace {
30  const std::string fallback_addon_icon = "misc/blank-hex.png";
31 
32  void resolve_deps_recursive(const addons_list& addons, const std::string& base_id, std::set<std::string>& dest)
33  {
34  addons_list::const_iterator it = addons.find(base_id);
35  if(it == addons.end()) {
36  LOG_AC << "resolve_deps_recursive(): " << base_id << " not in add-ons list\n";
37  return;
38  }
39 
40  const std::vector<std::string>& base_deps = it->second.depends;
41 
42  if(base_deps.empty()) {
43  return;
44  }
45 
46  for(const std::string& dep : base_deps) {
47  if(base_id == dep) {
48  LOG_AC << dep << " depends upon itself; breaking circular dependency\n";
49  continue;
50  } else if(dest.find(dep) != dest.end()) {
51  LOG_AC << dep << " already in dependency tree; breaking circular dependency\n";
52  continue;
53  }
54 
55  dest.insert(dep);
56 
57  resolve_deps_recursive(addons, dep, dest);
58  }
59  }
60 }
61 
62 void addon_info::read(const config& cfg)
63 {
64  this->id = cfg["name"].str();
65  this->title = cfg["title"].str();
66  this->description = cfg["description"].str();
67  this->icon = cfg["icon"].str();
68  this->version = cfg["version"].str();
69  this->author = cfg["author"].str();
70  this->size = cfg["size"];
71  this->downloads = cfg["downloads"];
72  this->uploads = cfg["uploads"];
73  this->type = get_addon_type(cfg["type"].str());
74 
75  const config::const_child_itors& locales = cfg.child_range("translation");
76 
77  for(const config& locale : locales) {
78  this->locales.push_back(locale["language"].str());
79  }
80 
81  this->core = cfg["core"].str();
82  this->depends = utils::split(cfg["dependencies"].str());
83  this->feedback_url = cfg["feedback_url"].str();
84 
85  this->updated = cfg["timestamp"].to_time_t();
86  this->created = cfg["original_timestamp"].to_time_t();
87 }
88 
89 void addon_info::write(config& cfg) const
90 {
91  cfg["id"] = this->id;
92  cfg["title"] = this->title;
93  cfg["description"] = this->description;
94  cfg["icon"] = this->icon;
95  cfg["version"] = this->version.str();
96  cfg["author"] = this->author;
97  cfg["size"] = this->size;
98  cfg["downloads"] = this->downloads;
99  cfg["uploads"] = this->uploads;
100  cfg["type"] = get_addon_type_string(this->type);
101 
102  for (const std::string& locale_id : this->locales) {
103  cfg.add_child("translation")["language"] = locale_id;
104  }
105 
106  cfg["core"] = this->core;
107  cfg["dependencies"] = utils::join(this->depends);
108  cfg["feedback_url"] = this->feedback_url;
109 
110  cfg["timestamp"] = this->updated;
111  cfg["original_timestamp"] = this->created;
112 }
113 
115 {
116  cfg["version"] = this->version.str();
117  cfg["uploads"] = this->uploads;
118  cfg["type"] = get_addon_type_string(this->type);
119  cfg["title"] = this->title;
120  cfg["dependencies"] = utils::join(this->depends);
121  cfg["core"] = this->core;
122 }
123 
125 {
126  if(this->title.empty()) {
127  return make_addon_title(this->id);
128  } else {
129  return this->title;
130  }
131 }
132 
134 {
135  std::string ret = icon;
136 
137  if(ret.empty()) {
138  ERR_AC << "add-on '" << id << "' doesn't have an icon path set" << std::endl;
139  ret = fallback_addon_icon;
140  }
141  else if(!image::exists(ret)) {
142  ERR_AC << "add-on '" << id << "' has an icon which cannot be found: '" << ret << "'" << std::endl;
143  ret = game_config::debug ? game_config::images::missing : fallback_addon_icon;
144  }
145  else if(ret.find("units/") != std::string::npos && ret.find_first_of('~') == std::string::npos) {
146  // HACK: prevent magenta icons, because they look awful
147  LOG_AC << "add-on '" << id << "' uses a unit baseframe as icon without TC/RC specifications\n";
148  ret += "~RC(magenta>red)";
149  }
150 
151  return ret;
152 }
153 
155 {
156  switch (type) {
157  case ADDON_SP_CAMPAIGN:
158  return _("addon_type^Campaign");
159  case ADDON_SP_SCENARIO:
160  return _("addon_type^Scenario");
162  return _("addon_type^SP/MP Campaign");
163  case ADDON_MP_ERA:
164  return _("addon_type^MP era");
165  case ADDON_MP_FACTION:
166  return _("addon_type^MP faction");
167  case ADDON_MP_MAPS:
168  return _("addon_type^MP map-pack");
169  case ADDON_MP_SCENARIO:
170  return _("addon_type^MP scenario");
171  case ADDON_MP_CAMPAIGN:
172  return _("addon_type^MP campaign");
173  case ADDON_MP_MOD:
174  return _("addon_type^MP modification");
175  case ADDON_CORE:
176  return _("addon_type^Core");
177  case ADDON_MEDIA:
178  return _("addon_type^Resources");
179  case ADDON_OTHER:
180  return _("addon_type^Other");
181  default:
182  return _("addon_type^(unknown)");
183  }
184 }
185 
186 std::set<std::string> addon_info::resolve_dependencies(const addons_list& addons) const
187 {
188  std::set<std::string> deps;
189  resolve_deps_recursive(addons, this->id, deps);
190 
191  if(deps.find(this->id) != deps.end()) {
192  LOG_AC << this->id << " depends upon itself; breaking circular dependency\n";
193  deps.erase(this->id);
194  }
195 
196  return deps;
197 }
198 
199 void read_addons_list(const config& cfg, addons_list& dest)
200 {
201  dest.clear();
202 
203  unsigned order = 0;
204 
205  /** @todo FIXME: get rid of this legacy "campaign"/"campaigns" silliness
206  */
207  const config::const_child_itors &addon_cfgs = cfg.child_range("campaign");
208  for(const config& addon_cfg : addon_cfgs) {
209  const std::string& id = addon_cfg["name"].str();
210  if(dest.find(id) != dest.end()) {
211  ERR_AC << "add-ons list has multiple entries for '" << id << "', not good; ignoring them" << std::endl;
212  continue;
213  }
214  dest[id].read(addon_cfg);
215  dest[id].order = order++;
216  }
217 }
218 
220 {
221  if(size > 0.0) {
222  return utils::si_string(size, true, _("unit_byte^B"));
223  } else {
224  return "";
225  }
226 }
227 
229 {
230  std::string ret(id);
231  std::replace(ret.begin(), ret.end(), '_', ' ');
232  return ret;
233 }
int size
Definition: info.hpp:41
child_itors child_range(const std::string &key)
Definition: config.cpp:613
std::string si_string(double input, bool base2, std::string unit)
Convert into a string with an SI-postfix.
Single-player scenario.
Definition: validation.hpp:45
void read_addons_list(const config &cfg, addons_list &dest)
Definition: info.cpp:199
GLuint GLdouble GLdouble GLint GLint order
Definition: glew.h:2972
an add-on that fits in no other category
Definition: validation.hpp:56
Total Conversion Core.
Definition: validation.hpp:43
GLuint GLuint GLsizei GLenum type
Definition: glew.h:1221
std::string size_display_string(double size)
Get a human-readable representation of the specified byte count.
Definition: info.cpp:219
std::string description
Definition: info.hpp:33
Multiplayer faction.
Definition: validation.hpp:51
#define LOG_AC
Definition: info.cpp:27
static lg::log_domain log_addons_client("addons-client")
std::string feedback_url
Definition: info.hpp:54
Definitions for the interface to Wesnoth Markup Language (WML).
time_t created
Definition: info.hpp:57
std::pair< const_child_iterator, const_child_iterator > const_child_itors
Definition: config.hpp:214
void write_minimal(config &cfg) const
Write only minimal WML used for state tracking (_info.cfg) files.
Definition: info.cpp:114
bool exists(const image::locator &i_locator)
returns true if the given image actually exists, without loading it.
Definition: image.cpp:1187
static UNUSEDNOWARN std::string _(const char *str)
Definition: gettext.hpp:82
GLuint id
Definition: glew.h:1647
std::string display_title() const
Get a title or automatic title for display.
Definition: info.cpp:124
std::map< std::string, addon_info > addons_list
Definition: info.hpp:26
std::string id
Definition: info.hpp:31
config & add_child(const std::string &key)
Definition: config.cpp:743
#define ERR_AC
Definition: info.cpp:26
Modification of the game for MP.
Definition: validation.hpp:53
ADDON_TYPE get_addon_type(const std::string &str)
Definition: validation.cpp:82
std::string join(T const &v, const std::string &s=",")
Generates a new string joining container items in a list.
std::string str() const
Serializes the version number into string form.
Definition: version.cpp:90
Miscellaneous content/media (unit packs, terrain packs, music packs, etc.).
Definition: validation.hpp:55
std::string display_icon() const
Get an icon path fixed for display (e.g.
Definition: info.cpp:133
void read(const config &cfg)
Definition: info.cpp:62
std::vector< std::string > locales
Definition: info.hpp:47
Multiplayer scenario.
Definition: validation.hpp:48
Multiplayer era.
Definition: validation.hpp:50
std::string icon
Definition: info.hpp:35
std::string display_type() const
Get an add-on type identifier for display in the user's language.
Definition: info.cpp:154
int uploads
Definition: info.hpp:43
Multiplayer plain (no WML) map pack.
Definition: validation.hpp:49
std::string replace(std::string str, const std::string &src, const std::string &dst)
Replace all instances of src in str with dst.
void write(config &cfg) const
Definition: info.cpp:89
GLsizeiptr size
Definition: glew.h:1649
std::string make_addon_title(const std::string &id)
Replaces underscores to dress up file or dirnames as add-on titles.
Definition: info.cpp:228
std::vector< std::string > depends
Definition: info.hpp:51
Hybrid campaign.
Definition: validation.hpp:46
std::string title
Definition: info.hpp:32
Standard logging facilities (interface).
version_info version
Definition: info.hpp:37
std::vector< std::string > split(std::string const &val, const char c, const int flags)
Splits a (comma-)separated string into a vector of pieces.
std::string get_addon_type_string(ADDON_TYPE type)
Definition: validation.cpp:98
int downloads
Definition: info.hpp:42
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:83
Single-player campaign.
Definition: validation.hpp:44
GLsizei const GLcharARB ** string
Definition: glew.h:4503
std::set< std::string > resolve_dependencies(const addons_list &addons) const
Resolve an add-on's dependency tree in a recursive fashion.
Definition: info.cpp:186
Multiplayer campaign.
Definition: validation.hpp:47
std::string author
Definition: info.hpp:39
time_t updated
Definition: info.hpp:56
std::string core
Definition: info.hpp:49