ManaPlus
configmanager.cpp
Go to the documentation of this file.
1 /*
2  * The ManaPlus Client
3  * Copyright (C) 2004-2009 The Mana World Development Team
4  * Copyright (C) 2009-2010 The Mana Developers
5  * Copyright (C) 2011-2019 The ManaPlus Developers
6  * Copyright (C) 2019-2021 Andrei Karas
7  *
8  * This file is part of The ManaPlus Client.
9  *
10  * This program is free software; you can redistribute it and/or modify
11  * it under the terms of the GNU General Public License as published by
12  * the Free Software Foundation; either version 2 of the License, or
13  * any later version.
14  *
15  * This program is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18  * GNU General Public License for more details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with this program. If not, see <http://www.gnu.org/licenses/>.
22  */
23 
24 #include "configmanager.h"
25 
26 #include "client.h"
27 #include "configuration.h"
28 #include "settings.h"
29 
30 #include "being/beingspeech.h"
31 
32 #include "fs/files.h"
33 #include "fs/mkdir.h"
34 #include "fs/paths.h"
35 
36 #include "utils/cast.h"
37 #include "utils/checkutils.h"
38 #include "utils/gettext.h"
39 
40 #include "render/renderers.h"
41 
42 #include "debug.h"
43 
44 static void setDefaultOption(const char *const name,
45  const bool def)
46 {
47  const int val = serverConfig.getValue(name, -1);
48  if (val == -1)
49  serverConfig.setValue(name, def);
50 }
51 
56 void ConfigManager::initServerConfig(const std::string &serverName)
57 {
59 
60  if (mkdir_r(settings.serverConfigDir.c_str()) != 0)
61  {
62  // TRANSLATORS: directory creation error
63  logger->error(strprintf(_("%s doesn't exist and can't be created! "
64  "Exiting."), settings.serverConfigDir.c_str()));
65  }
66  const std::string configPath = settings.serverConfigDir + "/config.xml";
67  FILE *configFile = fopen(configPath.c_str(), "r");
68  if (configFile == nullptr)
69  {
70  configFile = fopen(configPath.c_str(), "wb");
71  logger->log("Creating new server config: " + configPath);
72  if (configFile != nullptr)
73  {
74  fputs("<?xml version=\"1.0\"?>\n", configFile);
75  fputs("<configuration>\n", configFile);
76  fputs("</configuration>\n", configFile);
77  }
78  }
79  if (configFile != nullptr)
80  {
81  fclose(configFile);
82  serverConfig.init(configPath,
86  logger->log("serverConfigPath: " + configPath);
87  }
88  else
89  {
90  reportAlways("Error creating server config: %s",
91  configPath.c_str())
92  }
93 
94  const bool val = Client::isTmw();
95  setDefaultOption("enableManaMarketBot", val);
96  setDefaultOption("enableRemoteCommands", !val);
97 }
98 
100 {
101 #ifdef DEBUG_CONFIG
102  config.setIsMain(true);
103 #endif // DEBUG_CONFIG
104 
105  // Fill configuration with defaults
106  config.setValue("hwaccel", false);
107 #ifdef USE_OPENGL
108 #if (defined __APPLE__)
110 #elif (defined ANDROID)
112 #elif (defined WIN32)
114 #else // (defined __APPLE__)
115 
117 #endif // (defined __APPLE__)
118 #else // USE_OPENGL
119 
121 #endif // USE_OPENGL
122 
123  config.setValue("screen", false);
124  config.setValue("sound", true);
125  config.setValue("guialpha", 0.8F);
126 // config.setValue("remember", true);
127  config.setValue("sfxVolume", 100);
128  config.setValue("musicVolume", 60);
129  config.setValue("fpslimit", 60);
130  std::string defaultUpdateHost = branding.getValue("defaultUpdateHost", "");
131  if (!checkPath(defaultUpdateHost))
132  defaultUpdateHost.clear();
133  config.setValue("updatehost", defaultUpdateHost);
134  config.setValue("useScreenshotDirectorySuffix", true);
135  config.setValue("ChatLogLength", 128);
136 
137  std::string configPath;
138 
139 #ifndef UNITTESTS
140  if (settings.options.test.empty())
141  configPath = settings.configDir + "/config.xml";
142  else
143  configPath = settings.configDir + "/test.xml";
144 #else // UNITTESTS
145 
146  configPath = settings.configDir + "/unittestconfig.xml";
147 #endif // UNITTESTS
148 
149  FILE *configFile = fopen(configPath.c_str(), "r");
150  if (configFile == nullptr)
151  {
152  configFile = fopen(configPath.c_str(), "wb");
153  logger->log1("Creating new config");
154  if (configFile != nullptr)
155  {
156  fputs("<?xml version=\"1.0\"?>\n", configFile);
157  fputs("<configuration>\n", configFile);
158  fputs("</configuration>\n", configFile);
159  }
160  }
161  if (configFile == nullptr)
162  {
163  reportAlways("Can't create %s. Using defaults.",
164  configPath.c_str())
165  }
166  else
167  {
168  fclose(configFile);
169  config.init(configPath,
172  logger->log1("init 3");
175  logger->log("configuration file: " + configPath);
176  }
177 }
178 
179 void ConfigManager::backupConfig(const std::string &name)
180 {
181  const std::string fileName3 = pathJoin(settings.configDir, name);
182  StringVect arr;
183  if (Files::existsLocal(fileName3) == false)
184  {
185  logger->log("Config %s not exists, backup skipped.",
186  name.c_str());
187  return;
188  }
189  if (Files::loadTextFileLocal(fileName3, arr) == true)
190  {
191  if (arr.empty())
192  return;
193 
194  arr.clear();
195  const std::string tmpName = pathJoin(settings.configDir,
196  name).append(".tmp");
197  Files::copyFile(fileName3, tmpName);
198  if (Files::loadTextFileLocal(tmpName, arr) == false ||
199  arr.empty())
200  {
201  logger->safeError("Error backuping configs. "
202  "Probably no free space on disk.");
203  }
204  arr.clear();
205  }
206 
207  const std::string confName = pathJoin(settings.configDir,
208  name).append(".bak");
209  const int maxFileIndex = 5;
210  ::remove((confName + toString(maxFileIndex)).c_str());
211  for (int f = maxFileIndex; f > 1; f --)
212  {
213  const std::string fileName1 = confName + toString(f - 1);
214  const std::string fileName2 = confName + toString(f);
215  Files::renameFile(fileName1, fileName2);
216  }
217  const std::string fileName4 = confName + toString(1);
218  Files::copyFile(fileName3, fileName4);
219 }
220 
221 #ifdef __native_client__
223 {
224  RenderType tmpOpengl;
225 
226  isSafeMode = config.getBoolValue("safemode");
227  if (isSafeMode)
228  logger->log1("Run in safe mode");
229 
230  tmpOpengl = intToRenderType(config.getIntValue("opengl"));
231 
233 
234  config.write();
235 
237  {
238  isSafeMode = true;
239  return;
240  }
241 
242  config.setValue("safemode", false);
243  config.setValue("opengl", CAST_S32(tmpOpengl));
244 }
245 #elif !defined(ANDROID)
247 {
248  bool tmpHwaccel;
249  RenderType tmpOpengl;
250  int tmpFpslimit;
251  int tmpAltFpslimit;
252  bool tmpSound;
253  int width;
254  int height;
255  std::string font;
256  std::string bFont;
257  std::string particleFont;
258  std::string helpFont;
259  std::string secureFont;
260  std::string npcFont;
261  std::string japanFont;
262  std::string chinaFont;
263  bool showBackground;
264  bool enableMumble;
265  bool enableMapReduce;
266 
267  isSafeMode = config.getBoolValue("safemode");
268  if (isSafeMode)
269  logger->log1("Run in safe mode");
270 
271  tmpOpengl = intToRenderType(config.getIntValue("opengl"));
272 
273  width = config.getIntValue("screenwidth");
274  height = config.getIntValue("screenheight");
275  tmpHwaccel = config.getBoolValue("hwaccel");
276 
277  tmpFpslimit = config.getIntValue("fpslimit");
278  tmpAltFpslimit = config.getIntValue("altfpslimit");
279  tmpSound = config.getBoolValue("sound");
280 
281  font = config.getStringValue("font");
282  bFont = config.getStringValue("boldFont");
283  particleFont = config.getStringValue("particleFont");
284  helpFont = config.getStringValue("helpFont");
285  secureFont = config.getStringValue("secureFont");
286  npcFont = config.getStringValue("npcFont");
287  japanFont = config.getStringValue("japanFont");
288  chinaFont = config.getStringValue("chinaFont");
289 
290  showBackground = config.getBoolValue("showBackground");
291  enableMumble = config.getBoolValue("enableMumble");
292  enableMapReduce = config.getBoolValue("enableMapReduce");
293 
294  if (!settings.options.safeMode && tmpOpengl == RENDER_SOFTWARE)
295  {
296  // if video mode configured reset most settings to safe
297  config.setValue("hwaccel", false);
298  config.setValue("altfpslimit", 3);
299  config.setValue("sound", false);
300  config.setValue("safemode", true);
301  config.setValue("screenwidth", 640);
302  config.setValue("screenheight", 480);
303  config.setValue("font", "fonts/dejavusans.ttf");
304  config.setValue("boldFont", "fonts/dejavusans-bold.ttf");
305  config.setValue("particleFont", "fonts/dejavusans.ttf");
306  config.setValue("helpFont", "fonts/dejavusansmono.ttf");
307  config.setValue("secureFont", "fonts/dejavusansmono.ttf");
308  config.setValue("npcFont", "fonts/dejavusans.ttf");
309  config.setValue("japanFont", "fonts/mplus-1p-regular.ttf");
310  config.setValue("chinaFont", "fonts/wqy-microhei.ttf");
311  config.setValue("showBackground", false);
312  config.setValue("enableMumble", false);
313  config.setValue("enableMapReduce", false);
314  }
315  else
316  {
317  // if video mode not configured reset only video mode to safe
318  config.setValue("screenwidth", 640);
319  config.setValue("screenheight", 480);
320  }
321 #if defined(__APPLE__)
323 #else // defined(__APPLE__)
324 
326 #endif // defined(__APPLE__)
327 
328  config.write();
329 
331  {
332  isSafeMode = true;
333  return;
334  }
335 
336  config.setValue("safemode", false);
337  if (tmpOpengl == RENDER_SOFTWARE)
338  {
339  config.setValue("hwaccel", tmpHwaccel);
340  config.setValue("opengl", CAST_S32(tmpOpengl));
341  config.setValue("fpslimit", tmpFpslimit);
342  config.setValue("altfpslimit", tmpAltFpslimit);
343  config.setValue("sound", tmpSound);
344  config.setValue("screenwidth", width);
345  config.setValue("screenheight", height);
346  config.setValue("font", font);
347  config.setValue("boldFont", bFont);
348  config.setValue("particleFont", particleFont);
349  config.setValue("helpFont", helpFont);
350  config.setValue("secureFont", secureFont);
351  config.setValue("npcFont", npcFont);
352  config.setValue("japanFont", japanFont);
353  config.setValue("chinaFont", chinaFont);
354  config.setValue("showBackground", showBackground);
355  config.setValue("enableMumble", enableMumble);
356  config.setValue("enableMapReduce", enableMapReduce);
357  }
358  else
359  {
360  config.setValue("opengl", CAST_S32(tmpOpengl));
361  config.setValue("screenwidth", width);
362  config.setValue("screenheight", height);
363  }
364 }
365 #endif // __native_client__
366 
367 #define unassignKey(key, value) \
368  if (config.getStringValue(prefix + (key)) == (value)) \
369  config.setValue(key, "-1");
370 
372 {
373  const int version = config.getIntValue("cfgver");
374  if (version < 1)
375  {
376  if (config.getIntValue("fontSize") == 11)
377  config.deleteKey("fontSize");
378  if (config.getIntValue("npcfontSize") == 13)
379  config.deleteKey("npcfontSize");
380  }
381  if (version < 2)
382  {
383  if (config.getIntValue("screenButtonsSize") == 1)
384  config.deleteKey("screenButtonsSize");
385  if (config.getIntValue("screenJoystickSize") == 1)
386  config.deleteKey("screenJoystickSize");
387  }
388  if (version < 3)
389  {
390  config.setValue("audioFrequency", 44100);
391 #ifdef ANDROID
392  config.setValue("customcursor", false);
393 #endif // ANDROID
394  }
395 #ifdef ANDROID
396  if (version < 4)
397  {
398  config.setValue("showDidYouKnow", false);
399  }
400 #endif // ANDROID
401 
402  if (version < 5)
403  {
405  {
406  config.setValue("speech", CAST_S32(
408  }
409  }
410  if (version < 6)
411  config.setValue("blur", false);
412 
413  if (version < 7)
414  config.setValue("download-music", true);
415 
416  if (version < 9)
417  {
418  config.deleteKey("videodetected");
419  config.setValue("moveToTargetType", 10);
420  }
421  if (version < 10)
422  config.setValue("enableLazyScrolling", false);
423 
424  if (version < 11)
425  {
426 #ifdef USE_SDL2
427  const std::string prefix = std::string("sdl2");
428 #else // USE_SDL2
429 
430  const std::string prefix = std::string();
431 #endif // USE_SDL2
432 
433  unassignKey("keyDirectUp", "k108")
434  unassignKey("keyDirectDown", "k59")
435  unassignKey("keyDirectLeft", "k107")
436  unassignKey("keyDirectRight", "k39")
437  }
438  if (version < 12)
439  {
440 #ifdef USE_SDL2
441  const std::string prefix = std::string("sdl2");
442 #else // USE_SDL2
443 
444  const std::string prefix = std::string();
445 #endif // USE_SDL2
446 
447  unassignKey("keyAttack", "k120")
448  }
449 
450  if (version < 13)
451  config.setValue("keyWindowBotChecker", -1);
452 
453  if (version < 14 && config.getIntValue("syncPlayerMoveDistance") == 2)
454  config.setValue("syncPlayerMoveDistance", 5);
455  config.setValue("cfgver", 14);
456 }
457 
458 #undef unassignKey
#define CAST_S32
Definition: cast.h:30
#define reportAlways(...)
Definition: checkutils.h:253
static bool isTmw()
Definition: client.cpp:838
static void initServerConfig(const std::string &serverName)
static void backupConfig(const std::string &name)
static void storeSafeParameters()
static void checkConfigVersion()
static void initConfiguration()
std::string getValue(const std::string &key, const std::string &deflt) const
void deleteKey(const std::string &key)
bool getBoolValue(const std::string &key) const
std::string getStringValue(const std::string &key) const
void setValue(const std::string &key, const std::string &value)
void init(const std::string &filename, const UseVirtFs useResManager, const SkipError skipError)
int getIntValue(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
void safeError(const std::string &error_text) __attribute__((noreturn))
Definition: logger.cpp:435
void error(const std::string &error_text) __attribute__((noreturn))
Definition: logger.cpp:472
Options options
Definition: settings.h:130
std::string configDir
Definition: settings.h:111
std::string serverConfigDir
Definition: settings.h:117
#define unassignKey(key, value)
static void setDefaultOption(const char *const name, const bool def)
Configuration config
Configuration serverConfig
Configuration branding
void setConfigDefaults(Configuration &cfg)
Definition: defaults.cpp:90
bool isSafeMode
Definition: client.cpp:123
#define _(s)
Definition: gettext.h:35
Logger * logger
Definition: logger.cpp:89
int mkdir_r(const char *const pathname)
Create a directory, making leading components first if necessary.
Definition: mkdir.cpp:109
@ NO_NAME_IN_BUBBLE
Definition: beingspeech.h:33
std::string toString(T const &value)
converts any type to a string
Definition: catch.hpp:1774
bool loadTextFileLocal(const std::string &fileName, StringVect &lines)
Definition: files.cpp:229
int renameFile(const std::string &pFrom, const std::string &pTo)
Definition: files.cpp:134
int copyFile(const std::string &pFrom, const std::string &pTo)
Definition: files.cpp:176
bool existsLocal(const std::string &path)
Definition: files.cpp:209
bool remove(const std::string &filename)
Definition: fs.cpp:780
bool checkPath(const std::string &path)
Definition: paths.cpp:121
RenderType intToRenderType(const int mode)
Definition: renderers.cpp:43
RenderType
Definition: rendertype.h:26
@ RENDER_SAFE_OPENGL
Definition: rendertype.h:29
@ RENDER_GLES_OPENGL
Definition: rendertype.h:30
@ RENDER_NORMAL_OPENGL
Definition: rendertype.h:28
@ RENDER_SOFTWARE
Definition: rendertype.h:27
Settings settings
Definition: settings.cpp:32
const bool SkipError_false
Definition: skiperror.h:30
std::string strprintf(const char *const format,...)
std::string pathJoin(std::string str1, const std::string &str2)
std::vector< std::string > StringVect
Definition: stringvector.h:29
bool safeMode
Definition: options.h:98
std::string test
Definition: options.h:88
const bool UseVirtFs_false
Definition: usevirtfs.h:30