ManaPlus
client.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-2018 The ManaPlus Developers
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 "progs/manaplus/client.h"
24 
25 #include "chatlogger.h"
26 #include "configmanager.h"
27 #include "dirs.h"
28 #include "eventsmanager.h"
29 #include "game.h"
30 #include "graphicsmanager.h"
31 #include "main.h"
32 #include "party.h"
33 #include "pincodemanager.h"
34 #include "settings.h"
35 #include "soundmanager.h"
36 #include "spellmanager.h"
37 
38 #include "being/localclan.h"
39 #include "being/localplayer.h"
40 #include "being/playerinfo.h"
41 #include "being/playerrelations.h"
42 
43 #include "const/net/net.h"
44 
46 
47 #include "fs/virtfs/fs.h"
48 #include "fs/virtfs/tools.h"
49 
50 #include "gui/dialogsmanager.h"
51 #include "gui/gui.h"
52 #include "gui/skin.h"
53 #include "gui/popupmanager.h"
54 #include "gui/windowmanager.h"
55 
60 
67 #include "gui/windows/npcdialog.h"
68 #include "gui/windows/okdialog.h"
73 #include "gui/windows/quitdialog.h"
75 
76 #include "gui/widgets/button.h"
78 #include "gui/widgets/desktop.h"
80 
81 #include "input/inputmanager.h"
82 #include "input/joystick.h"
83 #include "input/keyboardconfig.h"
84 
86 
87 #include "net/charserverhandler.h"
88 #include "net/chathandler.h"
89 #include "net/download.h"
90 #include "net/gamehandler.h"
91 #include "net/generalhandler.h"
92 #include "net/guildhandler.h"
93 #include "net/inventoryhandler.h"
94 #include "net/ipc.h"
95 #include "net/loginhandler.h"
96 #include "net/net.h"
98 #include "net/useragent.h"
99 #include "net/packetlimiter.h"
100 #include "net/partyhandler.h"
101 
102 #ifdef TMWA_SUPPORT
103 #include "net/tmwa/guildmanager.h"
104 #endif // TMWA_SUPPORT
105 
106 #include "particle/particleengine.h"
107 
108 #include "resources/dbmanager.h"
109 #include "resources/imagehelper.h"
110 
112 
114 
116 
117 #include "utils/checkutils.h"
118 #include "utils/cpu.h"
119 #include "utils/delete2.h"
120 #include "utils/dumplibs.h"
121 #include "utils/dumpsizes.h"
122 #include "utils/env.h"
123 #include "utils/fuzzer.h"
124 #include "utils/gettext.h"
125 #include "utils/gettexthelper.h"
126 #include "utils/mrand.h"
127 #ifdef ANDROID
128 #include "fs/paths.h"
129 #endif // ANDROID
130 #include "utils/sdlcheckutils.h"
131 #include "utils/sdlhelper.h"
132 #include "utils/timer.h"
133 
135 
137 #include "listeners/errorlistener.h"
138 
139 #ifdef USE_OPENGL
140 #include "test/testlauncher.h"
141 #include "test/testmain.h"
142 #else // USE_OPENGL
143 #include "configuration.h"
144 #endif // USE_OPENGL
145 
146 #ifdef WIN32
147 PRAGMA48(GCC diagnostic push)
148 PRAGMA48(GCC diagnostic ignored "-Wshadow")
149 #include <SDL_syswm.h>
150 PRAGMA48(GCC diagnostic pop)
151 #include "fs/specialfolder.h"
152 #undef ERROR
153 #endif // WIN32
154 
155 #ifdef ANDROID
156 #ifndef USE_SDL2
157 PRAGMA48(GCC diagnostic push)
158 PRAGMA48(GCC diagnostic ignored "-Wshadow")
159 #include <SDL_screenkeyboard.h>
160 PRAGMA48(GCC diagnostic pop)
161 #include <fstream>
162 #endif // USE_SDL2
163 #endif // ANDROID
164 
165 #include <sys/stat.h>
166 
167 #ifdef USE_MUMBLE
168 #include "mumblemanager.h"
169 #endif // USE_MUMBLE
170 
171 PRAGMA48(GCC diagnostic push)
172 PRAGMA48(GCC diagnostic ignored "-Wshadow")
173 #ifdef USE_SDL2
174 #include <SDL2_framerate.h>
175 #else // USE_SDL2
176 #include <SDL_framerate.h>
177 #endif // USE_SDL2
178 PRAGMA48(GCC diagnostic pop)
179 
180 #include "debug.h"
181 
182 std::string errorMessage;
184 
185 Client *client = nullptr;
186 
187 extern FPSmanager fpsManager;
188 extern int evolPacketOffset;
189 
190 volatile bool runCounters;
191 bool isSafeMode = false;
197 int packetsType = 0;
198 bool packets_main = true;
199 bool packets_re = false;
200 bool packets_zero = false;
201 unsigned int tmwServerVersion = 0;
202 time_t start_time;
203 unsigned int mLastHost = 0;
204 unsigned long mSearchHash = 0;
206 volatile bool isTerminate = false;
207 
208 namespace
209 {
211  {
212  public:
214  { }
215 
217 
218  void action(const ActionEvent &event A_UNUSED) override final
219  {
220  client->setState(State::CHAR_SELECT);
221  }
222  } accountListener;
223 
225  {
226  public:
228  { }
229 
231 
232  void action(const ActionEvent &event A_UNUSED) override final
233  {
234  client->setState(State::PRE_LOGIN);
235  }
236  } loginListener;
237 } // namespace
238 
239 Client::Client() :
240  ActionListener(),
241  mCurrentServer(),
242  mGame(nullptr),
243  mCurrentDialog(nullptr),
244  mQuitDialog(nullptr),
245  mSetupButton(nullptr),
246  mVideoButton(nullptr),
247  mHelpButton(nullptr),
248  mAboutButton(nullptr),
249  mThemesButton(nullptr),
250  mPerfomanceButton(nullptr),
251 #ifdef ANDROID
252  mCloseButton(nullptr),
253 #endif // ANDROID
254  mState(State::CHOOSE_SERVER),
255  mOldState(State::START),
256  mSkin(nullptr),
257  mButtonPadding(1),
258  mButtonSpacing(3),
259  mPing(0),
260  mConfigAutoSaved(false)
261 {
263 }
264 
265 void Client::testsInit()
266 {
267  if (!settings.options.test.empty() &&
268  settings.options.test != "99")
269  {
270  gameInit();
271  }
272  else
273  {
274  initRand();
275  logger = new Logger;
276  SDL::initLogger();
281  }
282 }
283 
284 void Client::gameInit()
285 {
286  logger = new Logger;
287  SDL::initLogger();
288 
289  initRand();
290 
292  // Load branding information
293  if (!settings.options.brandingPath.empty())
294  {
298  }
300 
303 
304 #ifndef ENABLE_COMMANDLINEPASSWORD
305  if (!settings.options.password.empty())
306  {
307  settings.options.password.clear();
308  logger->log("Command line password parameter disabled.");
309  }
310 #endif
311 
312  // Configure logger
313  if (!settings.options.logFileName.empty())
314  {
316  }
317  else
318  {
320  "manaplus.log");
321  }
322  logger->log("Log file: " + settings.logFileName);
324 
325 #ifdef USE_FUZZER
326  Fuzzer::init();
327 #endif // USE_FUZZER
328 
329  if (settings.options.ipc == true)
330  IPC::start();
331  if (settings.options.test.empty())
332  ConfigManager::backupConfig("config.xml");
334  SDL::setLogLevel(config.getIntValue("sdlLogLevel"));
335  settings.init();
338  initFeatures();
339  initPaths();
340  logger->log("init 4");
341  logger->setDebugLog(config.getBoolValue("debugLog"));
342  logger->setReportUnimplemented(config.getBoolValue("unimplimentedLog"));
343 
344  config.incValue("runcount");
345 
346 #ifndef ANDROID
347  if (settings.options.test.empty())
349 #endif // ANDROID
350 
352  {
353  logger->error(strprintf("%s couldn't be set as home directory! "
354  "Exiting.", settings.localDataDir.c_str()));
355  }
356 
358 
359  chatLogger = new ChatLogger;
360  if (settings.options.chatLogDir.empty())
361  {
363  + std::string("/logs/"));
364  }
365  else
366  {
368  }
369 
370  // Log the client version
372  logger->log("Start configPath: " + config.getConfigPath());
373 
375 
376  updateEnv();
377  SDL::allowScreenSaver(config.getBoolValue("allowscreensaver"));
378  dumpLibs();
379  dumpSizes();
380 
381  // Initialize SDL
382  logger->log1("Initializing SDL...");
383  if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0)
384  {
385  logger->safeError(strprintf("Could not initialize SDL: %s",
386  SDL_GetError()));
387  }
388  atexit(SDL_Quit);
389 
391 #ifndef USE_SDL2
392  SDL_EnableUNICODE(1);
393 #endif // USE_SDL2
394 
398 
399 #ifdef WIN32
401 #endif // WIN32
402 #ifndef USE_SDL2
404 #endif // USE_SDL2
405 
407  logVars();
408  Cpu::detect();
410 #if defined(USE_OPENGL)
411 #if !defined(ANDROID) && !defined(__APPLE__) && \
412  !defined(__native_client__) && !defined(UNITTESTS)
413  if (!settings.options.safeMode &&
414  settings.options.renderer < 0 &&
415  settings.options.test.empty() &&
417  !config.getBoolValue("videodetected"))
418  {
420  }
421 #endif // !defined(ANDROID) && !defined(__APPLE__) &&
422  // !defined(__native_client__) && !defined(UNITTESTS)
423 #endif // defined(USE_OPENGL)
424 
425  initGraphics();
427 
428  touchManager.init();
429 
430 #ifndef WIN32
433 #endif // WIN32
434 
436 
437  // Add the main data directories to our VirtFs search path
438  if (!settings.options.dataPath.empty())
439  {
441  Append_false);
442  }
443 
444  // Add the local data directory to VirtFs search path
446  Append_false);
449 #ifdef ENABLE_CUSTOMNLS
450  TranslationManager::loadGettextLang();
451 #endif // ENABLE_CUSTOMNLS
452 
453 #ifdef USE_SDL2
455 #endif // USE_SDL2
457 
459 
460  theme = new Theme;
463  touchManager.init();
464 
465  // Initialize the item and emote shortcuts.
466  for (size_t f = 0; f < SHORTCUT_TABS; f ++)
467  itemShortcut[f] = new ItemShortcut(f);
470 
471  gui = new Gui;
475 
476  initSoundManager();
477 
478  // Initialize keyboard
479  keyboard.init();
480  inputManager.init();
481 
482  // Initialise player relations
484  Joystick::init();
486 
487  keyboard.update();
488  if (joystick != nullptr)
489  joystick->update();
490 
491  // Initialize default server
492  mCurrentServer.hostname = settings.options.serverName;
493  mCurrentServer.port = settings.options.serverPort;
494  if (!settings.options.serverType.empty())
495  {
496  mCurrentServer.type = ServerInfo::parseType(
498  }
499 
503  loginData.remember = (serverConfig.getValue("remember", 1) != 0);
504  loginData.registerLogin = false;
505 
506  if (mCurrentServer.hostname.empty())
507  {
508  mCurrentServer.hostname = branding.getValue("defaultServer", "");
509  settings.options.serverName = mCurrentServer.hostname;
510  }
511 
512  if (mCurrentServer.port == 0)
513  {
514  mCurrentServer.port = CAST_U16(branding.getValue(
515  "defaultPort", CAST_S32(DEFAULT_PORT)));
516  mCurrentServer.type = ServerInfo::parseType(
517  branding.getValue("defaultServerType", "tmwathena"));
518  }
519 
520  chatLogger->setServerName(mCurrentServer.hostname);
521 
522  if (loginData.username.empty() && loginData.remember)
523  loginData.username = serverConfig.getValue("username", "");
524 
525  if (mState != State::ERROR)
526  mState = State::CHOOSE_SERVER;
527 
528  startTimers();
529 
530  const int fpsLimit = config.getIntValue("fpslimit");
531  settings.limitFps = fpsLimit > 0;
532 
534  WindowManager::setFramerate(fpsLimit);
535  initConfigListeners();
536 
537  settings.guiAlpha = config.getFloatValue("guialpha");
538  optionChanged("fpslimit");
539 
540  start_time = time(nullptr);
541 
543 
544 #ifdef ANDROID
545 #ifndef USE_SDL2
546  WindowManager::updateScreenKeyboard(SDL_GetScreenKeyboardHeight(nullptr));
547 #endif // USE_SDL2
548 #endif // ANDROID
549 
550 #ifdef USE_MUMBLE
551  if (!mumbleManager)
552  mumbleManager = new MumbleManager;
553 #endif // USE_MUMBLE
554 
555  mSkin = theme->load("windowmenu.xml",
556  "",
557  true,
559  if (mSkin != nullptr)
560  {
561  mButtonPadding = mSkin->getPadding();
562  mButtonSpacing = mSkin->getOption("spacing", 3);
563  }
564  if (settings.options.error)
566 
567  if (settings.options.validate == true)
568  runValidate();
569 }
570 
572 {
574  gameClear();
575  else
576  testsClear();
578 }
579 
581 {
582  config.addListener("fpslimit", this);
583  config.addListener("guialpha", this);
584  config.addListener("gamma", this);
585  config.addListener("enableGamma", this);
586  config.addListener("particleEmitterSkip", this);
587  config.addListener("vsync", this);
588  config.addListener("repeateDelay", this);
589  config.addListener("repeateInterval", this);
590  config.addListener("logInput", this);
591 }
592 
594 {
595  // Initialize sound engine
596  try
597  {
598  if (config.getBoolValue("sound"))
599  soundManager.init();
600 
603  }
604  catch (const char *const err)
605  {
606  mState = State::ERROR;
607  errorMessage = err;
608  logger->log("Warning: %s", err);
609  }
611  "loginMusic",
612  "keprohm.ogg"),
614 }
615 
617 {
618 #ifndef USE_SDL2
620 #endif // USE_SDL2
621 
622  runCounters = config.getBoolValue("packetcounters");
623 
625 #ifdef USE_SDL2
627 #endif // USE_SDL2
628 
633 
635 }
636 
637 void Client::testsClear()
638 {
639  if (!settings.options.test.empty())
640  gameClear();
641  else
643 }
644 
645 void Client::gameClear()
646 {
647  if (logger != nullptr)
648  logger->log1("Quitting1");
649  isTerminate = true;
650  config.removeListeners(this);
651 
653 
654  IPC::stop();
657  if (windowContainer != nullptr)
659 
660  stopTimers();
662 
663  if (loginHandler != nullptr)
665 
666  if (chatHandler != nullptr)
667  chatHandler->clear();
668 
669  if (charServerHandler != nullptr)
671 
672  delete2(ipc);
673 
674 #ifdef USE_MUMBLE
675  delete2(mumbleManager);
676 #endif // USE_MUMBLE
677 
679 
680  // Before config.write() since it writes the shortcuts to the config
681  for (unsigned f = 0; f < SHORTCUT_TABS; f ++)
685 
687 
688  if (logger != nullptr)
689  logger->log1("Quitting2");
690 
691  delete2(mCurrentDialog);
694  delete2(gui);
695 
696  if (inventoryHandler != nullptr)
698 
699  if (logger != nullptr)
700  logger->log1("Quitting3");
701 
703 
705 
706  if (logger != nullptr)
707  logger->log1("Quitting4");
708 
709  XML::cleanupXML();
710 
711  if (logger != nullptr)
712  logger->log1("Quitting5");
713 
715 
716  // Shutdown sound
718 
719  if (logger != nullptr)
720  logger->log1("Quitting6");
721 
723 
725 
727 
728  if (logger != nullptr)
729  logger->log1("Quitting8");
730 
732 
733  if (logger != nullptr)
734  logger->log1("Quitting9");
735 
736  delete2(joystick);
737 
738  keyboard.deinit();
739 
740  if (logger != nullptr)
741  logger->log1("Quitting10");
742 
744 
745 #ifdef DEBUG_CONFIG
746  config.enableKeyLogging();
747 #endif // DEBUG_CONFIG
748 
750  config.write();
752 
753  config.clear();
755 
756  if (logger != nullptr)
757  logger->log1("Quitting11");
758 
759 #ifdef USE_PROFILER
761 #endif // USE_PROFILER
762 
763 #ifdef DEBUG_OPENGL_LEAKS
764  if (logger)
765  logger->log("textures left: %d", textures_count);
766 #endif // DEBUG_OPENGL_LEAKS
767 
769 
770  if (logger != nullptr)
771  logger->log1("Quitting12");
772 
775 }
776 
777 int Client::testsExec()
778 {
779 #ifdef USE_OPENGL
780  if (settings.options.test.empty())
781  {
782  TestMain test;
783  return test.exec();
784  }
785  else
786  {
787  TestLauncher launcher(settings.options.test);
788  return launcher.exec();
789  }
790 #else // USE_OPENGL
791 
792  return 0;
793 #endif // USE_OPENGL
794 }
795 
796 #define ADDBUTTON(var, object) var = object; \
797  x -= var->getWidth() + mButtonSpacing; \
798  var->setPosition(x, mButtonPadding); \
799  top->add(var);
800 
802 {
803  if ((gameHandler != nullptr) &&
804  (loginHandler != nullptr) &&
806  {
808  }
809 }
810 
812 {
813  if (mOldState == State::CHOOSE_SERVER)
814  {
815  settings.serverName = mCurrentServer.hostname;
816  ConfigManager::initServerConfig(mCurrentServer.hostname);
818  initTradeFilter();
821 
822  // Initialize the item and emote shortcuts.
823  for (unsigned f = 0; f < SHORTCUT_TABS; f ++)
824  {
825  delete itemShortcut[f];
826  itemShortcut[f] = new ItemShortcut(f);
827  }
828  delete emoteShortcut;
830 
831  // Initialize the drop shortcuts.
832  delete dropShortcut;
834 
835  initFeatures();
837  loginData.registerUrl = mCurrentServer.registerUrl;
838  loginData.packetVersion = mCurrentServer.packetVersion;
839  if (!mCurrentServer.onlineListUrl.empty())
840  settings.onlineListUrl = mCurrentServer.onlineListUrl;
841  else
843  settings.persistentIp = mCurrentServer.persistentIp;
844  settings.supportUrl = mCurrentServer.supportUrl;
845  settings.updateMirrors = mCurrentServer.updateMirrors;
847  "enableRemoteCommands", 1) != 0);
848 
849  if (settings.options.username.empty())
850  {
851  if (loginData.remember)
852  loginData.username = serverConfig.getValue("username", "");
853  else
854  loginData.username.clear();
855  }
856  else
857  {
859  }
862 
863  loginData.remember = (serverConfig.getValue("remember", 1) != 0);
864  Net::connectToServer(mCurrentServer);
865 
866 #ifdef USE_MUMBLE
867  if (mumbleManager)
868  mumbleManager->setServer(mCurrentServer.hostname);
869 #endif // USE_MUMBLE
870 
871 #ifdef TMWA_SUPPORT
873 #endif // TMWA_SUPPORT
874 
875  if (!mConfigAutoSaved)
876  {
877  mConfigAutoSaved = true;
878  config.write();
879  }
880  }
881  else if (mOldState != State::CHOOSE_SERVER &&
882  (loginHandler != nullptr) &&
884  {
885  mState = State::PRE_LOGIN;
886  }
887 }
888 
890 {
891  if (mOldState == State::UPDATE &&
892  (loginHandler != nullptr))
893  {
894  if (loginHandler->getWorlds().size() < 2)
895  mState = State::PRE_LOGIN;
896  }
897 }
898 
900 {
901  if (gui == nullptr)
902  return;
903 
904  BasicContainer2 *const top = static_cast<BasicContainer2*>(
905  gui->getTop());
906 
907  if (top == nullptr)
908  return;
909 
910  CREATEWIDGETV(desktop, Desktop, nullptr);
911  top->add(desktop);
912  int x = top->getWidth() - mButtonPadding;
913  ADDBUTTON(mSetupButton, new Button(desktop,
914  // TRANSLATORS: setup tab quick button
915  _("Setup"), "Setup", BUTTON_SKIN, this))
916  ADDBUTTON(mPerfomanceButton, new Button(desktop,
917  // TRANSLATORS: perfoamance tab quick button
918  _("Performance"), "Perfomance", BUTTON_SKIN, this))
919  ADDBUTTON(mVideoButton, new Button(desktop,
920  // TRANSLATORS: video tab quick button
921  _("Video"), "Video", BUTTON_SKIN, this))
922  ADDBUTTON(mThemesButton, new Button(desktop,
923  // TRANSLATORS: theme tab quick button
924  _("Theme"), "Themes", BUTTON_SKIN, this))
925  ADDBUTTON(mAboutButton, new Button(desktop,
926  // TRANSLATORS: theme tab quick button
927  _("About"), "about", BUTTON_SKIN, this))
928  ADDBUTTON(mHelpButton, new Button(desktop,
929  // TRANSLATORS: theme tab quick button
930  _("Help"), "help", BUTTON_SKIN, this))
931 #ifdef ANDROID
932  ADDBUTTON(mCloseButton, new Button(desktop,
933  // TRANSLATORS: close quick button
934  _("Close"), "close", BUTTON_SKIN, this))
935 #endif // ANDROID
936 
939 }
940 
942 {
943  if (mOldState == State::GAME &&
944  (gameHandler != nullptr))
945  {
947  }
948 }
949 
950 int Client::gameExec()
951 {
952  int lastTickTime = tick_time;
953 
954  while (mState != State::EXIT)
955  {
956  PROFILER_START();
958  continue;
959 
960  BLOCK_START("Client::gameExec 3")
961  if (generalHandler != nullptr)
963  BLOCK_END("Client::gameExec 3")
964 
965  BLOCK_START("Client::gameExec 4")
966  if (gui != nullptr)
967  gui->logic();
968  cur_time = time(nullptr);
969  int k = 0;
970  while (lastTickTime != tick_time &&
971  k < 40)
972  {
973  if (mGame != nullptr)
974  mGame->logic();
975  else if (gui != nullptr)
976  gui->handleInput();
977 
978  ++lastTickTime;
979  k ++;
980  }
982 
983  logic_count += k;
984  if (gui != nullptr)
985  gui->slowLogic();
986  if (mGame != nullptr)
987  mGame->slowLogic();
988  slowLogic();
989  BLOCK_END("Client::gameExec 4")
990 
991  // This is done because at some point tick_time will wrap.
992  lastTickTime = tick_time;
993 
994  // Update the screen when application is visible, delay otherwise.
996  {
997  frame_count++;
998  if (gui != nullptr)
999  gui->draw();
1001  }
1002  else
1003  {
1004  SDL_Delay(100);
1005  }
1006 
1007  BLOCK_START("~Client::SDL_framerateDelay")
1008  if (settings.limitFps)
1010  BLOCK_END("~Client::SDL_framerateDelay")
1011 
1012  BLOCK_START("Client::gameExec 6")
1013  if (mState == State::CONNECT_GAME)
1014  {
1015  stateConnectGame1();
1016  }
1017  else if (mState == State::CONNECT_SERVER)
1018  {
1019  stateConnectServer1();
1020  }
1021  else if (mState == State::WORLD_SELECT)
1022  {
1023  stateWorldSelect1();
1024  }
1025  else if (mOldState == State::START ||
1026  (mOldState == State::GAME && mState != State::GAME))
1027  {
1028  stateGame1();
1029  }
1030  else if (mState == State::SWITCH_LOGIN)
1031  {
1032  stateSwitchLogin1();
1033  }
1034  BLOCK_END("Client::gameExec 6")
1035 
1036  if (mState != mOldState)
1037  {
1038  BLOCK_START("Client::gameExec 7")
1039  PlayerInfo::stateChange(mState);
1040 
1041  if (mOldState == State::GAME)
1042  {
1043  delete2(mGame);
1050  if (guildHandler != nullptr)
1051  guildHandler->clear();
1052  if (partyHandler != nullptr)
1053  partyHandler->clear();
1054  if (chatLogger != nullptr)
1055  chatLogger->clear();
1056  if (!settings.options.dataPath.empty())
1058  else
1062  }
1063  else if (mOldState == State::CHAR_SELECT)
1064  {
1065  if (mState != State::CHANGEPASSWORD &&
1066  charServerHandler != nullptr)
1067  {
1069  }
1070  }
1071 
1072  mOldState = mState;
1073 
1074  // Get rid of the dialog of the previous state
1075  delete2(mCurrentDialog);
1076 
1077  // State has changed, while the quitDialog was active, it might
1078  // not be correct anymore
1079  if (mQuitDialog != nullptr)
1080  {
1081  mQuitDialog->scheduleDelete();
1082  mQuitDialog = nullptr;
1083  }
1084  BLOCK_END("Client::gameExec 7")
1085 
1086  BLOCK_START("Client::gameExec 8")
1087  switch (mState)
1088  {
1089  case State::CHOOSE_SERVER:
1090  {
1091  BLOCK_START("Client::gameExec STATE_CHOOSE_SERVER")
1092  logger->log1("State: CHOOSE SERVER");
1093  unloadData();
1095 
1096  // Allow changing this using a server choice dialog
1097  // We show the dialog box only if the command-line
1098  // options weren't set.
1099  if (settings.options.serverName.empty() &&
1100  settings.options.serverPort == 0 &&
1101  !branding.getValue("onlineServerList", "a").empty())
1102  {
1103  // Don't allow an alpha opacity
1104  // lower than the default value
1105  theme->setMinimumOpacity(0.8F);
1106 
1107  CREATEWIDGETV(mCurrentDialog, ServerDialog,
1108  &mCurrentServer,
1110  }
1111  else
1112  {
1113  mState = State::CONNECT_SERVER;
1114 
1115  // Reset options so that cancelling or connect
1116  // timeout will show the server dialog.
1117  settings.options.serverName.clear();
1119  }
1120  BLOCK_END("Client::gameExec STATE_CHOOSE_SERVER")
1121  break;
1122  }
1123 
1124  case State::CONNECT_SERVER:
1125  BLOCK_START("Client::gameExec State::CONNECT_SERVER")
1126  logger->log1("State: CONNECT SERVER");
1127  loginData.updateHosts.clear();
1128  CREATEWIDGETV(mCurrentDialog, ConnectionDialog,
1129  // TRANSLATORS: connection dialog header
1130  _("Connecting to server"),
1134  pincodeManager.init();
1135  BLOCK_END("Client::gameExec State::CONNECT_SERVER")
1136  break;
1137 
1138  case State::PRE_LOGIN:
1139  logger->log1("State: PRE_LOGIN");
1140  break;
1141 
1142  case State::LOGIN:
1143  BLOCK_START("Client::gameExec State::LOGIN")
1144  logger->log1("State: LOGIN");
1145  // Don't allow an alpha opacity
1146  // lower than the default value
1147  theme->setMinimumOpacity(0.8F);
1148 
1149  if (packetVersion == 0)
1150  {
1152  if (packetVersion != 0)
1153  {
1155  logger->log("Preconfigured packet version: %d",
1156  packetVersion);
1157  }
1158  }
1159 
1160  loginData.updateType = static_cast<UpdateTypeT>(
1161  serverConfig.getValue("updateType", 0));
1162 
1164  const_cast<char*>(mCurrentServer.hostname.c_str()),
1165  CAST_S32(mCurrentServer.hostname.size()));
1166  if (settings.options.username.empty() ||
1167  settings.options.password.empty())
1168  {
1169  CREATEWIDGETV(mCurrentDialog, LoginDialog,
1170  loginData,
1171  &mCurrentServer,
1173  }
1174  else
1175  {
1176  mState = State::LOGIN_ATTEMPT;
1177  // Clear the password so that when login fails, the
1178  // dialog will show up next time.
1179  settings.options.password.clear();
1180  }
1181  BLOCK_END("Client::gameExec State::LOGIN")
1182  break;
1183 
1184  case State::LOGIN_ATTEMPT:
1185  BLOCK_START("Client::gameExec State::LOGIN_ATTEMPT")
1186  logger->log1("State: LOGIN ATTEMPT");
1187  CREATEWIDGETV(mCurrentDialog, ConnectionDialog,
1188  // TRANSLATORS: connection dialog header
1189  _("Logging in"),
1191  if (loginHandler != nullptr)
1193  BLOCK_END("Client::gameExec State::LOGIN_ATTEMPT")
1194  break;
1195 
1196  case State::WORLD_SELECT:
1197  BLOCK_START("Client::gameExec State::WORLD_SELECT")
1198  logger->log1("State: WORLD SELECT");
1199  {
1202  if (loginHandler == nullptr)
1203  {
1204  BLOCK_END("Client::gameExec State::WORLD_SELECT")
1205  break;
1206  }
1207  Worlds worlds = loginHandler->getWorlds();
1208 
1209  if (worlds.empty())
1210  {
1211  // Trust that the netcode knows what it's doing
1212  mState = State::UPDATE;
1213  }
1214  else if (worlds.size() == 1)
1215  {
1217  0, mCurrentServer.persistentIp);
1218  mState = State::UPDATE;
1219  }
1220  else
1221  {
1222  CREATEWIDGETV(mCurrentDialog, WorldSelectDialog,
1223  worlds);
1225  {
1226  static_cast<WorldSelectDialog*>(mCurrentDialog)
1227  ->action(ActionEvent(nullptr, "ok"));
1228  }
1229  }
1230  }
1231  BLOCK_END("Client::gameExec State::WORLD_SELECT")
1232  break;
1233 
1235  BLOCK_START("Client::gameExec State::WORLD_SELECT_ATTEMPT")
1236  logger->log1("State: WORLD SELECT ATTEMPT");
1237  CREATEWIDGETV(mCurrentDialog, ConnectionDialog,
1238  // TRANSLATORS: connection dialog header
1239  _("Entering game world"),
1241  BLOCK_END("Client::gameExec State::WORLD_SELECT_ATTEMPT")
1242  break;
1243 
1244  case State::UPDATE:
1245  BLOCK_START("Client::gameExec State::UPDATE")
1246  logger->log1("State: UPDATE");
1247 
1248  // Determine which source to use for the update host
1249  if (!settings.options.updateHost.empty())
1251  else
1254 
1255  if (!settings.oldUpdates.empty())
1257 
1259  {
1260  mState = State::LOAD_DATA;
1261  settings.oldUpdates.clear();
1263  }
1264  else if ((loginData.updateType & UpdateType::Skip) != 0)
1265  {
1269  mState = State::LOAD_DATA;
1270  }
1271  else
1272  {
1275  CREATEWIDGETV(mCurrentDialog, UpdaterWindow,
1278  settings.options.dataPath.empty(),
1280  }
1281  BLOCK_END("Client::gameExec State::UPDATE")
1282  break;
1283 
1284  case State::LOAD_DATA:
1285  {
1286  BLOCK_START("Client::gameExec State::LOAD_DATA")
1287  logger->log1("State: LOAD DATA");
1288 
1289  loadData();
1290 
1291  mState = State::GET_CHARACTERS;
1292  BLOCK_END("Client::gameExec State::LOAD_DATA")
1293  break;
1294  }
1295  case State::GET_CHARACTERS:
1296  BLOCK_START("Client::gameExec State::GET_CHARACTERS")
1297  logger->log1("State: GET CHARACTERS");
1298  CREATEWIDGETV(mCurrentDialog, ConnectionDialog,
1299  // TRANSLATORS: connection dialog header
1300  _("Requesting characters"),
1302  if (charServerHandler != nullptr)
1304  BLOCK_END("Client::gameExec State::GET_CHARACTERS")
1305  break;
1306 
1307  case State::CHAR_SELECT:
1308  BLOCK_START("Client::gameExec State::CHAR_SELECT")
1309  logger->log1("State: CHAR SELECT");
1310  // Don't allow an alpha opacity
1311  // lower than the default value
1312  theme->setMinimumOpacity(0.8F);
1313 
1316 
1317  CREATEWIDGETV(mCurrentDialog, CharSelectDialog,
1318  loginData);
1320 
1321  if (!(static_cast<CharSelectDialog*>(mCurrentDialog))
1322  ->selectByName(settings.options.character,
1324  {
1325  (static_cast<CharSelectDialog*>(mCurrentDialog))
1326  ->selectByName(
1327  serverConfig.getValue("lastCharacter", ""),
1331  }
1332 
1333  // Choosing character on the command line should work only
1334  // once, clear it so that 'switch character' works.
1335  settings.options.character.clear();
1336  BLOCK_END("Client::gameExec State::CHAR_SELECT")
1337  break;
1338 
1339  case State::CONNECT_GAME:
1340  BLOCK_START("Client::gameExec State::CONNECT_GAME")
1341  logger->log1("State: CONNECT GAME");
1342  CREATEWIDGETV(mCurrentDialog, ConnectionDialog,
1343  // TRANSLATORS: connection dialog header
1344  _("Connecting to the game server"),
1346  if (gameHandler != nullptr)
1347  gameHandler->connect();
1348  BLOCK_END("Client::gameExec State::CONNECT_GAME")
1349  break;
1350 
1351  case State::CHANGE_MAP:
1352  BLOCK_START("Client::gameExec State::CHANGE_MAP")
1353  logger->log1("State: CHANGE_MAP");
1354  CREATEWIDGETV(mCurrentDialog, ConnectionDialog,
1355  // TRANSLATORS: connection dialog header
1356  _("Changing game servers"),
1358  if (gameHandler != nullptr)
1359  gameHandler->connect();
1360  BLOCK_END("Client::gameExec State::CHANGE_MAP")
1361  break;
1362 
1363  case State::GAME:
1364  BLOCK_START("Client::gameExec State::GAME")
1365  if (localPlayer != nullptr)
1366  {
1367  logger->log("Memorizing selected character %s",
1368  localPlayer->getName().c_str());
1369  serverConfig.setValue("lastCharacter",
1370  localPlayer->getName());
1371 #ifdef USE_MUMBLE
1372  if (mumbleManager)
1373  mumbleManager->setPlayer(localPlayer->getName());
1374 #endif // USE_MUMBLE
1375  }
1376 
1377  // Fade out logon-music here too to give the desired effect
1378  // of "flowing" into the game.
1379  soundManager.fadeOutMusic(1000);
1380 
1381  // Allow any alpha opacity
1382  theme->setMinimumOpacity(-1.0F);
1383 
1384  if (chatLogger != nullptr)
1386 
1387 #ifdef ANDROID
1388  delete2(mCloseButton);
1389 #endif // ANDROID
1390 
1391  delete2(mSetupButton);
1392  delete2(mVideoButton);
1393  delete2(mThemesButton);
1394  delete2(mAboutButton);
1395  delete2(mHelpButton);
1396  delete2(mPerfomanceButton);
1397  delete2(desktop);
1398 
1399  mCurrentDialog = nullptr;
1400 
1401  logger->log1("State: GAME");
1402  if (generalHandler != nullptr)
1404  mGame = new Game;
1405  BLOCK_END("Client::gameExec State::GAME")
1406  break;
1407 
1408  case State::LOGIN_ERROR:
1409  BLOCK_START("Client::gameExec State::LOGIN_ERROR")
1410  logger->log1("State: LOGIN ERROR");
1411  CREATEWIDGETV(mCurrentDialog, OkDialog,
1412  // TRANSLATORS: error dialog header
1413  _("Error"),
1414  errorMessage,
1415  // TRANSLATORS: ok dialog button
1416  _("Close"),
1418  Modal_true,
1420  nullptr,
1421  260);
1422  mCurrentDialog->addActionListener(&loginListener);
1423  mCurrentDialog = nullptr; // OkDialog deletes itself
1424  BLOCK_END("Client::gameExec State::LOGIN_ERROR")
1425  break;
1426 
1428  BLOCK_START("Client::gameExec State::ACCOUNTCHANGE_ERROR")
1429  logger->log1("State: ACCOUNT CHANGE ERROR");
1430  CREATEWIDGETV(mCurrentDialog, OkDialog,
1431  // TRANSLATORS: error dialog header
1432  _("Error"),
1433  errorMessage,
1434  // TRANSLATORS: ok dialog button
1435  _("Close"),
1437  Modal_true,
1439  nullptr,
1440  260);
1441  mCurrentDialog->addActionListener(&accountListener);
1442  mCurrentDialog = nullptr; // OkDialog deletes itself
1443  BLOCK_END("Client::gameExec State::ACCOUNTCHANGE_ERROR")
1444  break;
1445 
1446  case State::REGISTER_PREP:
1447  BLOCK_START("Client::gameExec State::REGISTER_PREP")
1448  logger->log1("State: REGISTER_PREP");
1449  CREATEWIDGETV(mCurrentDialog, ConnectionDialog,
1450  // TRANSLATORS: connection dialog header
1451  _("Requesting registration details"),
1452  State::LOGIN);
1454  BLOCK_END("Client::gameExec State::REGISTER_PREP")
1455  break;
1456 
1457  case State::REGISTER:
1458  logger->log1("State: REGISTER");
1459  CREATEWIDGETV(mCurrentDialog, RegisterDialog,
1460  loginData);
1461  break;
1462 
1464  BLOCK_START("Client::gameExec State::REGISTER_ATTEMPT")
1465  logger->log("Username is %s", loginData.username.c_str());
1466  if (loginHandler != nullptr)
1468  BLOCK_END("Client::gameExec State::REGISTER_ATTEMPT")
1469  break;
1470 
1471  case State::CHANGEPASSWORD:
1472  BLOCK_START("Client::gameExec State::CHANGEPASSWORD")
1473  logger->log1("State: CHANGE PASSWORD");
1474  CREATEWIDGETV(mCurrentDialog, ChangePasswordDialog,
1475  loginData);
1476  mCurrentDialog->setVisible(Visible_true);
1477  BLOCK_END("Client::gameExec State::CHANGEPASSWORD")
1478  break;
1479 
1481  BLOCK_START("Client::gameExec "
1482  "State::CHANGEPASSWORD_ATTEMPT")
1483  logger->log1("State: CHANGE PASSWORD ATTEMPT");
1484  if (loginHandler != nullptr)
1485  {
1488  }
1489  BLOCK_END("Client::gameExec State::CHANGEPASSWORD_ATTEMPT")
1490  break;
1491 
1493  BLOCK_START("Client::gameExec "
1494  "State::CHANGEPASSWORD_SUCCESS")
1495  logger->log1("State: CHANGE PASSWORD SUCCESS");
1496  CREATEWIDGETV(mCurrentDialog, OkDialog,
1497  // TRANSLATORS: password change message header
1498  _("Password Change"),
1499  // TRANSLATORS: password change message text
1500  _("Password changed successfully!"),
1501  // TRANSLATORS: ok dialog button
1502  _("OK"),
1504  Modal_true,
1506  nullptr,
1507  260);
1508  mCurrentDialog->addActionListener(&accountListener);
1509  mCurrentDialog = nullptr; // OkDialog deletes itself
1511  loginData.newPassword.clear();
1512  BLOCK_END("Client::gameExec State::CHANGEPASSWORD_SUCCESS")
1513  break;
1514 
1515  case State::CHANGEEMAIL:
1516  logger->log1("State: CHANGE EMAIL");
1517  CREATEWIDGETV(mCurrentDialog,
1519  loginData);
1520  mCurrentDialog->setVisible(Visible_true);
1521  break;
1522 
1524  logger->log1("State: CHANGE EMAIL ATTEMPT");
1525  if (loginHandler != nullptr)
1527  break;
1528 
1530  logger->log1("State: CHANGE EMAIL SUCCESS");
1531  CREATEWIDGETV(mCurrentDialog, OkDialog,
1532  // TRANSLATORS: email change message header
1533  _("Email Change"),
1534  // TRANSLATORS: email change message text
1535  _("Email changed successfully!"),
1536  // TRANSLATORS: ok dialog button
1537  _("OK"),
1539  Modal_true,
1541  nullptr,
1542  260);
1543  mCurrentDialog->addActionListener(&accountListener);
1544  mCurrentDialog = nullptr; // OkDialog deletes itself
1545  break;
1546 
1547  case State::SWITCH_SERVER:
1548  BLOCK_START("Client::gameExec State::SWITCH_SERVER")
1549  logger->log1("State: SWITCH SERVER");
1550 
1551  if (loginHandler != nullptr)
1553  if (gameHandler != nullptr)
1554  {
1556  gameHandler->clear();
1557  }
1558  settings.serverName.clear();
1559  settings.login.clear();
1561  serverConfig.write();
1562  serverConfig.unload();
1563  if (setupWindow != nullptr)
1565 
1566  mState = State::CHOOSE_SERVER;
1567  BLOCK_END("Client::gameExec State::SWITCH_SERVER")
1568  break;
1569 
1570  case State::SWITCH_LOGIN:
1571  BLOCK_START("Client::gameExec State::SWITCH_LOGIN")
1572  logger->log1("State: SWITCH LOGIN");
1573 
1574  if (loginHandler != nullptr)
1575  {
1576  loginHandler->logout();
1578  }
1579  if (gameHandler != nullptr)
1581  if (loginHandler != nullptr)
1582  loginHandler->connect();
1583 
1584  settings.login.clear();
1586  mState = State::LOGIN;
1587  BLOCK_END("Client::gameExec State::SWITCH_LOGIN")
1588  break;
1589 
1591  BLOCK_START("Client::gameExec State::SWITCH_CHARACTER")
1592  logger->log1("State: SWITCH CHARACTER");
1593 
1594  // Done with game
1595  if (gameHandler != nullptr)
1597 
1598  settings.login.clear();
1600  mState = State::GET_CHARACTERS;
1601  BLOCK_END("Client::gameExec State::SWITCH_CHARACTER")
1602  break;
1603 
1604  case State::LOGOUT_ATTEMPT:
1605  logger->log1("State: LOGOUT ATTEMPT");
1606  break;
1607 
1608  case State::WAIT:
1609  logger->log1("State: WAIT");
1610  break;
1611 
1612  case State::EXIT:
1613  BLOCK_START("Client::gameExec State::EXIT")
1614  logger->log1("State: EXIT");
1615  Net::unload();
1616  BLOCK_END("Client::gameExec State::EXIT")
1617  break;
1618 
1619  case State::FORCE_QUIT:
1620  BLOCK_START("Client::gameExec State::FORCE_QUIT")
1621  logger->log1("State: FORCE QUIT");
1622  if (generalHandler != nullptr)
1624  mState = State::EXIT;
1625  BLOCK_END("Client::gameExec State::FORCE_QUIT")
1626  break;
1627 
1628  case State::ERROR:
1629  BLOCK_START("Client::gameExec State::ERROR")
1630  config.write();
1631  if (mOldState == State::GAME)
1632  serverConfig.write();
1633  logger->log1("State: ERROR");
1634  logger->log("Error: %s\n", errorMessage.c_str());
1636  mCurrentDialog = DialogsManager::openErrorDialog(
1637  // TRANSLATORS: error message header
1638  _("Error"),
1639  errorMessage,
1640  Modal_true);
1641  mCurrentDialog->addActionListener(&errorListener);
1642  mCurrentDialog = nullptr; // OkDialog deletes itself
1644  BLOCK_END("Client::gameExec State::ERROR")
1645  break;
1646 
1648  // ++++++
1649  break;
1650 
1651  case State::START:
1652  default:
1653  mState = State::FORCE_QUIT;
1654  break;
1655  }
1656  BLOCK_END("Client::gameExec 8")
1657  }
1658  PROFILER_END();
1659  }
1660 
1661  return 0;
1662 }
1663 
1664 void Client::optionChanged(const std::string &name)
1665 {
1666  if (name == "fpslimit")
1667  {
1668  const int fpsLimit = config.getIntValue("fpslimit");
1669  settings.limitFps = fpsLimit > 0;
1670  WindowManager::setFramerate(fpsLimit);
1671  }
1672  else if (name == "guialpha" ||
1673  name == "enableGuiOpacity")
1674  {
1675  const float alpha = config.getFloatValue("guialpha");
1676  settings.guiAlpha = alpha;
1677  ImageHelper::setEnableAlpha(alpha != 1.0F &&
1678  config.getBoolValue("enableGuiOpacity"));
1679  }
1680  else if (name == "gamma" ||
1681  name == "enableGamma")
1682  {
1684  }
1685  else if (name == "particleEmitterSkip")
1686  {
1688  config.getIntValue("particleEmitterSkip") + 1;
1689  }
1690  else if (name == "vsync")
1691  {
1693  }
1694  else if (name == "repeateInterval" ||
1695  name == "repeateDelay")
1696  {
1698  }
1699 }
1700 
1701 void Client::action(const ActionEvent &event)
1702 {
1703  std::string tab;
1704  const std::string &eventId = event.getId();
1705 
1706  if (eventId == "close")
1707  {
1708  setState(State::FORCE_QUIT);
1709  return;
1710  }
1711  if (eventId == "Setup")
1712  {
1713  tab.clear();
1714  }
1715  else if (eventId == "help")
1716  {
1718  return;
1719  }
1720  else if (eventId == "about")
1721  {
1723  return;
1724  }
1725  else if (eventId == "Video")
1726  {
1727  tab = "Video";
1728  }
1729  else if (eventId == "Themes")
1730  {
1731  tab = "Theme";
1732  }
1733  else if (eventId == "Perfomance")
1734  {
1735  tab = "Perfomance";
1736  }
1737  else
1738  {
1739  return;
1740  }
1741 
1742  if (setupWindow != nullptr)
1743  {
1747  {
1748  if (!tab.empty())
1749  setupWindow->activateTab(tab);
1751  }
1752  }
1753 }
1754 
1756 {
1757  features.init(paths.getStringValue("featuresFile"),
1759  SkipError_true);
1761  settings.fixDeadAnimation = features.getBoolValue("fixDeadAnimation");
1762 }
1763 
1764 void Client::initPaths()
1765 {
1766  settings.gmCommandSymbol = paths.getStringValue("gmCommandSymbol");
1767  settings.gmCharCommandSymbol = paths.getStringValue("gmCharCommandSymbol");
1768  settings.linkCommandSymbol = paths.getStringValue("linkCommandSymbol");
1769  if (settings.linkCommandSymbol.empty())
1771  settings.overweightPercent = paths.getIntValue("overweightPercent");
1773  "playerNameOffset");
1775  "playerBadgeAtRightOffset");
1776  settings.unknownSkillsAutoTab = paths.getBoolValue("unknownSkillsAutoTab");
1777  settings.enableNewMailSystem = paths.getBoolValue("enableNewMailSystem");
1778 }
1779 
1781 {
1782  const std::string tradeListName =
1783  settings.serverConfigDir + "/tradefilter.txt";
1784 
1785  std::ofstream tradeFile;
1786  struct stat statbuf;
1787 
1788  if ((stat(tradeListName.c_str(), &statbuf) != 0) ||
1789  !S_ISREG(statbuf.st_mode))
1790  {
1791  tradeFile.open(tradeListName.c_str(),
1792  std::ios::out);
1793  if (tradeFile.is_open())
1794  {
1795  tradeFile << ": sell" << std::endl;
1796  tradeFile << ": buy" << std::endl;
1797  tradeFile << ": trade" << std::endl;
1798  tradeFile << "i sell" << std::endl;
1799  tradeFile << "i buy" << std::endl;
1800  tradeFile << "i trade" << std::endl;
1801  tradeFile << "i trading" << std::endl;
1802  tradeFile << "i am buy" << std::endl;
1803  tradeFile << "i am sell" << std::endl;
1804  tradeFile << "i am trade" << std::endl;
1805  tradeFile << "i am trading" << std::endl;
1806  tradeFile << "i'm buy" << std::endl;
1807  tradeFile << "i'm sell" << std::endl;
1808  tradeFile << "i'm trade" << std::endl;
1809  tradeFile << "i'm trading" << std::endl;
1810  }
1811  else
1812  {
1813  reportAlways("Error opening file for writing: %s",
1814  tradeListName.c_str());
1815  }
1816  tradeFile.close();
1817  }
1818 }
1819 
1820 bool Client::isTmw()
1821 {
1822  const std::string &name = settings.serverName;
1823  if (name == "server.themanaworld.org" ||
1824  name == "themanaworld.org" ||
1825  name == "167.114.129.72")
1826  {
1827  return true;
1828  }
1829  return false;
1830 }
1831 
1832 void Client::moveButtons(const int width)
1833 {
1834  if (mSetupButton != nullptr)
1835  {
1836  int x = width - mSetupButton->getWidth() - mButtonPadding;
1837  mSetupButton->setPosition(x, mButtonPadding);
1838 #ifndef WIN32
1839  x -= mPerfomanceButton->getWidth() + mButtonSpacing;
1840  mPerfomanceButton->setPosition(x, mButtonPadding);
1841 
1842  x -= mVideoButton->getWidth() + mButtonSpacing;
1843  mVideoButton->setPosition(x, mButtonPadding);
1844 
1845  x -= mThemesButton->getWidth() + mButtonSpacing;
1846  mThemesButton->setPosition(x, mButtonPadding);
1847 
1848  x -= mAboutButton->getWidth() + mButtonSpacing;
1849  mAboutButton->setPosition(x, mButtonPadding);
1850 
1851  x -= mHelpButton->getWidth() + mButtonSpacing;
1852  mHelpButton->setPosition(x, mButtonPadding);
1853 #ifdef ANDROID
1854  x -= mCloseButton->getWidth() + mButtonSpacing;
1855  mCloseButton->setPosition(x, mButtonPadding);
1856 #endif // ANDROID
1857 #endif // WIN32
1858  }
1859 }
1860 
1861 void Client::windowRemoved(const Window *const window)
1862 {
1863  if (mCurrentDialog == window)
1864  mCurrentDialog = nullptr;
1865 }
1866 
1867 void Client::focusWindow()
1868 {
1869  if (mCurrentDialog != nullptr)
1870  {
1871  mCurrentDialog->requestFocus();
1872  }
1873 }
1874 
1876 {
1877  if (mCurrentDialog == nullptr ||
1878  mState != State::CHAR_SELECT)
1879  {
1880  return;
1881  }
1882  CharSelectDialog *const dialog =
1883  dynamic_cast<CharSelectDialog*>(mCurrentDialog);
1884  if (dialog != nullptr)
1886 }
1887 
1888 void Client::logVars()
1889 {
1890 #ifdef ANDROID
1891  logger->log("APPDIR: %s", getenv("APPDIR"));
1892  logger->log("DATADIR2: %s", getSdStoragePath().c_str());
1893 #endif // ANDROID
1894 }
1895 
1896 void Client::slowLogic()
1897 {
1898  if ((gameHandler == nullptr) ||
1899  !gameHandler->mustPing())
1900  {
1901  return;
1902  }
1903 
1904  if (get_elapsed_time1(mPing) > 1500)
1905  {
1906  mPing = tick_time;
1907  if (mState == State::UPDATE ||
1908  mState == State::LOGIN ||
1909  mState == State::LOGIN_ATTEMPT ||
1910  mState == State::REGISTER ||
1911  mState == State::REGISTER_ATTEMPT)
1912  {
1913  if (loginHandler != nullptr)
1914  loginHandler->ping();
1915  if (generalHandler != nullptr)
1917  }
1918  else if (mState == State::CHAR_SELECT)
1919  {
1920  if (charServerHandler != nullptr)
1922  if (generalHandler != nullptr)
1924  }
1925  }
1926 }
1927 
1929 {
1930  // If another data path has been set,
1931  // we don't load any other files...
1932  if (settings.options.dataPath.empty())
1933  {
1934  // Add customdata directory
1936  "customdata/",
1937  "zip",
1938  Append_false);
1939  }
1940 
1942  {
1944  settings.updatesDir + "/local/",
1945  "zip",
1946  Append_false);
1947 
1951  "local/"),
1952  Append_false);
1953  }
1954 
1955  logger->log("Init paths");
1956  paths.init("paths.xml",
1958  SkipError_false);
1960  initPaths();
1961  if (SpriteReference::Empty == nullptr)
1962  {
1964  paths.getStringValue("spriteErrorFile"),
1965  0);
1966  }
1967 
1968  if (BeingInfo::unknown == nullptr)
1970 
1971  initFeatures();
1974  PlayerInfo::stateChange(mState);
1975 
1978 
1979  delete spellManager;
1980  spellManager = new SpellManager;
1981  delete spellShortcut;
1983 
1985 
1987 
1988  if (desktop != nullptr)
1990 }
1991 
1993 {
1995  mCurrentServer.supportUrl.clear();
1996  settings.supportUrl.clear();
1997  if (settings.options.dataPath.empty())
1998  {
1999  // Add customdata directory
2001  "customdata/",
2002  "zip");
2003  }
2004 
2005  if (!settings.oldUpdates.empty())
2006  {
2008  settings.oldUpdates.clear();
2009  }
2010 
2012  {
2014  pathJoin(settings.updatesDir, "local/"),
2015  "zip");
2016 
2020  "local/"));
2021  }
2022 
2024 
2026  localClan.clear();
2027  serverVersion = 0;
2028  packetVersion = 0;
2029  packetVersionMain = 0;
2030  packetVersionRe = 0;
2031  packetVersionZero = 0;
2032  tmwServerVersion = 0;
2033  evolPacketOffset = 0;
2034 }
2035 
2037 {
2038  loadData();
2040 
2042  unloadData();
2043  delete2(client);
2044  VirtFs::deinit();
2045  exit(0);
2046 }
Definition: logger.h:67
void setSize(const int width, const int height)
Definition: widget.cpp:366
void gameInit()
Definition: client.cpp:168
virtual void updatePacketVersion() const =0
#define A_DELETE_COPY(func)
Definition: localconsts.h:52
Configuration branding
void stateSwitchLogin1()
Definition: client.cpp:941
void testsClear()
Definition: client.cpp:163
static void unloadUpdates(const std::string &dir)
bool ipc
Definition: options.h:99
const bool UseVirtFs_false
Definition: usevirtfs.h:29
bool deinit()
Definition: fs.cpp:784
std::string test
Definition: options.h:87
std::vector< WorldInfo * > Worlds
Definition: worldinfo.h:58
void stateGame1()
Definition: client.cpp:899
void deinit()
Definition: playerinfo.cpp:435
static bool isTmw()
Definition: client.cpp:836
Uint32 SDL_framerateDelay(FPSmanager *manager)
Delay execution to maintain a constant framerate and calculate fps.
std::string getStringValue(const std::string &key) const
void slowLogic()
Definition: gui.cpp:322
#define _(s)
Definition: gettext.h:34
DropShortcut * dropShortcut
static void init()
int exec(const bool testAudio=true)
Definition: testmain.cpp:77
const bool SkipError_false
Definition: skiperror.h:29
int packetVersion
Definition: logindata.h:72
void logic()
Definition: gui.cpp:301
void unload()
Definition: net.cpp:173
static void initTempDir()
Definition: dirs.cpp:380
volatile bool isTerminate
Definition: client.cpp:206
int getWidth() const
Definition: widget.h:220
void log1(const char *const log_text)
Definition: logger.cpp:233
static SpriteReference * Empty
void unloadData()
Definition: client.cpp:1992
void activateTab(const std::string &name)
ImageHelper * imageHelper
Definition: imagehelper.cpp:43
std::string logFileName
Definition: options.h:82
int packetVersion
Definition: client.cpp:124
std::string updatesDir
Definition: settings.h:108
std::string serverName
Definition: settings.h:112
static void storeSafeParameters()
virtual void flushNetwork() const =0
unsigned int tmwServerVersion
Definition: client.cpp:132
std::string linkCommandSymbol
Definition: settings.h:125
#define PROFILER_END()
Definition: perfomance.h:77
volatile bool runCounters
Definition: client.cpp:121
volatile int tick_time
Definition: timer.cpp:52
Gui * gui
Definition: gui.cpp:110
std::string registerUrl
Definition: logindata.h:68
void setState(const StateT state)
Definition: client.h:65
const bool Visible_true
Definition: visible.h:29
LoginData loginData
Definition: client.cpp:183
static void stop()
Definition: ipc.cpp:153
std::string onlineListUrl
Definition: settings.h:114
static void initUsersDir()
Definition: dirs.cpp:594
time_t start_time
Definition: client.cpp:133
Joystick * joystick
Definition: joystick.cpp:42
virtual const Worlds & getWorlds() const =0
static void extractDataDir()
Definition: dirs.cpp:178
WindowContainer * windowContainer
bool mountDir(std::string newDir, const Append append)
Definition: fs.cpp:392
static const uint16_t DEFAULT_PORT
Definition: net.h:31
void setBrandingDefaults(Configuration &cfg)
Definition: defaults.cpp:474
static void initFeatures()
Definition: client.cpp:1755
bool fixDeadAnimation
Definition: settings.h:157
void init()
Definition: playerinfo.cpp:431
SpellManager * spellManager
Options options
Definition: settings.h:128
static void initLang()
static void deleteRenderers()
bool registerLogin
Definition: logindata.h:74
int textures_count
Definition: client.cpp:136
static void backupConfig(const std::string &name)
virtual void getRegistrationDetails() const =0
int packetVersionZero
Definition: client.cpp:127
bool persistentIp
Definition: settings.h:150
void searchAndRemoveArchives(const std::string &path, const std::string &ext)
Definition: tools.cpp:61
std::string chatLogDir
Definition: options.h:83
std::string serverType
Definition: options.h:89
volatile int frame_count
Definition: timer.cpp:55
std::string pathJoin(std::string str1, const std::string &str2)
void setFeaturesDefaults(Configuration &cfg)
Definition: defaults.cpp:735
std::string serverName
Definition: options.h:88
virtual void requestMoveToTop()
Definition: widget.cpp:212
virtual void changePassword(const std::string &oldPassword, const std::string &newPassword) const =0
static BeingInfo * unknown
Definition: beinginfo.h:55
Definition: window.h:98
bool packets_main
Definition: client.cpp:129
bool unmountDirSilent(std::string oldDir)
Definition: fs.cpp:553
bool packets_zero
Definition: client.cpp:131
virtual void unload() const =0
#define BLOCK_START(name)
Definition: perfomance.h:78
Definition: button.h:96
SoundManager soundManager
Configuration config
#define final
Definition: localconsts.h:45
void clear()
Definition: playerinfo.cpp:449
static std::string getThemePath()
Definition: theme.h:66
static void updateDataPath()
Definition: dirs.cpp:160
static ServerTypeT parseType(const std::string &serverType)
Definition: serverinfo.h:196
void fadeOutMusic(const int ms)
static void initFunctions()
Definition: dyepalette.cpp:252
PopupManager * popupManager
static void prepareSlotNames()
static void loadDirMods(const std::string &dir)
bool limitFps
Definition: settings.h:151
Skin * load(const std::string &filename, const std::string &filename2, const bool full, const std::string &defaultPath)
Definition: theme.cpp:178
#define BLOCK_END(name)
Definition: perfomance.h:79
static int emitterSkip
IPC * ipc
Definition: ipc.cpp:36
std::string supportUrl
Definition: settings.h:119
static void selectSkin()
Definition: theme.cpp:597
virtual void updateScreen()=0
void deleteValidateWindows()
int getIntValue(const std::string &key) const
std::string brandingPath
Definition: options.h:78
float getFloatValue(const std::string &key) const
void draw()
Definition: gui.cpp:469
anonymous_namespace{client.cpp}::LoginListener loginListener
bool packets_re
Definition: client.cpp:130
void loadDb()
Definition: dbmanager.cpp:62
Client * client
Definition: client.cpp:117
#define CREATEWIDGETV(var, type,...)
Definition: createwidget.h:24
#define delete2(var)
Definition: delete2.h:24
const Image *restrict const top
Configuration serverConfig
Net::GuildHandler * guildHandler
Definition: net.cpp:88
Definition: gui.h:115
LocalClan localClan
Definition: localclan.cpp:25
void clear()
Definition: localclan.h:47
static void clearParties()
Definition: party.cpp:327
void clear()
Definition: chatlogger.cpp:228
Net::GeneralHandler * generalHandler
Definition: net.cpp:84
StringVect updateHosts
Definition: logindata.h:62
int getWidth() const
Definition: graphics.cpp:642
static void setEnableAlpha(const bool n)
Definition: imagehelper.h:97
void externalUnload()
int playerBadgeAtRightOffset
Definition: settings.h:147
virtual void reloadPartially() const =0
static void initTradeFilter()
Definition: client.cpp:1780
virtual void clear() const =0
std::vector< std::string > updateMirrors
Definition: settings.h:127
void addListener(const std::string &key, ConfigListener *const listener)
void initPacketLimiter()
bool enableRemoteCommands
Definition: settings.h:159
virtual void clear() const =0
void stateConnectGame1()
Definition: client.cpp:801
Logger * logger
Definition: logger.cpp:88
std::string localDataDir
Definition: settings.h:110
void searchAndAddArchives(const std::string &path, const std::string &ext, const Append append)
Definition: tools.cpp:40
void postInit(Graphics *const graphics)
Definition: gui.cpp:150
void testsInit()
Definition: client.cpp:159
void update()
Definition: joystick.cpp:350
std::string email
Definition: logindata.h:66
std::string character
Definition: options.h:77
static void clearGuilds()
Definition: guild.cpp:380
std::string errorMessage
Definition: client.cpp:115
Settings settings
Definition: settings.cpp:31
std::string newPassword
Definition: logindata.h:60
int getPadding() const
Definition: skin.h:99
void setBaseLogDir(const std::string &logDir)
Definition: chatlogger.h:63
std::string gmCommandSymbol
Definition: settings.h:123
virtual void flushSend() const =0
static void initConfigDir()
Definition: dirs.cpp:393
static void clearInstance()
Definition: game.h:84
#define CAST_U16
Definition: cast.h:28
bool safeMode
Definition: options.h:97
const bool UseVirtFs_true
Definition: usevirtfs.h:29
bool getBoolValue(const std::string &key) const
volatile int logic_count
Definition: timer.cpp:56
int get_elapsed_time1(const int startTime)
Definition: timer.cpp:104
std::string updateHost
Definition: logindata.h:61
FPSmanager fpsManager
bool handleInput()
Definition: gui.cpp:387
std::string logFileName
Definition: settings.h:120
#define CAST_S32
Definition: cast.h:29
virtual void beginDraw()
Definition: graphics.h:440
const std::string BUTTON_SKIN
Definition: button.h:88
const std::string & getConfigPath() const
std::string strprintf(const char *const format,...)
Definition: stringutils.cpp:99
void setFramerate(const unsigned int fpsLimit)
static void initRootDir()
Definition: dirs.cpp:265
void startTimers()
Definition: timer.cpp:112
void updateScreenKeyboard(const int height)
Net::LoginHandler * loginHandler
Definition: net.cpp:86
static void cleanUp()
Definition: graphics.cpp:158
#define fromBool(val, name)
Definition: booldefines.h:48
bool error
Definition: options.h:101
std::string serverConfigDir
Definition: settings.h:115
std::string oldUpdates
Definition: settings.h:107
Definition: game.h:62
virtual void disconnect() const =0
void setLogLevel(const int level)
Definition: sdlhelper.cpp:190
std::string updateHost
Definition: options.h:79
static void unloadMods(const std::string &dir)
LocalPlayer * localPlayer
void safeError(const std::string &error_text) __attribute__((noreturn))
Definition: logger.cpp:430
static void loadLocalUpdates(const std::string &dir)
int getHeight() const
Definition: graphics.cpp:647
bool unknownSkillsAutoTab
Definition: settings.h:161
virtual void ping() const =0
virtual void add(Widget *const widget)
void loadData()
Definition: client.cpp:1928
void moveButtons(const int width)
Definition: client.cpp:772
virtual void loginOrRegister(LoginData *const data) const =0
unsigned int overweightPercent
Definition: settings.h:145
virtual void chooseServer(unsigned int server, const bool persistentIp) const =0
std::string username
Definition: logindata.h:58
void setDebugLog(const bool n)
Definition: logger.h:180
ErrorListener errorListener
void optionChanged(const std::string &name)
Definition: client.cpp:1664
int gameExec()
Definition: client.cpp:575
static void loadCurrentLang()
bool skipUpdate
Definition: options.h:94
Graphics * mainGraphics
Definition: graphics.cpp:108
bool isWindowVisible() const
Definition: window.h:483
static void load()
void setVisible(Visible visible)
const bool ShowCenter_true
Definition: showcenter.h:29
void setSfxVolume(const int volume)
Definition: theme.h:52
const unsigned int SHORTCUT_TABS
Definition: itemshortcut.h:27
static int testsExec()
Definition: client.cpp:831
static std::string savedPassword
Definition: logindialog.h:79
anonymous_namespace{client.cpp}::AccountListener accountListener
#define PRAGMA48(str)
Definition: localconsts.h:190
unsigned int mLastHost
Definition: client.cpp:134
#define PROFILER_START()
Definition: perfomance.h:76
volatile time_t cur_time
Definition: timer.cpp:57
#define FULL_VERSION
Definition: main.h:163
int evolPacketOffset
Definition: net.cpp:39
bool validate
Definition: options.h:102
void initSoundManager()
Definition: client.cpp:388
Definition: client.h:48
std::string dataPath
Definition: options.h:80
ItemShortcut * itemShortcut[SHORTCUT_TABS]
const std::string & getName() const
Definition: being.h:231
void stateConnectServer1()
Definition: client.cpp:811
void setMusicVolume(const int volume)
void setMinimumOpacity(const float minimumOpacity)
Definition: theme.cpp:271
Net::InventoryHandler * inventoryHandler
Definition: net.cpp:85
virtual void clearWorlds() const =0
AssertListener * assertListener
void slowLogic()
Definition: client.cpp:827
EventsManager eventsManager
void focusWindow()
Definition: client.cpp:807
int serverVersion
Definition: client.cpp:123
void dumpLibs()
Definition: dumplibs.cpp:115
bool handleEvents() const
void connectToServer(const ServerInfo &server)
Definition: net.cpp:123
void initRand()
Definition: mrand.cpp:34
Structure holding the state and timing information of the framerate controller.
Configuration paths
bool isSafeMode
Definition: client.cpp:122
std::string password
Definition: options.h:76
static void clearDialogs()
Definition: npcdialog.cpp:1216
UpdateTypeT updateType
Definition: logindata.h:64
EmoteShortcut * emoteShortcut
void playMusic(const std::string &fileName, const SkipError skipError)
virtual void disconnect() const =0
const bool Append_false
Definition: append.h:29
std::string getValue(const std::string &key, const std::string &deflt) const
Theme * theme
Definition: theme.cpp:61
#define A_UNUSED
Definition: localconsts.h:151
PincodeManager pincodeManager
bool Visible
Definition: visible.h:29
Widget * getTop() const
Definition: gui.h:247
void runValidate() __attribute__((noreturn))
Definition: client.cpp:2036
Net::ChatHandler * chatHandler
Definition: net.cpp:82
void loadData()
Definition: playerinfo.cpp:442
virtual void clear() const =0
void removeListeners(ConfigListener *const listener)
bool testMode
Definition: options.h:98
virtual void clear() const =0
bool setWriteDir(const std::string &newDir)
Definition: fs.cpp:330
static void clear()
Definition: beinginfo.cpp:216
int packetVersionRe
Definition: client.cpp:126
void reloadWallpaper()
Definition: desktop.cpp:121
void initLogger()
Definition: sdlhelper.cpp:186
static void start()
Definition: ipc.cpp:162
virtual bool mustPing() const =0
Client()
Definition: client.cpp:138
std::string password
Definition: logindata.h:59
Configuration features
void windowRemoved(const Window *const window)
Definition: client.cpp:801
int renderer
Definition: options.h:90
virtual void connect() const =0
~Client()
Definition: client.cpp:380
void unloadDb()
Definition: dbmanager.cpp:105
void detect()
Definition: cpu.cpp:45
virtual bool isConnected() const =0
void stateWorldSelect1()
Definition: client.cpp:889
Net::PartyHandler * partyHandler
Definition: net.cpp:90
virtual void logout() const =0
void stopTimers()
Definition: timer.cpp:120
void setLogFile(const std::string &logFilename)
Definition: logger.cpp:119
static void mountDataDir()
Definition: dirs.cpp:197
void SDL_initFramerate(FPSmanager *manager)
Initialize the framerate manager.
virtual void postInit()
Definition: graphics.h:461
void stateChange(const StateT state)
Definition: playerinfo.cpp:467
void dumpSizes()
Definition: dumpsizes.cpp:32
std::string configDir
Definition: settings.h:109
void setConfigDefaults2(Configuration &cfg)
Definition: defaults.cpp:427
UpdateType ::T UpdateTypeT
Definition: updatetype.h:35
KeyboardConfig keyboard
static void logVars()
Definition: client.cpp:819
void gameClear()
Definition: client.cpp:433
static void initGraphics()
Definition: client.cpp:411
#define override
Definition: localconsts.h:46
SetupWindow * setupWindow
Definition: setupwindow.cpp:63
int playerNameOffset
Definition: settings.h:146
static void initServerConfig(const std::string &serverName)
#define CHECKLISTENERS
Definition: localconsts.h:268
static void initScreenshotDir()
Definition: dirs.cpp:539
void initConfigListeners()
Definition: client.cpp:580
InputManager inputManager
TouchManager touchManager
void error(const std::string &error_text) __attribute__((noreturn))
Definition: logger.cpp:467
void setServerName(const std::string &serverName)
Definition: chatlogger.cpp:176
bool cleanOrphans(const bool always)
void allowScreenSaver(const bool allow)
Definition: sdlhelper.cpp:209
static void loadDictionaryLang()
std::string updateHost
Definition: settings.h:105
void log(const char *const log_text,...)
Definition: logger.cpp:264
int packetVersionMain
Definition: client.cpp:125
static void initUpdatesDir()
Definition: dirs.cpp:446
void clearUpdateHost()
Definition: logindata.h:95
virtual void changeEmail(const std::string &email) const =0
const bool SkipError_true
Definition: skiperror.h:29
Desktop * desktop
Definition: desktop.cpp:48
static unsigned long adlerBuffer(const char *const buffer, int size)
Definition: download.cpp:146
virtual void ping() const =0
unsigned long mSearchHash
Definition: client.cpp:135
bool remember
Definition: logindata.h:73
virtual void clear() const =0
static Window * openErrorDialog(const std::string &header, const std::string &message, const Modal modal)
bool chooseDefault
Definition: options.h:95
float guiAlpha
Definition: settings.h:129
void cleanupXML()
Definition: libxml.cpp:314
Net::GameHandler * gameHandler
Definition: net.cpp:87
void action(const ActionEvent &event)
Definition: client.cpp:730
static void initConfiguration()
virtual bool isConnected() const =0
ChatLogger * chatLogger
Definition: chatlogger.cpp:43
DialogsManager * dialogsManager
void updateEnv()
Definition: env.cpp:29
virtual void connect() const =0
void incValue(const std::string &key)
Net::CharServerHandler * charServerHandler
Definition: net.cpp:81
PlayerRelationsManager playerRelations
bool enableNewMailSystem
Definition: settings.h:162
void init(const std::string &filename, const UseVirtFs useResManager, const SkipError skipError)
virtual void postInit()
Definition: imagehelper.h:109
#define reportAlways(...)
Definition: checkutils.h:252
GraphicsManager graphicsManager
void setValue(const std::string &key, const std::string &value)
std::string gmCharCommandSymbol
Definition: settings.h:124
void update()
Definition: useragent.cpp:31
virtual void registerAccount(const LoginData *const loginData) const =0
void executeAction(const InputActionT keyNum)
static void init()
Definition: joystick.cpp:72
void setReportUnimplemented(const bool n)
Definition: logger.h:183
static void initHomeDir()
Definition: dirs.cpp:329
void init()
Definition: settings.cpp:33
#define ADDBUTTON(var, object)
Definition: client.cpp:796
static void checkConfigVersion()
void updatePinState()
Definition: client.cpp:815
void createValidateWindows()
static void unload()
static void initPaths()
Definition: client.cpp:848
void loadIgnorePackets()
Definition: net.cpp:187
int packetsType
Definition: client.cpp:128
SpellShortcut * spellShortcut
static void initLocalDataDir()
Definition: dirs.cpp:336
virtual void clear() const =0
virtual void requestCharacters() const =0
uint16_t serverPort
Definition: options.h:91
std::string login
Definition: settings.h:106
std::string username
Definition: options.h:75
void setPathsDefaults(Configuration &cfg)
Definition: defaults.cpp:534