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  // Configure logger
305  if (!settings.options.logFileName.empty())
306  {
308  }
309  else
310  {
312  "manaplus.log");
313  }
314  logger->log("Log file: " + settings.logFileName);
316 
317 #ifdef USE_FUZZER
318  Fuzzer::init();
319 #endif // USE_FUZZER
320 
321  if (settings.options.ipc == true)
322  IPC::start();
323  if (settings.options.test.empty())
324  ConfigManager::backupConfig("config.xml");
326  SDL::setLogLevel(config.getIntValue("sdlLogLevel"));
327  settings.init();
330  initFeatures();
331  initPaths();
332  logger->log("init 4");
333  logger->setDebugLog(config.getBoolValue("debugLog"));
334  logger->setReportUnimplemented(config.getBoolValue("unimplimentedLog"));
335 
336  config.incValue("runcount");
337 
338 #ifndef ANDROID
339  if (settings.options.test.empty())
341 #endif // ANDROID
342 
344  {
345  logger->error(strprintf("%s couldn't be set as home directory! "
346  "Exiting.", settings.localDataDir.c_str()));
347  }
348 
350 
351  chatLogger = new ChatLogger;
352  if (settings.options.chatLogDir.empty())
353  {
355  + std::string("/logs/"));
356  }
357  else
358  {
360  }
361 
362  // Log the client version
364  logger->log("Start configPath: " + config.getConfigPath());
365 
367 
368  updateEnv();
369  SDL::allowScreenSaver(config.getBoolValue("allowscreensaver"));
370  dumpLibs();
371  dumpSizes();
372 
373  // Initialize SDL
374  logger->log1("Initializing SDL...");
375  if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0)
376  {
377  logger->safeError(strprintf("Could not initialize SDL: %s",
378  SDL_GetError()));
379  }
380  atexit(SDL_Quit);
381 
383 #ifndef USE_SDL2
384  SDL_EnableUNICODE(1);
385 #endif // USE_SDL2
386 
390 
391 #ifdef WIN32
393 #endif // WIN32
394 #ifndef USE_SDL2
396 #endif // USE_SDL2
397 
399  logVars();
400  Cpu::detect();
402 #if defined(USE_OPENGL)
403 #if !defined(ANDROID) && !defined(__APPLE__) && \
404  !defined(__native_client__) && !defined(UNITTESTS)
405  if (!settings.options.safeMode &&
406  settings.options.renderer < 0 &&
407  settings.options.test.empty() &&
409  !config.getBoolValue("videodetected"))
410  {
412  }
413 #endif // !defined(ANDROID) && !defined(__APPLE__) &&
414  // !defined(__native_client__) && !defined(UNITTESTS)
415 #endif // defined(USE_OPENGL)
416 
417  initGraphics();
419 
420  touchManager.init();
421 
422 #ifndef WIN32
425 #endif // WIN32
426 
428 
429  // Add the main data directories to our VirtFs search path
430  if (!settings.options.dataPath.empty())
431  {
433  Append_false);
434  }
435 
436  // Add the local data directory to VirtFs search path
438  Append_false);
441 #ifdef ENABLE_CUSTOMNLS
442  TranslationManager::loadGettextLang();
443 #endif // ENABLE_CUSTOMNLS
444 
445 #ifdef USE_SDL2
447 #endif // USE_SDL2
449 
451 
452  theme = new Theme;
455  touchManager.init();
456 
457  // Initialize the item and emote shortcuts.
458  for (size_t f = 0; f < SHORTCUT_TABS; f ++)
459  itemShortcut[f] = new ItemShortcut(f);
462 
463  gui = new Gui;
467 
468  initSoundManager();
469 
470  // Initialize keyboard
471  keyboard.init();
472  inputManager.init();
473 
474  // Initialise player relations
476  Joystick::init();
478 
479  keyboard.update();
480  if (joystick != nullptr)
481  joystick->update();
482 
483  // Initialize default server
484  mCurrentServer.hostname = settings.options.serverName;
485  mCurrentServer.port = settings.options.serverPort;
486  if (!settings.options.serverType.empty())
487  {
488  mCurrentServer.type = ServerInfo::parseType(
490  }
491 
495  loginData.remember = (serverConfig.getValue("remember", 1) != 0);
496  loginData.registerLogin = false;
497 
498  if (mCurrentServer.hostname.empty())
499  {
500  mCurrentServer.hostname = branding.getValue("defaultServer", "");
501  settings.options.serverName = mCurrentServer.hostname;
502  }
503 
504  if (mCurrentServer.port == 0)
505  {
506  mCurrentServer.port = CAST_U16(branding.getValue(
507  "defaultPort", CAST_S32(DEFAULT_PORT)));
508  mCurrentServer.type = ServerInfo::parseType(
509  branding.getValue("defaultServerType", "tmwathena"));
510  }
511 
512  chatLogger->setServerName(mCurrentServer.hostname);
513 
514  if (loginData.username.empty() && loginData.remember)
515  loginData.username = serverConfig.getValue("username", "");
516 
517  if (mState != State::ERROR)
518  mState = State::CHOOSE_SERVER;
519 
520  startTimers();
521 
522  const int fpsLimit = config.getIntValue("fpslimit");
523  settings.limitFps = fpsLimit > 0;
524 
526  WindowManager::setFramerate(fpsLimit);
527  initConfigListeners();
528 
529  settings.guiAlpha = config.getFloatValue("guialpha");
530  optionChanged("fpslimit");
531 
532  start_time = time(nullptr);
533 
535 
536 #ifdef ANDROID
537 #ifndef USE_SDL2
538  WindowManager::updateScreenKeyboard(SDL_GetScreenKeyboardHeight(nullptr));
539 #endif // USE_SDL2
540 #endif // ANDROID
541 
542 #ifdef USE_MUMBLE
543  if (!mumbleManager)
544  mumbleManager = new MumbleManager;
545 #endif // USE_MUMBLE
546 
547  mSkin = theme->load("windowmenu.xml",
548  "",
549  true,
551  if (mSkin != nullptr)
552  {
553  mButtonPadding = mSkin->getPadding();
554  mButtonSpacing = mSkin->getOption("spacing", 3);
555  }
556  if (settings.options.error)
558 
559  if (settings.options.validate == true)
560  runValidate();
561 }
562 
564 {
566  gameClear();
567  else
568  testsClear();
570 }
571 
573 {
574  config.addListener("fpslimit", this);
575  config.addListener("guialpha", this);
576  config.addListener("gamma", this);
577  config.addListener("enableGamma", this);
578  config.addListener("particleEmitterSkip", this);
579  config.addListener("vsync", this);
580  config.addListener("repeateDelay", this);
581  config.addListener("repeateInterval", this);
582  config.addListener("logInput", this);
583 }
584 
586 {
587  // Initialize sound engine
588  try
589  {
590  if (config.getBoolValue("sound"))
591  soundManager.init();
592 
595  }
596  catch (const char *const err)
597  {
598  mState = State::ERROR;
599  errorMessage = err;
600  logger->log("Warning: %s", err);
601  }
603  "loginMusic",
604  "keprohm.ogg"),
606 }
607 
609 {
610 #ifndef USE_SDL2
612 #endif // USE_SDL2
613 
614  runCounters = config.getBoolValue("packetcounters");
615 
617 #ifdef USE_SDL2
619 #endif // USE_SDL2
620 
625 
627 }
628 
629 void Client::testsClear()
630 {
631  if (!settings.options.test.empty())
632  gameClear();
633  else
635 }
636 
637 void Client::gameClear()
638 {
639  if (logger != nullptr)
640  logger->log1("Quitting1");
641  isTerminate = true;
642  config.removeListeners(this);
643 
645 
646  IPC::stop();
649  if (windowContainer != nullptr)
651 
652  stopTimers();
654 
655  if (loginHandler != nullptr)
657 
658  if (chatHandler != nullptr)
659  chatHandler->clear();
660 
661  if (charServerHandler != nullptr)
663 
664  delete2(ipc);
665 
666 #ifdef USE_MUMBLE
667  delete2(mumbleManager);
668 #endif // USE_MUMBLE
669 
671 
672  // Before config.write() since it writes the shortcuts to the config
673  for (unsigned f = 0; f < SHORTCUT_TABS; f ++)
677 
679 
680  if (logger != nullptr)
681  logger->log1("Quitting2");
682 
683  delete2(mCurrentDialog);
686  delete2(gui);
687 
688  if (inventoryHandler != nullptr)
690 
691  if (logger != nullptr)
692  logger->log1("Quitting3");
693 
695 
697 
698  if (logger != nullptr)
699  logger->log1("Quitting4");
700 
701  XML::cleanupXML();
702 
703  if (logger != nullptr)
704  logger->log1("Quitting5");
705 
707 
708  // Shutdown sound
710 
711  if (logger != nullptr)
712  logger->log1("Quitting6");
713 
715 
717 
719 
720  if (logger != nullptr)
721  logger->log1("Quitting8");
722 
724 
725  if (logger != nullptr)
726  logger->log1("Quitting9");
727 
728  delete2(joystick);
729 
730  keyboard.deinit();
731 
732  if (logger != nullptr)
733  logger->log1("Quitting10");
734 
736 
737 #ifdef DEBUG_CONFIG
738  config.enableKeyLogging();
739 #endif // DEBUG_CONFIG
740 
742  config.write();
744 
745  config.clear();
747 
748  if (logger != nullptr)
749  logger->log1("Quitting11");
750 
751 #ifdef USE_PROFILER
753 #endif // USE_PROFILER
754 
755 #ifdef DEBUG_OPENGL_LEAKS
756  if (logger)
757  logger->log("textures left: %d", textures_count);
758 #endif // DEBUG_OPENGL_LEAKS
759 
761 
762  if (logger != nullptr)
763  logger->log1("Quitting12");
764 
767 }
768 
769 int Client::testsExec()
770 {
771 #ifdef USE_OPENGL
772  if (settings.options.test.empty())
773  {
774  TestMain test;
775  return test.exec();
776  }
777  else
778  {
779  TestLauncher launcher(settings.options.test);
780  return launcher.exec();
781  }
782 #else // USE_OPENGL
783 
784  return 0;
785 #endif // USE_OPENGL
786 }
787 
788 #define ADDBUTTON(var, object) var = object; \
789  x -= var->getWidth() + mButtonSpacing; \
790  var->setPosition(x, mButtonPadding); \
791  top->add(var);
792 
794 {
795  if ((gameHandler != nullptr) &&
796  (loginHandler != nullptr) &&
798  {
800  }
801 }
802 
804 {
805  if (mOldState == State::CHOOSE_SERVER)
806  {
807  settings.serverName = mCurrentServer.hostname;
808  ConfigManager::initServerConfig(mCurrentServer.hostname);
810  initTradeFilter();
813 
814  // Initialize the item and emote shortcuts.
815  for (unsigned f = 0; f < SHORTCUT_TABS; f ++)
816  {
817  delete itemShortcut[f];
818  itemShortcut[f] = new ItemShortcut(f);
819  }
820  delete emoteShortcut;
822 
823  // Initialize the drop shortcuts.
824  delete dropShortcut;
826 
827  initFeatures();
829  loginData.registerUrl = mCurrentServer.registerUrl;
830  loginData.packetVersion = mCurrentServer.packetVersion;
831  if (!mCurrentServer.onlineListUrl.empty())
832  settings.onlineListUrl = mCurrentServer.onlineListUrl;
833  else
835  settings.persistentIp = mCurrentServer.persistentIp;
836  settings.supportUrl = mCurrentServer.supportUrl;
837  settings.updateMirrors = mCurrentServer.updateMirrors;
839  "enableRemoteCommands", 1) != 0);
840 
841  if (settings.options.username.empty())
842  {
843  if (loginData.remember)
844  loginData.username = serverConfig.getValue("username", "");
845  else
846  loginData.username.clear();
847  }
848  else
849  {
851  }
854 
855  loginData.remember = (serverConfig.getValue("remember", 1) != 0);
856  Net::connectToServer(mCurrentServer);
857 
858 #ifdef USE_MUMBLE
859  if (mumbleManager)
860  mumbleManager->setServer(mCurrentServer.hostname);
861 #endif // USE_MUMBLE
862 
863 #ifdef TMWA_SUPPORT
865 #endif // TMWA_SUPPORT
866 
867  if (!mConfigAutoSaved)
868  {
869  mConfigAutoSaved = true;
870  config.write();
871  }
872  }
873  else if (mOldState != State::CHOOSE_SERVER &&
874  (loginHandler != nullptr) &&
876  {
877  mState = State::PRE_LOGIN;
878  }
879 }
880 
882 {
883  if (mOldState == State::UPDATE &&
884  (loginHandler != nullptr))
885  {
886  if (loginHandler->getWorlds().size() < 2)
887  mState = State::PRE_LOGIN;
888  }
889 }
890 
892 {
893  if (gui == nullptr)
894  return;
895 
896  BasicContainer2 *const top = static_cast<BasicContainer2*>(
897  gui->getTop());
898 
899  if (top == nullptr)
900  return;
901 
902  CREATEWIDGETV(desktop, Desktop, nullptr);
903  top->add(desktop);
904  int x = top->getWidth() - mButtonPadding;
905  ADDBUTTON(mSetupButton, new Button(desktop,
906  // TRANSLATORS: setup tab quick button
907  _("Setup"), "Setup", BUTTON_SKIN, this))
908  ADDBUTTON(mPerfomanceButton, new Button(desktop,
909  // TRANSLATORS: perfoamance tab quick button
910  _("Performance"), "Perfomance", BUTTON_SKIN, this))
911  ADDBUTTON(mVideoButton, new Button(desktop,
912  // TRANSLATORS: video tab quick button
913  _("Video"), "Video", BUTTON_SKIN, this))
914  ADDBUTTON(mThemesButton, new Button(desktop,
915  // TRANSLATORS: theme tab quick button
916  _("Theme"), "Themes", BUTTON_SKIN, this))
917  ADDBUTTON(mAboutButton, new Button(desktop,
918  // TRANSLATORS: theme tab quick button
919  _("About"), "about", BUTTON_SKIN, this))
920  ADDBUTTON(mHelpButton, new Button(desktop,
921  // TRANSLATORS: theme tab quick button
922  _("Help"), "help", BUTTON_SKIN, this))
923 #ifdef ANDROID
924  ADDBUTTON(mCloseButton, new Button(desktop,
925  // TRANSLATORS: close quick button
926  _("Close"), "close", BUTTON_SKIN, this))
927 #endif // ANDROID
928 
931 }
932 
934 {
935  if (mOldState == State::GAME &&
936  (gameHandler != nullptr))
937  {
939  }
940 }
941 
942 int Client::gameExec()
943 {
944  int lastTickTime = tick_time;
945 
946  while (mState != State::EXIT)
947  {
948  PROFILER_START();
950  continue;
951 
952  BLOCK_START("Client::gameExec 3")
953  if (generalHandler != nullptr)
955  BLOCK_END("Client::gameExec 3")
956 
957  BLOCK_START("Client::gameExec 4")
958  if (gui != nullptr)
959  gui->logic();
960  cur_time = time(nullptr);
961  int k = 0;
962  while (lastTickTime != tick_time &&
963  k < 40)
964  {
965  if (mGame != nullptr)
966  mGame->logic();
967  else if (gui != nullptr)
968  gui->handleInput();
969 
970  ++lastTickTime;
971  k ++;
972  }
974 
975  logic_count += k;
976  if (gui != nullptr)
977  gui->slowLogic();
978  if (mGame != nullptr)
979  mGame->slowLogic();
980  slowLogic();
981  BLOCK_END("Client::gameExec 4")
982 
983  // This is done because at some point tick_time will wrap.
984  lastTickTime = tick_time;
985 
986  // Update the screen when application is visible, delay otherwise.
988  {
989  frame_count++;
990  if (gui != nullptr)
991  gui->draw();
993  }
994  else
995  {
996  SDL_Delay(100);
997  }
998 
999  BLOCK_START("~Client::SDL_framerateDelay")
1000  if (settings.limitFps)
1002  BLOCK_END("~Client::SDL_framerateDelay")
1003 
1004  BLOCK_START("Client::gameExec 6")
1005  if (mState == State::CONNECT_GAME)
1006  {
1007  stateConnectGame1();
1008  }
1009  else if (mState == State::CONNECT_SERVER)
1010  {
1011  stateConnectServer1();
1012  }
1013  else if (mState == State::WORLD_SELECT)
1014  {
1015  stateWorldSelect1();
1016  }
1017  else if (mOldState == State::START ||
1018  (mOldState == State::GAME && mState != State::GAME))
1019  {
1020  stateGame1();
1021  }
1022  else if (mState == State::SWITCH_LOGIN)
1023  {
1024  stateSwitchLogin1();
1025  }
1026  BLOCK_END("Client::gameExec 6")
1027 
1028  if (mState != mOldState)
1029  {
1030  BLOCK_START("Client::gameExec 7")
1031  PlayerInfo::stateChange(mState);
1032 
1033  if (mOldState == State::GAME)
1034  {
1035  delete2(mGame);
1042  if (guildHandler != nullptr)
1043  guildHandler->clear();
1044  if (partyHandler != nullptr)
1045  partyHandler->clear();
1046  if (chatLogger != nullptr)
1047  chatLogger->clear();
1048  if (!settings.options.dataPath.empty())
1050  else
1054  }
1055  else if (mOldState == State::CHAR_SELECT)
1056  {
1057  if (mState != State::CHANGEPASSWORD &&
1058  charServerHandler != nullptr)
1059  {
1061  }
1062  }
1063 
1064  mOldState = mState;
1065 
1066  // Get rid of the dialog of the previous state
1067  delete2(mCurrentDialog);
1068 
1069  // State has changed, while the quitDialog was active, it might
1070  // not be correct anymore
1071  if (mQuitDialog != nullptr)
1072  {
1073  mQuitDialog->scheduleDelete();
1074  mQuitDialog = nullptr;
1075  }
1076  BLOCK_END("Client::gameExec 7")
1077 
1078  BLOCK_START("Client::gameExec 8")
1079  switch (mState)
1080  {
1081  case State::CHOOSE_SERVER:
1082  {
1083  BLOCK_START("Client::gameExec STATE_CHOOSE_SERVER")
1084  logger->log1("State: CHOOSE SERVER");
1085  unloadData();
1087 
1088  // Allow changing this using a server choice dialog
1089  // We show the dialog box only if the command-line
1090  // options weren't set.
1091  if (settings.options.serverName.empty() &&
1092  settings.options.serverPort == 0 &&
1093  !branding.getValue("onlineServerList", "a").empty())
1094  {
1095  // Don't allow an alpha opacity
1096  // lower than the default value
1097  theme->setMinimumOpacity(0.8F);
1098 
1099  CREATEWIDGETV(mCurrentDialog, ServerDialog,
1100  &mCurrentServer,
1102  }
1103  else
1104  {
1105  mState = State::CONNECT_SERVER;
1106 
1107  // Reset options so that cancelling or connect
1108  // timeout will show the server dialog.
1109  settings.options.serverName.clear();
1111  }
1112  BLOCK_END("Client::gameExec STATE_CHOOSE_SERVER")
1113  break;
1114  }
1115 
1116  case State::CONNECT_SERVER:
1117  BLOCK_START("Client::gameExec State::CONNECT_SERVER")
1118  logger->log1("State: CONNECT SERVER");
1119  loginData.updateHosts.clear();
1120  CREATEWIDGETV(mCurrentDialog, ConnectionDialog,
1121  // TRANSLATORS: connection dialog header
1122  _("Connecting to server"),
1126  pincodeManager.init();
1127  BLOCK_END("Client::gameExec State::CONNECT_SERVER")
1128  break;
1129 
1130  case State::PRE_LOGIN:
1131  logger->log1("State: PRE_LOGIN");
1132  break;
1133 
1134  case State::LOGIN:
1135  BLOCK_START("Client::gameExec State::LOGIN")
1136  logger->log1("State: LOGIN");
1137  // Don't allow an alpha opacity
1138  // lower than the default value
1139  theme->setMinimumOpacity(0.8F);
1140 
1141  if (packetVersion == 0)
1142  {
1144  if (packetVersion != 0)
1145  {
1147  logger->log("Preconfigured packet version: %d",
1148  packetVersion);
1149  }
1150  }
1151 
1152  loginData.updateType = static_cast<UpdateTypeT>(
1153  serverConfig.getValue("updateType", 0));
1154 
1156  const_cast<char*>(mCurrentServer.hostname.c_str()),
1157  CAST_S32(mCurrentServer.hostname.size()));
1158  if (settings.options.username.empty() ||
1159  settings.options.password.empty())
1160  {
1161  CREATEWIDGETV(mCurrentDialog, LoginDialog,
1162  loginData,
1163  &mCurrentServer,
1165  }
1166  else
1167  {
1168  mState = State::LOGIN_ATTEMPT;
1169  // Clear the password so that when login fails, the
1170  // dialog will show up next time.
1171  settings.options.password.clear();
1172  }
1173  BLOCK_END("Client::gameExec State::LOGIN")
1174  break;
1175 
1176  case State::LOGIN_ATTEMPT:
1177  BLOCK_START("Client::gameExec State::LOGIN_ATTEMPT")
1178  logger->log1("State: LOGIN ATTEMPT");
1179  CREATEWIDGETV(mCurrentDialog, ConnectionDialog,
1180  // TRANSLATORS: connection dialog header
1181  _("Logging in"),
1183  if (loginHandler != nullptr)
1185  BLOCK_END("Client::gameExec State::LOGIN_ATTEMPT")
1186  break;
1187 
1188  case State::WORLD_SELECT:
1189  BLOCK_START("Client::gameExec State::WORLD_SELECT")
1190  logger->log1("State: WORLD SELECT");
1191  {
1194  if (loginHandler == nullptr)
1195  {
1196  BLOCK_END("Client::gameExec State::WORLD_SELECT")
1197  break;
1198  }
1199  Worlds worlds = loginHandler->getWorlds();
1200 
1201  if (worlds.empty())
1202  {
1203  // Trust that the netcode knows what it's doing
1204  mState = State::UPDATE;
1205  }
1206  else if (worlds.size() == 1)
1207  {
1209  0, mCurrentServer.persistentIp);
1210  mState = State::UPDATE;
1211  }
1212  else
1213  {
1214  CREATEWIDGETV(mCurrentDialog, WorldSelectDialog,
1215  worlds);
1217  {
1218  static_cast<WorldSelectDialog*>(mCurrentDialog)
1219  ->action(ActionEvent(nullptr, "ok"));
1220  }
1221  }
1222  }
1223  BLOCK_END("Client::gameExec State::WORLD_SELECT")
1224  break;
1225 
1227  BLOCK_START("Client::gameExec State::WORLD_SELECT_ATTEMPT")
1228  logger->log1("State: WORLD SELECT ATTEMPT");
1229  CREATEWIDGETV(mCurrentDialog, ConnectionDialog,
1230  // TRANSLATORS: connection dialog header
1231  _("Entering game world"),
1233  BLOCK_END("Client::gameExec State::WORLD_SELECT_ATTEMPT")
1234  break;
1235 
1236  case State::UPDATE:
1237  BLOCK_START("Client::gameExec State::UPDATE")
1238  logger->log1("State: UPDATE");
1239 
1240  // Determine which source to use for the update host
1241  if (!settings.options.updateHost.empty())
1243  else
1246 
1247  if (!settings.oldUpdates.empty())
1249 
1251  {
1252  mState = State::LOAD_DATA;
1253  settings.oldUpdates.clear();
1255  }
1256  else if ((loginData.updateType & UpdateType::Skip) != 0)
1257  {
1261  mState = State::LOAD_DATA;
1262  }
1263  else
1264  {
1267  CREATEWIDGETV(mCurrentDialog, UpdaterWindow,
1270  settings.options.dataPath.empty(),
1272  }
1273  BLOCK_END("Client::gameExec State::UPDATE")
1274  break;
1275 
1276  case State::LOAD_DATA:
1277  {
1278  BLOCK_START("Client::gameExec State::LOAD_DATA")
1279  logger->log1("State: LOAD DATA");
1280 
1281  loadData();
1282 
1283  mState = State::GET_CHARACTERS;
1284  BLOCK_END("Client::gameExec State::LOAD_DATA")
1285  break;
1286  }
1287  case State::GET_CHARACTERS:
1288  BLOCK_START("Client::gameExec State::GET_CHARACTERS")
1289  logger->log1("State: GET CHARACTERS");
1290  CREATEWIDGETV(mCurrentDialog, ConnectionDialog,
1291  // TRANSLATORS: connection dialog header
1292  _("Requesting characters"),
1294  if (charServerHandler != nullptr)
1296  BLOCK_END("Client::gameExec State::GET_CHARACTERS")
1297  break;
1298 
1299  case State::CHAR_SELECT:
1300  BLOCK_START("Client::gameExec State::CHAR_SELECT")
1301  logger->log1("State: CHAR SELECT");
1302  // Don't allow an alpha opacity
1303  // lower than the default value
1304  theme->setMinimumOpacity(0.8F);
1305 
1308 
1309  CREATEWIDGETV(mCurrentDialog, CharSelectDialog,
1310  loginData);
1312 
1313  if (!(static_cast<CharSelectDialog*>(mCurrentDialog))
1314  ->selectByName(settings.options.character,
1316  {
1317  (static_cast<CharSelectDialog*>(mCurrentDialog))
1318  ->selectByName(
1319  serverConfig.getValue("lastCharacter", ""),
1323  }
1324 
1325  // Choosing character on the command line should work only
1326  // once, clear it so that 'switch character' works.
1327  settings.options.character.clear();
1328  BLOCK_END("Client::gameExec State::CHAR_SELECT")
1329  break;
1330 
1331  case State::CONNECT_GAME:
1332  BLOCK_START("Client::gameExec State::CONNECT_GAME")
1333  logger->log1("State: CONNECT GAME");
1334  CREATEWIDGETV(mCurrentDialog, ConnectionDialog,
1335  // TRANSLATORS: connection dialog header
1336  _("Connecting to the game server"),
1338  if (gameHandler != nullptr)
1339  gameHandler->connect();
1340  BLOCK_END("Client::gameExec State::CONNECT_GAME")
1341  break;
1342 
1343  case State::CHANGE_MAP:
1344  BLOCK_START("Client::gameExec State::CHANGE_MAP")
1345  logger->log1("State: CHANGE_MAP");
1346  CREATEWIDGETV(mCurrentDialog, ConnectionDialog,
1347  // TRANSLATORS: connection dialog header
1348  _("Changing game servers"),
1350  if (gameHandler != nullptr)
1351  gameHandler->connect();
1352  BLOCK_END("Client::gameExec State::CHANGE_MAP")
1353  break;
1354 
1355  case State::GAME:
1356  BLOCK_START("Client::gameExec State::GAME")
1357  if (localPlayer != nullptr)
1358  {
1359  logger->log("Memorizing selected character %s",
1360  localPlayer->getName().c_str());
1361  serverConfig.setValue("lastCharacter",
1362  localPlayer->getName());
1363 #ifdef USE_MUMBLE
1364  if (mumbleManager)
1365  mumbleManager->setPlayer(localPlayer->getName());
1366 #endif // USE_MUMBLE
1367  }
1368 
1369  // Fade out logon-music here too to give the desired effect
1370  // of "flowing" into the game.
1371  soundManager.fadeOutMusic(1000);
1372 
1373  // Allow any alpha opacity
1374  theme->setMinimumOpacity(-1.0F);
1375 
1376  if (chatLogger != nullptr)
1378 
1379 #ifdef ANDROID
1380  delete2(mCloseButton);
1381 #endif // ANDROID
1382 
1383  delete2(mSetupButton);
1384  delete2(mVideoButton);
1385  delete2(mThemesButton);
1386  delete2(mAboutButton);
1387  delete2(mHelpButton);
1388  delete2(mPerfomanceButton);
1389  delete2(desktop);
1390 
1391  mCurrentDialog = nullptr;
1392 
1393  logger->log1("State: GAME");
1394  if (generalHandler != nullptr)
1396  mGame = new Game;
1397  BLOCK_END("Client::gameExec State::GAME")
1398  break;
1399 
1400  case State::LOGIN_ERROR:
1401  BLOCK_START("Client::gameExec State::LOGIN_ERROR")
1402  logger->log1("State: LOGIN ERROR");
1403  CREATEWIDGETV(mCurrentDialog, OkDialog,
1404  // TRANSLATORS: error dialog header
1405  _("Error"),
1406  errorMessage,
1407  // TRANSLATORS: ok dialog button
1408  _("Close"),
1410  Modal_true,
1412  nullptr,
1413  260);
1414  mCurrentDialog->addActionListener(&loginListener);
1415  mCurrentDialog = nullptr; // OkDialog deletes itself
1416  BLOCK_END("Client::gameExec State::LOGIN_ERROR")
1417  break;
1418 
1420  BLOCK_START("Client::gameExec State::ACCOUNTCHANGE_ERROR")
1421  logger->log1("State: ACCOUNT CHANGE ERROR");
1422  CREATEWIDGETV(mCurrentDialog, OkDialog,
1423  // TRANSLATORS: error dialog header
1424  _("Error"),
1425  errorMessage,
1426  // TRANSLATORS: ok dialog button
1427  _("Close"),
1429  Modal_true,
1431  nullptr,
1432  260);
1433  mCurrentDialog->addActionListener(&accountListener);
1434  mCurrentDialog = nullptr; // OkDialog deletes itself
1435  BLOCK_END("Client::gameExec State::ACCOUNTCHANGE_ERROR")
1436  break;
1437 
1438  case State::REGISTER_PREP:
1439  BLOCK_START("Client::gameExec State::REGISTER_PREP")
1440  logger->log1("State: REGISTER_PREP");
1441  CREATEWIDGETV(mCurrentDialog, ConnectionDialog,
1442  // TRANSLATORS: connection dialog header
1443  _("Requesting registration details"),
1444  State::LOGIN);
1446  BLOCK_END("Client::gameExec State::REGISTER_PREP")
1447  break;
1448 
1449  case State::REGISTER:
1450  logger->log1("State: REGISTER");
1451  CREATEWIDGETV(mCurrentDialog, RegisterDialog,
1452  loginData);
1453  break;
1454 
1456  BLOCK_START("Client::gameExec State::REGISTER_ATTEMPT")
1457  logger->log("Username is %s", loginData.username.c_str());
1458  if (loginHandler != nullptr)
1460  BLOCK_END("Client::gameExec State::REGISTER_ATTEMPT")
1461  break;
1462 
1463  case State::CHANGEPASSWORD:
1464  BLOCK_START("Client::gameExec State::CHANGEPASSWORD")
1465  logger->log1("State: CHANGE PASSWORD");
1466  CREATEWIDGETV(mCurrentDialog, ChangePasswordDialog,
1467  loginData);
1468  mCurrentDialog->setVisible(Visible_true);
1469  BLOCK_END("Client::gameExec State::CHANGEPASSWORD")
1470  break;
1471 
1473  BLOCK_START("Client::gameExec "
1474  "State::CHANGEPASSWORD_ATTEMPT")
1475  logger->log1("State: CHANGE PASSWORD ATTEMPT");
1476  if (loginHandler != nullptr)
1477  {
1480  }
1481  BLOCK_END("Client::gameExec State::CHANGEPASSWORD_ATTEMPT")
1482  break;
1483 
1485  BLOCK_START("Client::gameExec "
1486  "State::CHANGEPASSWORD_SUCCESS")
1487  logger->log1("State: CHANGE PASSWORD SUCCESS");
1488  CREATEWIDGETV(mCurrentDialog, OkDialog,
1489  // TRANSLATORS: password change message header
1490  _("Password Change"),
1491  // TRANSLATORS: password change message text
1492  _("Password changed successfully!"),
1493  // TRANSLATORS: ok dialog button
1494  _("OK"),
1496  Modal_true,
1498  nullptr,
1499  260);
1500  mCurrentDialog->addActionListener(&accountListener);
1501  mCurrentDialog = nullptr; // OkDialog deletes itself
1503  loginData.newPassword.clear();
1504  BLOCK_END("Client::gameExec State::CHANGEPASSWORD_SUCCESS")
1505  break;
1506 
1507  case State::CHANGEEMAIL:
1508  logger->log1("State: CHANGE EMAIL");
1509  CREATEWIDGETV(mCurrentDialog,
1511  loginData);
1512  mCurrentDialog->setVisible(Visible_true);
1513  break;
1514 
1516  logger->log1("State: CHANGE EMAIL ATTEMPT");
1517  if (loginHandler != nullptr)
1519  break;
1520 
1522  logger->log1("State: CHANGE EMAIL SUCCESS");
1523  CREATEWIDGETV(mCurrentDialog, OkDialog,
1524  // TRANSLATORS: email change message header
1525  _("Email Change"),
1526  // TRANSLATORS: email change message text
1527  _("Email changed successfully!"),
1528  // TRANSLATORS: ok dialog button
1529  _("OK"),
1531  Modal_true,
1533  nullptr,
1534  260);
1535  mCurrentDialog->addActionListener(&accountListener);
1536  mCurrentDialog = nullptr; // OkDialog deletes itself
1537  break;
1538 
1539  case State::SWITCH_SERVER:
1540  BLOCK_START("Client::gameExec State::SWITCH_SERVER")
1541  logger->log1("State: SWITCH SERVER");
1542 
1543  if (loginHandler != nullptr)
1545  if (gameHandler != nullptr)
1546  {
1548  gameHandler->clear();
1549  }
1550  settings.serverName.clear();
1551  settings.login.clear();
1553  serverConfig.write();
1554  serverConfig.unload();
1555  if (setupWindow != nullptr)
1557 
1558  mState = State::CHOOSE_SERVER;
1559  BLOCK_END("Client::gameExec State::SWITCH_SERVER")
1560  break;
1561 
1562  case State::SWITCH_LOGIN:
1563  BLOCK_START("Client::gameExec State::SWITCH_LOGIN")
1564  logger->log1("State: SWITCH LOGIN");
1565 
1566  if (loginHandler != nullptr)
1567  {
1568  loginHandler->logout();
1570  }
1571  if (gameHandler != nullptr)
1573  if (loginHandler != nullptr)
1574  loginHandler->connect();
1575 
1576  settings.login.clear();
1578  mState = State::LOGIN;
1579  BLOCK_END("Client::gameExec State::SWITCH_LOGIN")
1580  break;
1581 
1583  BLOCK_START("Client::gameExec State::SWITCH_CHARACTER")
1584  logger->log1("State: SWITCH CHARACTER");
1585 
1586  // Done with game
1587  if (gameHandler != nullptr)
1589 
1590  settings.login.clear();
1592  mState = State::GET_CHARACTERS;
1593  BLOCK_END("Client::gameExec State::SWITCH_CHARACTER")
1594  break;
1595 
1596  case State::LOGOUT_ATTEMPT:
1597  logger->log1("State: LOGOUT ATTEMPT");
1598  break;
1599 
1600  case State::WAIT:
1601  logger->log1("State: WAIT");
1602  break;
1603 
1604  case State::EXIT:
1605  BLOCK_START("Client::gameExec State::EXIT")
1606  logger->log1("State: EXIT");
1607  Net::unload();
1608  BLOCK_END("Client::gameExec State::EXIT")
1609  break;
1610 
1611  case State::FORCE_QUIT:
1612  BLOCK_START("Client::gameExec State::FORCE_QUIT")
1613  logger->log1("State: FORCE QUIT");
1614  if (generalHandler != nullptr)
1616  mState = State::EXIT;
1617  BLOCK_END("Client::gameExec State::FORCE_QUIT")
1618  break;
1619 
1620  case State::ERROR:
1621  BLOCK_START("Client::gameExec State::ERROR")
1622  config.write();
1623  if (mOldState == State::GAME)
1624  serverConfig.write();
1625  logger->log1("State: ERROR");
1626  logger->log("Error: %s\n", errorMessage.c_str());
1628  mCurrentDialog = DialogsManager::openErrorDialog(
1629  // TRANSLATORS: error message header
1630  _("Error"),
1631  errorMessage,
1632  Modal_true);
1633  mCurrentDialog->addActionListener(&errorListener);
1634  mCurrentDialog = nullptr; // OkDialog deletes itself
1636  BLOCK_END("Client::gameExec State::ERROR")
1637  break;
1638 
1640  // ++++++
1641  break;
1642 
1643  case State::START:
1644  default:
1645  mState = State::FORCE_QUIT;
1646  break;
1647  }
1648  BLOCK_END("Client::gameExec 8")
1649  }
1650  PROFILER_END();
1651  }
1652 
1653  return 0;
1654 }
1655 
1656 void Client::optionChanged(const std::string &name)
1657 {
1658  if (name == "fpslimit")
1659  {
1660  const int fpsLimit = config.getIntValue("fpslimit");
1661  settings.limitFps = fpsLimit > 0;
1662  WindowManager::setFramerate(fpsLimit);
1663  }
1664  else if (name == "guialpha" ||
1665  name == "enableGuiOpacity")
1666  {
1667  const float alpha = config.getFloatValue("guialpha");
1668  settings.guiAlpha = alpha;
1669  ImageHelper::setEnableAlpha(alpha != 1.0F &&
1670  config.getBoolValue("enableGuiOpacity"));
1671  }
1672  else if (name == "gamma" ||
1673  name == "enableGamma")
1674  {
1676  }
1677  else if (name == "particleEmitterSkip")
1678  {
1680  config.getIntValue("particleEmitterSkip") + 1;
1681  }
1682  else if (name == "vsync")
1683  {
1685  }
1686  else if (name == "repeateInterval" ||
1687  name == "repeateDelay")
1688  {
1690  }
1691 }
1692 
1693 void Client::action(const ActionEvent &event)
1694 {
1695  std::string tab;
1696  const std::string &eventId = event.getId();
1697 
1698  if (eventId == "close")
1699  {
1700  setState(State::FORCE_QUIT);
1701  return;
1702  }
1703  if (eventId == "Setup")
1704  {
1705  tab.clear();
1706  }
1707  else if (eventId == "help")
1708  {
1710  return;
1711  }
1712  else if (eventId == "about")
1713  {
1715  return;
1716  }
1717  else if (eventId == "Video")
1718  {
1719  tab = "Video";
1720  }
1721  else if (eventId == "Themes")
1722  {
1723  tab = "Theme";
1724  }
1725  else if (eventId == "Perfomance")
1726  {
1727  tab = "Perfomance";
1728  }
1729  else
1730  {
1731  return;
1732  }
1733 
1734  if (setupWindow != nullptr)
1735  {
1739  {
1740  if (!tab.empty())
1741  setupWindow->activateTab(tab);
1743  }
1744  }
1745 }
1746 
1748 {
1749  features.init(paths.getStringValue("featuresFile"),
1751  SkipError_true);
1753  settings.fixDeadAnimation = features.getBoolValue("fixDeadAnimation");
1754 }
1755 
1756 void Client::initPaths()
1757 {
1758  settings.gmCommandSymbol = paths.getStringValue("gmCommandSymbol");
1759  settings.gmCharCommandSymbol = paths.getStringValue("gmCharCommandSymbol");
1760  settings.linkCommandSymbol = paths.getStringValue("linkCommandSymbol");
1761  if (settings.linkCommandSymbol.empty())
1763  settings.overweightPercent = paths.getIntValue("overweightPercent");
1765  "playerNameOffset");
1767  "playerBadgeAtRightOffset");
1768  settings.unknownSkillsAutoTab = paths.getBoolValue("unknownSkillsAutoTab");
1769  settings.enableNewMailSystem = paths.getBoolValue("enableNewMailSystem");
1770 }
1771 
1773 {
1774  const std::string tradeListName =
1775  settings.serverConfigDir + "/tradefilter.txt";
1776 
1777  std::ofstream tradeFile;
1778  struct stat statbuf;
1779 
1780  if ((stat(tradeListName.c_str(), &statbuf) != 0) ||
1781  !S_ISREG(statbuf.st_mode))
1782  {
1783  tradeFile.open(tradeListName.c_str(),
1784  std::ios::out);
1785  if (tradeFile.is_open())
1786  {
1787  tradeFile << ": sell" << std::endl;
1788  tradeFile << ": buy" << std::endl;
1789  tradeFile << ": trade" << std::endl;
1790  tradeFile << "i sell" << std::endl;
1791  tradeFile << "i buy" << std::endl;
1792  tradeFile << "i trade" << std::endl;
1793  tradeFile << "i trading" << std::endl;
1794  tradeFile << "i am buy" << std::endl;
1795  tradeFile << "i am sell" << std::endl;
1796  tradeFile << "i am trade" << std::endl;
1797  tradeFile << "i am trading" << std::endl;
1798  tradeFile << "i'm buy" << std::endl;
1799  tradeFile << "i'm sell" << std::endl;
1800  tradeFile << "i'm trade" << std::endl;
1801  tradeFile << "i'm trading" << std::endl;
1802  }
1803  else
1804  {
1805  reportAlways("Error opening file for writing: %s",
1806  tradeListName.c_str());
1807  }
1808  tradeFile.close();
1809  }
1810 }
1811 
1812 bool Client::isTmw()
1813 {
1814  const std::string &name = settings.serverName;
1815  if (name == "server.themanaworld.org" ||
1816  name == "themanaworld.org" ||
1817  name == "167.114.129.72")
1818  {
1819  return true;
1820  }
1821  return false;
1822 }
1823 
1824 void Client::moveButtons(const int width)
1825 {
1826  if (mSetupButton != nullptr)
1827  {
1828  int x = width - mSetupButton->getWidth() - mButtonPadding;
1829  mSetupButton->setPosition(x, mButtonPadding);
1830 #ifndef WIN32
1831  x -= mPerfomanceButton->getWidth() + mButtonSpacing;
1832  mPerfomanceButton->setPosition(x, mButtonPadding);
1833 
1834  x -= mVideoButton->getWidth() + mButtonSpacing;
1835  mVideoButton->setPosition(x, mButtonPadding);
1836 
1837  x -= mThemesButton->getWidth() + mButtonSpacing;
1838  mThemesButton->setPosition(x, mButtonPadding);
1839 
1840  x -= mAboutButton->getWidth() + mButtonSpacing;
1841  mAboutButton->setPosition(x, mButtonPadding);
1842 
1843  x -= mHelpButton->getWidth() + mButtonSpacing;
1844  mHelpButton->setPosition(x, mButtonPadding);
1845 #ifdef ANDROID
1846  x -= mCloseButton->getWidth() + mButtonSpacing;
1847  mCloseButton->setPosition(x, mButtonPadding);
1848 #endif // ANDROID
1849 #endif // WIN32
1850  }
1851 }
1852 
1853 void Client::windowRemoved(const Window *const window)
1854 {
1855  if (mCurrentDialog == window)
1856  mCurrentDialog = nullptr;
1857 }
1858 
1859 void Client::focusWindow()
1860 {
1861  if (mCurrentDialog != nullptr)
1862  {
1863  mCurrentDialog->requestFocus();
1864  }
1865 }
1866 
1868 {
1869  if (mCurrentDialog == nullptr ||
1870  mState != State::CHAR_SELECT)
1871  {
1872  return;
1873  }
1874  CharSelectDialog *const dialog =
1875  dynamic_cast<CharSelectDialog*>(mCurrentDialog);
1876  if (dialog != nullptr)
1878 }
1879 
1880 void Client::logVars()
1881 {
1882 #ifdef ANDROID
1883  logger->log("APPDIR: %s", getenv("APPDIR"));
1884  logger->log("DATADIR2: %s", getSdStoragePath().c_str());
1885 #endif // ANDROID
1886 }
1887 
1888 void Client::slowLogic()
1889 {
1890  if ((gameHandler == nullptr) ||
1891  !gameHandler->mustPing())
1892  {
1893  return;
1894  }
1895 
1896  if (get_elapsed_time1(mPing) > 1500)
1897  {
1898  mPing = tick_time;
1899  if (mState == State::UPDATE ||
1900  mState == State::LOGIN ||
1901  mState == State::LOGIN_ATTEMPT ||
1902  mState == State::REGISTER ||
1903  mState == State::REGISTER_ATTEMPT)
1904  {
1905  if (loginHandler != nullptr)
1906  loginHandler->ping();
1907  if (generalHandler != nullptr)
1909  }
1910  else if (mState == State::CHAR_SELECT)
1911  {
1912  if (charServerHandler != nullptr)
1914  if (generalHandler != nullptr)
1916  }
1917  }
1918 }
1919 
1921 {
1922  // If another data path has been set,
1923  // we don't load any other files...
1924  if (settings.options.dataPath.empty())
1925  {
1926  // Add customdata directory
1928  "customdata/",
1929  "zip",
1930  Append_false);
1931  }
1932 
1934  {
1936  settings.updatesDir + "/local/",
1937  "zip",
1938  Append_false);
1939 
1943  "local/"),
1944  Append_false);
1945  }
1946 
1947  logger->log("Init paths");
1948  paths.init("paths.xml",
1950  SkipError_false);
1952  initPaths();
1953  if (SpriteReference::Empty == nullptr)
1954  {
1956  paths.getStringValue("spriteErrorFile"),
1957  0);
1958  }
1959 
1960  if (BeingInfo::unknown == nullptr)
1962 
1963  initFeatures();
1966  PlayerInfo::stateChange(mState);
1967 
1970 
1971  delete spellManager;
1972  spellManager = new SpellManager;
1973  delete spellShortcut;
1975 
1977 
1979 
1980  if (desktop != nullptr)
1982 }
1983 
1985 {
1987  mCurrentServer.supportUrl.clear();
1988  settings.supportUrl.clear();
1989  if (settings.options.dataPath.empty())
1990  {
1991  // Add customdata directory
1993  "customdata/",
1994  "zip");
1995  }
1996 
1997  if (!settings.oldUpdates.empty())
1998  {
2000  settings.oldUpdates.clear();
2001  }
2002 
2004  {
2006  pathJoin(settings.updatesDir, "local/"),
2007  "zip");
2008 
2012  "local/"));
2013  }
2014 
2016 
2018  localClan.clear();
2019  serverVersion = 0;
2020  packetVersion = 0;
2021  packetVersionMain = 0;
2022  packetVersionRe = 0;
2023  packetVersionZero = 0;
2024  tmwServerVersion = 0;
2025  evolPacketOffset = 0;
2026 }
2027 
2029 {
2030  loadData();
2032 
2034  unloadData();
2035  delete2(client);
2036  VirtFs::deinit();
2037  exit(0);
2038 }
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:933
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:891
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:1984
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:107
std::string serverName
Definition: settings.h:111
static void storeSafeParameters()
virtual void flushNetwork() const =0
unsigned int tmwServerVersion
Definition: client.cpp:132
std::string linkCommandSymbol
Definition: settings.h:124
#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:113
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:473
static void initFeatures()
Definition: client.cpp:1747
bool fixDeadAnimation
Definition: settings.h:156
void init()
Definition: playerinfo.cpp:431
SpellManager * spellManager
Options options
Definition: settings.h:127
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:149
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:734
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:150
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:118
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:146
virtual void reloadPartially() const =0
static void initTradeFilter()
Definition: client.cpp:1772
virtual void clear() const =0
std::vector< std::string > updateMirrors
Definition: settings.h:126
void addListener(const std::string &key, ConfigListener *const listener)
void initPacketLimiter()
bool enableRemoteCommands
Definition: settings.h:158
virtual void clear() const =0
void stateConnectGame1()
Definition: client.cpp:793
Logger * logger
Definition: logger.cpp:88
std::string localDataDir
Definition: settings.h:109
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:122
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:119
#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:114
std::string oldUpdates
Definition: settings.h:106
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:160
virtual void ping() const =0
virtual void add(Widget *const widget)
void loadData()
Definition: client.cpp:1920
void moveButtons(const int width)
Definition: client.cpp:772
virtual void loginOrRegister(LoginData *const data) const =0
unsigned int overweightPercent
Definition: settings.h:144
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:1656
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:803
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:111
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:2028
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:881
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:108
void setConfigDefaults2(Configuration &cfg)
Definition: defaults.cpp:426
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:145
static void initServerConfig(const std::string &serverName)
#define CHECKLISTENERS
Definition: localconsts.h:262
static void initScreenshotDir()
Definition: dirs.cpp:539
void initConfigListeners()
Definition: client.cpp:572
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:104
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:128
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:161
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:123
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:788
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:105
std::string username
Definition: options.h:75
void setPathsDefaults(Configuration &cfg)
Definition: defaults.cpp:533