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-2017 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 "settings.h"
34 #include "soundmanager.h"
35 #include "spellmanager.h"
36 
37 #include "being/localplayer.h"
38 #include "being/playerinfo.h"
39 #include "being/playerrelations.h"
40 
41 #include "const/net/net.h"
42 
44 
45 #include "fs/virtfs/fs.h"
46 #include "fs/virtfs/tools.h"
47 
48 #include "gui/dialogsmanager.h"
49 #include "gui/gui.h"
50 #include "gui/skin.h"
51 #include "gui/popupmanager.h"
52 #include "gui/windowmanager.h"
53 
58 
65 #include "gui/windows/npcdialog.h"
66 #include "gui/windows/okdialog.h"
71 #include "gui/windows/quitdialog.h"
73 
74 #include "gui/widgets/button.h"
76 #include "gui/widgets/desktop.h"
78 
79 #include "input/inputmanager.h"
80 #include "input/joystick.h"
81 #include "input/keyboardconfig.h"
82 
84 
85 #include "net/charserverhandler.h"
86 #include "net/chathandler.h"
87 #include "net/download.h"
88 #include "net/gamehandler.h"
89 #include "net/generalhandler.h"
90 #include "net/guildhandler.h"
91 #include "net/inventoryhandler.h"
92 #include "net/ipc.h"
93 #include "net/loginhandler.h"
94 #include "net/net.h"
96 #include "net/useragent.h"
97 #include "net/packetlimiter.h"
98 #include "net/partyhandler.h"
99 
100 #ifdef TMWA_SUPPORT
101 #include "net/tmwa/guildmanager.h"
102 #endif // TMWA_SUPPORT
103 
104 #include "particle/particleengine.h"
105 
106 #include "resources/dbmanager.h"
107 #include "resources/imagehelper.h"
108 
110 
112 
114 
115 #include "utils/checkutils.h"
116 #include "utils/cpu.h"
117 #include "utils/delete2.h"
118 #include "utils/dumplibs.h"
119 #include "utils/dumpsizes.h"
120 #include "utils/env.h"
121 #include "utils/fuzzer.h"
122 #include "utils/gettext.h"
123 #include "utils/gettexthelper.h"
124 #include "utils/mrand.h"
125 #ifdef ANDROID
126 #include "fs/paths.h"
127 #endif // ANDROID
128 #include "utils/sdlcheckutils.h"
129 #include "utils/sdlhelper.h"
130 #include "utils/timer.h"
131 
133 
135 #include "listeners/errorlistener.h"
136 
137 #ifdef USE_OPENGL
138 #include "test/testlauncher.h"
139 #include "test/testmain.h"
140 #else // USE_OPENGL
141 #include "configuration.h"
142 #endif // USE_OPENGL
143 
144 #ifdef WIN32
145 PRAGMA48(GCC diagnostic push)
146 PRAGMA48(GCC diagnostic ignored "-Wshadow")
147 #include <SDL_syswm.h>
148 PRAGMA48(GCC diagnostic pop)
149 #include "fs/specialfolder.h"
150 #undef ERROR
151 #endif // WIN32
152 
153 #ifdef ANDROID
154 #ifndef USE_SDL2
155 PRAGMA48(GCC diagnostic push)
156 PRAGMA48(GCC diagnostic ignored "-Wshadow")
157 #include <SDL_screenkeyboard.h>
158 PRAGMA48(GCC diagnostic pop)
159 #include <fstream>
160 #endif // USE_SDL2
161 #endif // ANDROID
162 
163 #include <sys/stat.h>
164 
165 #ifdef USE_MUMBLE
166 #include "mumblemanager.h"
167 #endif // USE_MUMBLE
168 
169 PRAGMA48(GCC diagnostic push)
170 PRAGMA48(GCC diagnostic ignored "-Wshadow")
171 #ifdef USE_SDL2
172 #include <SDL2_framerate.h>
173 #else // USE_SDL2
174 #include <SDL_framerate.h>
175 #endif // USE_SDL2
176 PRAGMA48(GCC diagnostic pop)
177 
178 #include "debug.h"
179 
180 std::string errorMessage;
182 
183 Client *client = nullptr;
184 
185 extern FPSmanager fpsManager;
186 extern int evolPacketOffset;
187 
188 volatile bool runCounters;
189 bool isSafeMode = false;
192 unsigned int tmwServerVersion = 0;
193 time_t start_time;
194 unsigned int mLastHost = 0;
195 unsigned long mSearchHash = 0;
197 volatile bool isTerminate = false;
198 
199 namespace
200 {
202  {
203  public:
205  { }
206 
208 
209  void action(const ActionEvent &event A_UNUSED) override final
210  {
211  client->setState(State::CHAR_SELECT);
212  }
213  } accountListener;
214 
216  {
217  public:
219  { }
220 
222 
223  void action(const ActionEvent &event A_UNUSED) override final
224  {
225  client->setState(State::PRE_LOGIN);
226  }
227  } loginListener;
228 } // namespace
229 
230 Client::Client() :
231  ActionListener(),
232  mCurrentServer(),
233  mGame(nullptr),
234  mCurrentDialog(nullptr),
235  mQuitDialog(nullptr),
236  mSetupButton(nullptr),
237  mVideoButton(nullptr),
238  mHelpButton(nullptr),
239  mAboutButton(nullptr),
240  mThemesButton(nullptr),
241  mPerfomanceButton(nullptr),
242 #ifdef ANDROID
243  mCloseButton(nullptr),
244 #endif // ANDROID
245  mState(State::CHOOSE_SERVER),
246  mOldState(State::START),
247  mSkin(nullptr),
248  mButtonPadding(1),
249  mButtonSpacing(3),
250  mPing(0),
251  mConfigAutoSaved(false)
252 {
254 }
255 
256 void Client::testsInit()
257 {
258  if (!settings.options.test.empty() &&
259  settings.options.test != "99")
260  {
261  gameInit();
262  }
263  else
264  {
265  initRand();
266  logger = new Logger;
267  SDL::initLogger();
272  }
273 }
274 
275 void Client::gameInit()
276 {
277  logger = new Logger;
278  SDL::initLogger();
279 
280  initRand();
281 
283  // Load branding information
284  if (!settings.options.brandingPath.empty())
287 
290 
291  // Configure logger
292  if (!settings.options.logFileName.empty())
293  {
295  }
296  else
297  {
299  "manaplus.log");
300  }
301  logger->log("Log file: " + settings.logFileName);
303 
304 #ifdef USE_FUZZER
305  Fuzzer::init();
306 #endif // USE_FUZZER
307 
308  if (settings.options.ipc == true)
309  IPC::start();
310  if (settings.options.test.empty())
311  ConfigManager::backupConfig("config.xml");
313  SDL::setLogLevel(config.getIntValue("sdlLogLevel"));
314  settings.init();
317  initFeatures();
318  initPaths();
319  logger->log("init 4");
320  logger->setDebugLog(config.getBoolValue("debugLog"));
321  logger->setReportUnimplemented(config.getBoolValue("unimplimentedLog"));
322 
323  config.incValue("runcount");
324 
325 #ifndef ANDROID
326  if (settings.options.test.empty())
328 #endif // ANDROID
329 
331  {
332  logger->error(strprintf("%s couldn't be set as home directory! "
333  "Exiting.", settings.localDataDir.c_str()));
334  }
335 
337 
338  chatLogger = new ChatLogger;
339  if (settings.options.chatLogDir.empty())
340  {
342  + std::string("/logs/"));
343  }
344  else
345  {
347  }
348 
349  // Log the client version
351  logger->log("Start configPath: " + config.getConfigPath());
352 
354 
355  updateEnv();
356  SDL::allowScreenSaver(config.getBoolValue("allowscreensaver"));
357  dumpLibs();
358  dumpSizes();
359 
360  // Initialize SDL
361  logger->log1("Initializing SDL...");
362  if (SDL_Init(SDL_INIT_VIDEO | SDL_INIT_TIMER) < 0)
363  {
364  logger->safeError(strprintf("Could not initialize SDL: %s",
365  SDL_GetError()));
366  }
367  atexit(SDL_Quit);
368 
370 #ifndef USE_SDL2
371  SDL_EnableUNICODE(1);
372 #endif // USE_SDL2
373 
377 
378 #ifdef WIN32
380 #endif // WIN32
381 #ifndef USE_SDL2
383 #endif // USE_SDL2
384 
386  logVars();
387  Cpu::detect();
389 #if defined(USE_OPENGL)
390 #if !defined(ANDROID) && !defined(__APPLE__) && \
391  !defined(__native_client__) && !defined(UNITTESTS)
392  if (!settings.options.safeMode &&
393  settings.options.renderer < 0 &&
394  settings.options.test.empty() &&
396  !config.getBoolValue("videodetected"))
397  {
399  }
400 #endif // !defined(ANDROID) && !defined(__APPLE__) &&
401  // !defined(__native_client__) && !defined(UNITTESTS)
402 #endif // defined(USE_OPENGL)
403 
404  initGraphics();
406 
407  touchManager.init();
408 
409 #ifndef WIN32
412 #endif // WIN32
413 
415 
416  // Add the main data directories to our VirtFs search path
417  if (!settings.options.dataPath.empty())
418  {
420  Append_false);
421  }
422 
423  // Add the local data directory to VirtFs search path
425  Append_false);
428 #ifdef ENABLE_CUSTOMNLS
429  TranslationManager::loadGettextLang();
430 #endif // ENABLE_CUSTOMNLS
431 
432 #ifdef USE_SDL2
434 #endif // USE_SDL2
436 
438 
439  theme = new Theme;
442  touchManager.init();
443 
444  // Initialize the item and emote shortcuts.
445  for (size_t f = 0; f < SHORTCUT_TABS; f ++)
446  itemShortcut[f] = new ItemShortcut(f);
449 
450  gui = new Gui;
454 
455  initSoundManager();
456 
457  // Initialize keyboard
458  keyboard.init();
459  inputManager.init();
460 
461  // Initialise player relations
463  Joystick::init();
465 
466  keyboard.update();
467  if (joystick != nullptr)
468  joystick->update();
469 
470  // Initialize default server
471  mCurrentServer.hostname = settings.options.serverName;
472  mCurrentServer.port = settings.options.serverPort;
473  if (!settings.options.serverType.empty())
474  {
475  mCurrentServer.type = ServerInfo::parseType(
477  }
478 
482  loginData.remember = (serverConfig.getValue("remember", 1) != 0);
483  loginData.registerLogin = false;
484 
485  if (mCurrentServer.hostname.empty())
486  {
487  mCurrentServer.hostname = branding.getValue("defaultServer", "");
488  settings.options.serverName = mCurrentServer.hostname;
489  }
490 
491  if (mCurrentServer.port == 0)
492  {
493  mCurrentServer.port = CAST_U16(branding.getValue(
494  "defaultPort", CAST_S32(DEFAULT_PORT)));
495  mCurrentServer.type = ServerInfo::parseType(
496  branding.getValue("defaultServerType", "tmwathena"));
497  }
498 
499  chatLogger->setServerName(mCurrentServer.hostname);
500 
501  if (loginData.username.empty() && loginData.remember)
502  loginData.username = serverConfig.getValue("username", "");
503 
504  if (mState != State::ERROR)
505  mState = State::CHOOSE_SERVER;
506 
507  startTimers();
508 
509  const int fpsLimit = config.getIntValue("fpslimit");
510  settings.limitFps = fpsLimit > 0;
511 
513  WindowManager::setFramerate(fpsLimit);
514  initConfigListeners();
515 
516  settings.guiAlpha = config.getFloatValue("guialpha");
517  optionChanged("fpslimit");
518 
519  start_time = time(nullptr);
520 
522 
523 #ifdef ANDROID
524 #ifndef USE_SDL2
525  WindowManager::updateScreenKeyboard(SDL_GetScreenKeyboardHeight(nullptr));
526 #endif // USE_SDL2
527 #endif // ANDROID
528 
529 #ifdef USE_MUMBLE
530  if (!mumbleManager)
531  mumbleManager = new MumbleManager;
532 #endif // USE_MUMBLE
533 
534  mSkin = theme->load("windowmenu.xml", "");
535  if (mSkin != nullptr)
536  {
537  mButtonPadding = mSkin->getPadding();
538  mButtonSpacing = mSkin->getOption("spacing", 3);
539  }
540  if (settings.options.error)
542 
543  if (settings.options.validate == true)
544  runValidate();
545 }
546 
548 {
550  gameClear();
551  else
552  testsClear();
554 }
555 
557 {
558  config.addListener("fpslimit", this);
559  config.addListener("guialpha", this);
560  config.addListener("gamma", this);
561  config.addListener("enableGamma", this);
562  config.addListener("particleEmitterSkip", this);
563  config.addListener("vsync", this);
564  config.addListener("repeateDelay", this);
565  config.addListener("repeateInterval", this);
566  config.addListener("logInput", this);
567 }
568 
570 {
571  // Initialize sound engine
572  try
573  {
574  if (config.getBoolValue("sound"))
575  soundManager.init();
576 
579  }
580  catch (const char *const err)
581  {
582  mState = State::ERROR;
583  errorMessage = err;
584  logger->log("Warning: %s", err);
585  }
587  "loginMusic",
588  "keprohm.ogg"),
590 }
591 
593 {
594 #ifndef USE_SDL2
596 #endif // USE_SDL2
597 
598  runCounters = config.getBoolValue("packetcounters");
599 
601 #ifdef USE_SDL2
603 #endif // USE_SDL2
604 
609 
611 }
612 
613 void Client::testsClear()
614 {
615  if (!settings.options.test.empty())
616  gameClear();
617  else
619 }
620 
621 void Client::gameClear()
622 {
623  if (logger != nullptr)
624  logger->log1("Quitting1");
625  isTerminate = true;
626  config.removeListeners(this);
627 
629 
630  IPC::stop();
633  if (windowContainer != nullptr)
635 
636  stopTimers();
638 
639  if (loginHandler != nullptr)
641 
642  if (chatHandler != nullptr)
643  chatHandler->clear();
644 
645  if (charServerHandler != nullptr)
647 
648  delete2(ipc);
649 
650 #ifdef USE_MUMBLE
651  delete2(mumbleManager);
652 #endif // USE_MUMBLE
653 
655 
656  // Before config.write() since it writes the shortcuts to the config
657  for (unsigned f = 0; f < SHORTCUT_TABS; f ++)
661 
663 
664  if (logger != nullptr)
665  logger->log1("Quitting2");
666 
667  delete2(mCurrentDialog);
670  delete2(gui);
671 
672  if (inventoryHandler != nullptr)
674 
675  if (logger != nullptr)
676  logger->log1("Quitting3");
677 
679 
681 
682  if (logger != nullptr)
683  logger->log1("Quitting4");
684 
685  XML::cleanupXML();
686 
687  if (logger != nullptr)
688  logger->log1("Quitting5");
689 
691 
692  // Shutdown sound
694 
695  if (logger != nullptr)
696  logger->log1("Quitting6");
697 
699 
701 
703 
704  if (logger != nullptr)
705  logger->log1("Quitting8");
706 
708 
709  if (logger != nullptr)
710  logger->log1("Quitting9");
711 
712  delete2(joystick);
713 
714  keyboard.deinit();
715 
716  if (logger != nullptr)
717  logger->log1("Quitting10");
718 
720 
721 #ifdef DEBUG_CONFIG
722  config.enableKeyLogging();
723 #endif // DEBUG_CONFIG
724 
726  config.write();
728 
729  config.clear();
731 
732  if (logger != nullptr)
733  logger->log1("Quitting11");
734 
735 #ifdef USE_PROFILER
737 #endif // USE_PROFILER
738 
739 #ifdef DEBUG_OPENGL_LEAKS
740  if (logger)
741  logger->log("textures left: %d", textures_count);
742 #endif // DEBUG_OPENGL_LEAKS
743 
745 
746  if (logger != nullptr)
747  logger->log1("Quitting12");
748 
751 }
752 
753 int Client::testsExec()
754 {
755 #ifdef USE_OPENGL
756  if (settings.options.test.empty())
757  {
758  TestMain test;
759  return test.exec();
760  }
761  else
762  {
763  TestLauncher launcher(settings.options.test);
764  return launcher.exec();
765  }
766 #else // USE_OPENGL
767 
768  return 0;
769 #endif // USE_OPENGL
770 }
771 
772 #define ADDBUTTON(var, object) var = object; \
773  x -= var->getWidth() + mButtonSpacing; \
774  var->setPosition(x, mButtonPadding); \
775  top->add(var);
776 
778 {
779  if ((gameHandler != nullptr) &&
780  (loginHandler != nullptr) &&
782  {
784  }
785 }
786 
788 {
789  if (mOldState == State::CHOOSE_SERVER)
790  {
791  settings.serverName = mCurrentServer.hostname;
792  ConfigManager::initServerConfig(mCurrentServer.hostname);
794  initTradeFilter();
797 
798  // Initialize the item and emote shortcuts.
799  for (unsigned f = 0; f < SHORTCUT_TABS; f ++)
800  {
801  delete itemShortcut[f];
802  itemShortcut[f] = new ItemShortcut(f);
803  }
804  delete emoteShortcut;
806 
807  // Initialize the drop shortcuts.
808  delete dropShortcut;
810 
811  initFeatures();
813  loginData.registerUrl = mCurrentServer.registerUrl;
814  loginData.packetVersion = mCurrentServer.packetVersion;
815  if (!mCurrentServer.onlineListUrl.empty())
816  settings.onlineListUrl = mCurrentServer.onlineListUrl;
817  else
819  settings.persistentIp = mCurrentServer.persistentIp;
820  settings.supportUrl = mCurrentServer.supportUrl;
821  settings.updateMirrors = mCurrentServer.updateMirrors;
823  "enableRemoteCommands", 1) != 0);
824 
825  if (settings.options.username.empty())
826  {
827  if (loginData.remember)
828  loginData.username = serverConfig.getValue("username", "");
829  else
830  loginData.username.clear();
831  }
832  else
833  {
835  }
838 
839  loginData.remember = (serverConfig.getValue("remember", 1) != 0);
840  Net::connectToServer(mCurrentServer);
841 
842 #ifdef USE_MUMBLE
843  if (mumbleManager)
844  mumbleManager->setServer(mCurrentServer.hostname);
845 #endif // USE_MUMBLE
846 
847 #ifdef TMWA_SUPPORT
849 #endif // TMWA_SUPPORT
850 
851  if (!mConfigAutoSaved)
852  {
853  mConfigAutoSaved = true;
854  config.write();
855  }
856  }
857  else if (mOldState != State::CHOOSE_SERVER &&
858  (loginHandler != nullptr) &&
860  {
861  mState = State::PRE_LOGIN;
862  }
863 }
864 
866 {
867  if (mOldState == State::UPDATE &&
868  (loginHandler != nullptr))
869  {
870  if (loginHandler->getWorlds().size() < 2)
871  mState = State::PRE_LOGIN;
872  }
873 }
874 
876 {
877  if (gui == nullptr)
878  return;
879 
880  BasicContainer2 *const top = static_cast<BasicContainer2*>(
881  gui->getTop());
882 
883  if (top == nullptr)
884  return;
885 
886  CREATEWIDGETV(desktop, Desktop, nullptr);
887  top->add(desktop);
888  int x = top->getWidth() - mButtonPadding;
889  ADDBUTTON(mSetupButton, new Button(desktop,
890  // TRANSLATORS: setup tab quick button
891  _("Setup"), "Setup", this))
892  ADDBUTTON(mPerfomanceButton, new Button(desktop,
893  // TRANSLATORS: perfoamance tab quick button
894  _("Performance"), "Perfomance", this))
895  ADDBUTTON(mVideoButton, new Button(desktop,
896  // TRANSLATORS: video tab quick button
897  _("Video"), "Video", this))
898  ADDBUTTON(mThemesButton, new Button(desktop,
899  // TRANSLATORS: theme tab quick button
900  _("Theme"), "Themes", this))
901  ADDBUTTON(mAboutButton, new Button(desktop,
902  // TRANSLATORS: theme tab quick button
903  _("About"), "about", this))
904  ADDBUTTON(mHelpButton, new Button(desktop,
905  // TRANSLATORS: theme tab quick button
906  _("Help"), "help", this))
907 #ifdef ANDROID
908  ADDBUTTON(mCloseButton, new Button(desktop,
909  // TRANSLATORS: close quick button
910  _("Close"), "close", this))
911 #endif // ANDROID
912 
915 }
916 
918 {
919  if (mOldState == State::GAME &&
920  (gameHandler != nullptr))
921  {
923  }
924 }
925 
926 int Client::gameExec()
927 {
928  int lastTickTime = tick_time;
929 
930  while (mState != State::EXIT)
931  {
932  PROFILER_START();
934  continue;
935 
936  BLOCK_START("Client::gameExec 3")
937  if (generalHandler != nullptr)
939  BLOCK_END("Client::gameExec 3")
940 
941  BLOCK_START("Client::gameExec 4")
942  if (gui != nullptr)
943  gui->logic();
944  cur_time = time(nullptr);
945  int k = 0;
946  while (lastTickTime != tick_time &&
947  k < 40)
948  {
949  if (mGame != nullptr)
950  mGame->logic();
951  else if (gui != nullptr)
952  gui->handleInput();
953 
954  ++lastTickTime;
955  k ++;
956  }
958 
959  logic_count += k;
960  if (gui != nullptr)
961  gui->slowLogic();
962  if (mGame != nullptr)
963  mGame->slowLogic();
964  slowLogic();
965  BLOCK_END("Client::gameExec 4")
966 
967  // This is done because at some point tick_time will wrap.
968  lastTickTime = tick_time;
969 
970  // Update the screen when application is visible, delay otherwise.
972  {
973  frame_count++;
974  if (gui != nullptr)
975  gui->draw();
977  }
978  else
979  {
980  SDL_Delay(100);
981  }
982 
983  BLOCK_START("~Client::SDL_framerateDelay")
984  if (settings.limitFps)
986  BLOCK_END("~Client::SDL_framerateDelay")
987 
988  BLOCK_START("Client::gameExec 6")
989  if (mState == State::CONNECT_GAME)
990  {
991  stateConnectGame1();
992  }
993  else if (mState == State::CONNECT_SERVER)
994  {
995  stateConnectServer1();
996  }
997  else if (mState == State::WORLD_SELECT)
998  {
999  stateWorldSelect1();
1000  }
1001  else if (mOldState == State::START ||
1002  (mOldState == State::GAME && mState != State::GAME))
1003  {
1004  stateGame1();
1005  }
1006  else if (mState == State::SWITCH_LOGIN)
1007  {
1008  stateSwitchLogin1();
1009  }
1010  BLOCK_END("Client::gameExec 6")
1011 
1012  if (mState != mOldState)
1013  {
1014  BLOCK_START("Client::gameExec 7")
1015  PlayerInfo::stateChange(mState);
1016 
1017  if (mOldState == State::GAME)
1018  {
1019  delete2(mGame);
1026  if (guildHandler != nullptr)
1027  guildHandler->clear();
1028  if (partyHandler != nullptr)
1029  partyHandler->clear();
1030  if (chatLogger != nullptr)
1031  chatLogger->clear();
1032  if (!settings.options.dataPath.empty())
1034  else
1038  }
1039  else if (mOldState == State::CHAR_SELECT)
1040  {
1041  if (mState != State::CHANGEPASSWORD &&
1042  charServerHandler != nullptr)
1043  {
1045  }
1046  }
1047 
1048  mOldState = mState;
1049 
1050  // Get rid of the dialog of the previous state
1051  delete2(mCurrentDialog);
1052 
1053  // State has changed, while the quitDialog was active, it might
1054  // not be correct anymore
1055  if (mQuitDialog != nullptr)
1056  {
1057  mQuitDialog->scheduleDelete();
1058  mQuitDialog = nullptr;
1059  }
1060  BLOCK_END("Client::gameExec 7")
1061 
1062  BLOCK_START("Client::gameExec 8")
1063  switch (mState)
1064  {
1065  case State::CHOOSE_SERVER:
1066  {
1067  BLOCK_START("Client::gameExec STATE_CHOOSE_SERVER")
1068  logger->log1("State: CHOOSE SERVER");
1069  unloadData();
1070 
1071  // Allow changing this using a server choice dialog
1072  // We show the dialog box only if the command-line
1073  // options weren't set.
1074  if (settings.options.serverName.empty() &&
1075  settings.options.serverPort == 0 &&
1076  !branding.getValue("onlineServerList", "a").empty())
1077  {
1078  // Don't allow an alpha opacity
1079  // lower than the default value
1080  theme->setMinimumOpacity(0.8F);
1081 
1082  CREATEWIDGETV(mCurrentDialog, ServerDialog,
1083  &mCurrentServer,
1085  }
1086  else
1087  {
1088  mState = State::CONNECT_SERVER;
1089 
1090  // Reset options so that cancelling or connect
1091  // timeout will show the server dialog.
1092  settings.options.serverName.clear();
1094  }
1095  BLOCK_END("Client::gameExec STATE_CHOOSE_SERVER")
1096  break;
1097  }
1098 
1099  case State::CONNECT_SERVER:
1100  BLOCK_START("Client::gameExec State::CONNECT_SERVER")
1101  logger->log1("State: CONNECT SERVER");
1102  loginData.updateHosts.clear();
1103  CREATEWIDGETV(mCurrentDialog, ConnectionDialog,
1104  // TRANSLATORS: connection dialog header
1105  _("Connecting to server"),
1109  BLOCK_END("Client::gameExec State::CONNECT_SERVER")
1110  break;
1111 
1112  case State::PRE_LOGIN:
1113  logger->log1("State: PRE_LOGIN");
1114  break;
1115 
1116  case State::LOGIN:
1117  BLOCK_START("Client::gameExec State::LOGIN")
1118  logger->log1("State: LOGIN");
1119  // Don't allow an alpha opacity
1120  // lower than the default value
1121  theme->setMinimumOpacity(0.8F);
1122 
1123  if (packetVersion == 0)
1124  {
1126  if (packetVersion != 0)
1127  {
1129  logger->log("Preconfigured packet version: %d",
1130  packetVersion);
1131  }
1132  }
1133 
1134  loginData.updateType = static_cast<UpdateTypeT>(
1135  serverConfig.getValue("updateType", 0));
1136 
1138  const_cast<char*>(mCurrentServer.hostname.c_str()),
1139  CAST_S32(mCurrentServer.hostname.size()));
1140  if (settings.options.username.empty() ||
1141  settings.options.password.empty())
1142  {
1143  CREATEWIDGETV(mCurrentDialog, LoginDialog,
1144  loginData,
1145  &mCurrentServer,
1147  }
1148  else
1149  {
1150  mState = State::LOGIN_ATTEMPT;
1151  // Clear the password so that when login fails, the
1152  // dialog will show up next time.
1153  settings.options.password.clear();
1154  }
1155  BLOCK_END("Client::gameExec State::LOGIN")
1156  break;
1157 
1158  case State::LOGIN_ATTEMPT:
1159  BLOCK_START("Client::gameExec State::LOGIN_ATTEMPT")
1160  logger->log1("State: LOGIN ATTEMPT");
1161  CREATEWIDGETV(mCurrentDialog, ConnectionDialog,
1162  // TRANSLATORS: connection dialog header
1163  _("Logging in"),
1165  if (loginHandler != nullptr)
1167  BLOCK_END("Client::gameExec State::LOGIN_ATTEMPT")
1168  break;
1169 
1170  case State::WORLD_SELECT:
1171  BLOCK_START("Client::gameExec State::WORLD_SELECT")
1172  logger->log1("State: WORLD SELECT");
1173  {
1176  if (loginHandler == nullptr)
1177  {
1178  BLOCK_END("Client::gameExec State::WORLD_SELECT")
1179  break;
1180  }
1181  Worlds worlds = loginHandler->getWorlds();
1182 
1183  if (worlds.empty())
1184  {
1185  // Trust that the netcode knows what it's doing
1186  mState = State::UPDATE;
1187  }
1188  else if (worlds.size() == 1)
1189  {
1191  0, mCurrentServer.persistentIp);
1192  mState = State::UPDATE;
1193  }
1194  else
1195  {
1196  CREATEWIDGETV(mCurrentDialog, WorldSelectDialog,
1197  worlds);
1199  {
1200  static_cast<WorldSelectDialog*>(mCurrentDialog)
1201  ->action(ActionEvent(nullptr, "ok"));
1202  }
1203  }
1204  }
1205  BLOCK_END("Client::gameExec State::WORLD_SELECT")
1206  break;
1207 
1209  BLOCK_START("Client::gameExec State::WORLD_SELECT_ATTEMPT")
1210  logger->log1("State: WORLD SELECT ATTEMPT");
1211  CREATEWIDGETV(mCurrentDialog, ConnectionDialog,
1212  // TRANSLATORS: connection dialog header
1213  _("Entering game world"),
1215  BLOCK_END("Client::gameExec State::WORLD_SELECT_ATTEMPT")
1216  break;
1217 
1218  case State::UPDATE:
1219  BLOCK_START("Client::gameExec State::UPDATE")
1220  logger->log1("State: UPDATE");
1221 
1222  // Determine which source to use for the update host
1223  if (!settings.options.updateHost.empty())
1225  else
1228 
1229  if (!settings.oldUpdates.empty())
1231 
1233  {
1234  mState = State::LOAD_DATA;
1235  settings.oldUpdates.clear();
1237  }
1238  else if ((loginData.updateType & UpdateType::Skip) != 0)
1239  {
1243  mState = State::LOAD_DATA;
1244  }
1245  else
1246  {
1249  CREATEWIDGETV(mCurrentDialog, UpdaterWindow,
1252  settings.options.dataPath.empty(),
1254  }
1255  BLOCK_END("Client::gameExec State::UPDATE")
1256  break;
1257 
1258  case State::LOAD_DATA:
1259  {
1260  BLOCK_START("Client::gameExec State::LOAD_DATA")
1261  logger->log1("State: LOAD DATA");
1262 
1263  loadData();
1264 
1265  mState = State::GET_CHARACTERS;
1266  BLOCK_END("Client::gameExec State::LOAD_DATA")
1267  break;
1268  }
1269  case State::GET_CHARACTERS:
1270  BLOCK_START("Client::gameExec State::GET_CHARACTERS")
1271  logger->log1("State: GET CHARACTERS");
1272  CREATEWIDGETV(mCurrentDialog, ConnectionDialog,
1273  // TRANSLATORS: connection dialog header
1274  _("Requesting characters"),
1276  if (charServerHandler != nullptr)
1278  BLOCK_END("Client::gameExec State::GET_CHARACTERS")
1279  break;
1280 
1281  case State::CHAR_SELECT:
1282  BLOCK_START("Client::gameExec State::CHAR_SELECT")
1283  logger->log1("State: CHAR SELECT");
1284  // Don't allow an alpha opacity
1285  // lower than the default value
1286  theme->setMinimumOpacity(0.8F);
1287 
1290 
1291  CREATEWIDGETV(mCurrentDialog, CharSelectDialog,
1292  loginData);
1293 
1294  if (!(static_cast<CharSelectDialog*>(mCurrentDialog))
1295  ->selectByName(settings.options.character,
1297  {
1298  (static_cast<CharSelectDialog*>(mCurrentDialog))
1299  ->selectByName(
1300  serverConfig.getValue("lastCharacter", ""),
1304  }
1305 
1306  // Choosing character on the command line should work only
1307  // once, clear it so that 'switch character' works.
1308  settings.options.character.clear();
1309  BLOCK_END("Client::gameExec State::CHAR_SELECT")
1310  break;
1311 
1312  case State::CONNECT_GAME:
1313  BLOCK_START("Client::gameExec State::CONNECT_GAME")
1314  logger->log1("State: CONNECT GAME");
1315  CREATEWIDGETV(mCurrentDialog, ConnectionDialog,
1316  // TRANSLATORS: connection dialog header
1317  _("Connecting to the game server"),
1319  if (gameHandler != nullptr)
1320  gameHandler->connect();
1321  BLOCK_END("Client::gameExec State::CONNECT_GAME")
1322  break;
1323 
1324  case State::CHANGE_MAP:
1325  BLOCK_START("Client::gameExec State::CHANGE_MAP")
1326  logger->log1("State: CHANGE_MAP");
1327  CREATEWIDGETV(mCurrentDialog, ConnectionDialog,
1328  // TRANSLATORS: connection dialog header
1329  _("Changing game servers"),
1331  if (gameHandler != nullptr)
1332  gameHandler->connect();
1333  BLOCK_END("Client::gameExec State::CHANGE_MAP")
1334  break;
1335 
1336  case State::GAME:
1337  BLOCK_START("Client::gameExec State::GAME")
1338  if (localPlayer != nullptr)
1339  {
1340  logger->log("Memorizing selected character %s",
1341  localPlayer->getName().c_str());
1342  serverConfig.setValue("lastCharacter",
1343  localPlayer->getName());
1344 #ifdef USE_MUMBLE
1345  if (mumbleManager)
1346  mumbleManager->setPlayer(localPlayer->getName());
1347 #endif // USE_MUMBLE
1348  }
1349 
1350  // Fade out logon-music here too to give the desired effect
1351  // of "flowing" into the game.
1352  soundManager.fadeOutMusic(1000);
1353 
1354  // Allow any alpha opacity
1355  theme->setMinimumOpacity(-1.0F);
1356 
1357  if (chatLogger != nullptr)
1359 
1360 #ifdef ANDROID
1361  delete2(mCloseButton);
1362 #endif // ANDROID
1363 
1364  delete2(mSetupButton);
1365  delete2(mVideoButton);
1366  delete2(mThemesButton);
1367  delete2(mAboutButton);
1368  delete2(mHelpButton);
1369  delete2(mPerfomanceButton);
1370  delete2(desktop);
1371 
1372  mCurrentDialog = nullptr;
1373 
1374  logger->log1("State: GAME");
1375  if (generalHandler != nullptr)
1377  mGame = new Game;
1378  BLOCK_END("Client::gameExec State::GAME")
1379  break;
1380 
1381  case State::LOGIN_ERROR:
1382  BLOCK_START("Client::gameExec State::LOGIN_ERROR")
1383  logger->log1("State: LOGIN ERROR");
1384  CREATEWIDGETV(mCurrentDialog, OkDialog,
1385  // TRANSLATORS: error dialog header
1386  _("Error"),
1387  errorMessage,
1388  // TRANSLATORS: ok dialog button
1389  _("Close"),
1391  Modal_true,
1393  nullptr,
1394  260);
1395  mCurrentDialog->addActionListener(&loginListener);
1396  mCurrentDialog = nullptr; // OkDialog deletes itself
1397  BLOCK_END("Client::gameExec State::LOGIN_ERROR")
1398  break;
1399 
1401  BLOCK_START("Client::gameExec State::ACCOUNTCHANGE_ERROR")
1402  logger->log1("State: ACCOUNT CHANGE 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(&accountListener);
1415  mCurrentDialog = nullptr; // OkDialog deletes itself
1416  BLOCK_END("Client::gameExec State::ACCOUNTCHANGE_ERROR")
1417  break;
1418 
1419  case State::REGISTER_PREP:
1420  BLOCK_START("Client::gameExec State::REGISTER_PREP")
1421  logger->log1("State: REGISTER_PREP");
1422  CREATEWIDGETV(mCurrentDialog, ConnectionDialog,
1423  // TRANSLATORS: connection dialog header
1424  _("Requesting registration details"),
1425  State::LOGIN);
1427  BLOCK_END("Client::gameExec State::REGISTER_PREP")
1428  break;
1429 
1430  case State::REGISTER:
1431  logger->log1("State: REGISTER");
1432  CREATEWIDGETV(mCurrentDialog, RegisterDialog,
1433  loginData);
1434  break;
1435 
1437  BLOCK_START("Client::gameExec State::REGISTER_ATTEMPT")
1438  logger->log("Username is %s", loginData.username.c_str());
1439  if (loginHandler != nullptr)
1441  BLOCK_END("Client::gameExec State::REGISTER_ATTEMPT")
1442  break;
1443 
1444  case State::CHANGEPASSWORD:
1445  BLOCK_START("Client::gameExec State::CHANGEPASSWORD")
1446  logger->log1("State: CHANGE PASSWORD");
1447  CREATEWIDGETV(mCurrentDialog, ChangePasswordDialog,
1448  loginData);
1449  mCurrentDialog->setVisible(Visible_true);
1450  BLOCK_END("Client::gameExec State::CHANGEPASSWORD")
1451  break;
1452 
1454  BLOCK_START("Client::gameExec "
1455  "State::CHANGEPASSWORD_ATTEMPT")
1456  logger->log1("State: CHANGE PASSWORD ATTEMPT");
1457  if (loginHandler != nullptr)
1458  {
1461  }
1462  BLOCK_END("Client::gameExec State::CHANGEPASSWORD_ATTEMPT")
1463  break;
1464 
1466  BLOCK_START("Client::gameExec "
1467  "State::CHANGEPASSWORD_SUCCESS")
1468  logger->log1("State: CHANGE PASSWORD SUCCESS");
1469  CREATEWIDGETV(mCurrentDialog, OkDialog,
1470  // TRANSLATORS: password change message header
1471  _("Password Change"),
1472  // TRANSLATORS: password change message text
1473  _("Password changed successfully!"),
1474  // TRANSLATORS: ok dialog button
1475  _("OK"),
1477  Modal_true,
1479  nullptr,
1480  260);
1481  mCurrentDialog->addActionListener(&accountListener);
1482  mCurrentDialog = nullptr; // OkDialog deletes itself
1484  loginData.newPassword.clear();
1485  BLOCK_END("Client::gameExec State::CHANGEPASSWORD_SUCCESS")
1486  break;
1487 
1488  case State::CHANGEEMAIL:
1489  logger->log1("State: CHANGE EMAIL");
1490  CREATEWIDGETV(mCurrentDialog,
1492  loginData);
1493  mCurrentDialog->setVisible(Visible_true);
1494  break;
1495 
1497  logger->log1("State: CHANGE EMAIL ATTEMPT");
1498  if (loginHandler != nullptr)
1500  break;
1501 
1503  logger->log1("State: CHANGE EMAIL SUCCESS");
1504  CREATEWIDGETV(mCurrentDialog, OkDialog,
1505  // TRANSLATORS: email change message header
1506  _("Email Change"),
1507  // TRANSLATORS: email change message text
1508  _("Email changed successfully!"),
1509  // TRANSLATORS: ok dialog button
1510  _("OK"),
1512  Modal_true,
1514  nullptr,
1515  260);
1516  mCurrentDialog->addActionListener(&accountListener);
1517  mCurrentDialog = nullptr; // OkDialog deletes itself
1518  break;
1519 
1520  case State::SWITCH_SERVER:
1521  BLOCK_START("Client::gameExec State::SWITCH_SERVER")
1522  logger->log1("State: SWITCH SERVER");
1523 
1524  if (loginHandler != nullptr)
1526  if (gameHandler != nullptr)
1527  {
1529  gameHandler->clear();
1530  }
1531  settings.serverName.clear();
1532  settings.login.clear();
1534  serverConfig.write();
1535  serverConfig.unload();
1536  if (setupWindow != nullptr)
1538 
1539  mState = State::CHOOSE_SERVER;
1540  BLOCK_END("Client::gameExec State::SWITCH_SERVER")
1541  break;
1542 
1543  case State::SWITCH_LOGIN:
1544  BLOCK_START("Client::gameExec State::SWITCH_LOGIN")
1545  logger->log1("State: SWITCH LOGIN");
1546 
1547  if (loginHandler != nullptr)
1548  {
1549  loginHandler->logout();
1551  }
1552  if (gameHandler != nullptr)
1554  if (loginHandler != nullptr)
1555  loginHandler->connect();
1556 
1557  settings.login.clear();
1559  mState = State::LOGIN;
1560  BLOCK_END("Client::gameExec State::SWITCH_LOGIN")
1561  break;
1562 
1564  BLOCK_START("Client::gameExec State::SWITCH_CHARACTER")
1565  logger->log1("State: SWITCH CHARACTER");
1566 
1567  // Done with game
1568  if (gameHandler != nullptr)
1570 
1571  settings.login.clear();
1573  mState = State::GET_CHARACTERS;
1574  BLOCK_END("Client::gameExec State::SWITCH_CHARACTER")
1575  break;
1576 
1577  case State::LOGOUT_ATTEMPT:
1578  logger->log1("State: LOGOUT ATTEMPT");
1579  break;
1580 
1581  case State::WAIT:
1582  logger->log1("State: WAIT");
1583  break;
1584 
1585  case State::EXIT:
1586  BLOCK_START("Client::gameExec State::EXIT")
1587  logger->log1("State: EXIT");
1588  Net::unload();
1589  BLOCK_END("Client::gameExec State::EXIT")
1590  break;
1591 
1592  case State::FORCE_QUIT:
1593  BLOCK_START("Client::gameExec State::FORCE_QUIT")
1594  logger->log1("State: FORCE QUIT");
1595  if (generalHandler != nullptr)
1597  mState = State::EXIT;
1598  BLOCK_END("Client::gameExec State::FORCE_QUIT")
1599  break;
1600 
1601  case State::ERROR:
1602  BLOCK_START("Client::gameExec State::ERROR")
1603  config.write();
1604  if (mOldState == State::GAME)
1605  serverConfig.write();
1606  logger->log1("State: ERROR");
1607  logger->log("Error: %s\n", errorMessage.c_str());
1608  mCurrentDialog = DialogsManager::openErrorDialog(
1609  // TRANSLATORS: error message header
1610  _("Error"),
1611  errorMessage,
1612  Modal_true);
1613  mCurrentDialog->addActionListener(&errorListener);
1614  mCurrentDialog = nullptr; // OkDialog deletes itself
1616  BLOCK_END("Client::gameExec State::ERROR")
1617  break;
1618 
1620  // ++++++
1621  break;
1622 
1623  case State::START:
1624  default:
1625  mState = State::FORCE_QUIT;
1626  break;
1627  }
1628  BLOCK_END("Client::gameExec 8")
1629  }
1630  PROFILER_END();
1631  }
1632 
1633  return 0;
1634 }
1635 
1636 void Client::optionChanged(const std::string &name)
1637 {
1638  if (name == "fpslimit")
1639  {
1640  const int fpsLimit = config.getIntValue("fpslimit");
1641  settings.limitFps = fpsLimit > 0;
1642  WindowManager::setFramerate(fpsLimit);
1643  }
1644  else if (name == "guialpha" ||
1645  name == "enableGuiOpacity")
1646  {
1647  const float alpha = config.getFloatValue("guialpha");
1648  settings.guiAlpha = alpha;
1649  ImageHelper::setEnableAlpha(alpha != 1.0F &&
1650  config.getBoolValue("enableGuiOpacity"));
1651  }
1652  else if (name == "gamma" ||
1653  name == "enableGamma")
1654  {
1656  }
1657  else if (name == "particleEmitterSkip")
1658  {
1660  config.getIntValue("particleEmitterSkip") + 1;
1661  }
1662  else if (name == "vsync")
1663  {
1665  }
1666  else if (name == "repeateInterval" ||
1667  name == "repeateDelay")
1668  {
1670  }
1671 }
1672 
1673 void Client::action(const ActionEvent &event)
1674 {
1675  std::string tab;
1676  const std::string &eventId = event.getId();
1677 
1678  if (eventId == "close")
1679  {
1680  setState(State::FORCE_QUIT);
1681  return;
1682  }
1683  if (eventId == "Setup")
1684  {
1685  tab.clear();
1686  }
1687  else if (eventId == "help")
1688  {
1690  return;
1691  }
1692  else if (eventId == "about")
1693  {
1695  return;
1696  }
1697  else if (eventId == "Video")
1698  {
1699  tab = "Video";
1700  }
1701  else if (eventId == "Themes")
1702  {
1703  tab = "Theme";
1704  }
1705  else if (eventId == "Perfomance")
1706  {
1707  tab = "Perfomance";
1708  }
1709  else
1710  {
1711  return;
1712  }
1713 
1714  if (setupWindow != nullptr)
1715  {
1719  {
1720  if (!tab.empty())
1721  setupWindow->activateTab(tab);
1723  }
1724  }
1725 }
1726 
1728 {
1729  features.init(paths.getStringValue("featuresFile"),
1731  SkipError_true);
1733  settings.fixDeadAnimation = features.getBoolValue("fixDeadAnimation");
1734 }
1735 
1736 void Client::initPaths()
1737 {
1738  settings.gmCommandSymbol = paths.getStringValue("gmCommandSymbol");
1739  settings.gmCharCommandSymbol = paths.getStringValue("gmCharCommandSymbol");
1740  settings.linkCommandSymbol = paths.getStringValue("linkCommandSymbol");
1741  if (settings.linkCommandSymbol.empty())
1743  settings.overweightPercent = paths.getIntValue("overweightPercent");
1745  "playerNameOffset");
1747  "playerBadgeAtRightOffset");
1748  settings.unknownSkillsAutoTab = paths.getBoolValue("unknownSkillsAutoTab");
1749  settings.enableNewMailSystem = paths.getBoolValue("enableNewMailSystem");
1750 }
1751 
1753 {
1754  const std::string tradeListName =
1755  settings.serverConfigDir + "/tradefilter.txt";
1756 
1757  std::ofstream tradeFile;
1758  struct stat statbuf;
1759 
1760  if ((stat(tradeListName.c_str(), &statbuf) != 0) ||
1761  !S_ISREG(statbuf.st_mode))
1762  {
1763  tradeFile.open(tradeListName.c_str(),
1764  std::ios::out);
1765  if (tradeFile.is_open())
1766  {
1767  tradeFile << ": sell" << std::endl;
1768  tradeFile << ": buy" << std::endl;
1769  tradeFile << ": trade" << std::endl;
1770  tradeFile << "i sell" << std::endl;
1771  tradeFile << "i buy" << std::endl;
1772  tradeFile << "i trade" << std::endl;
1773  tradeFile << "i trading" << std::endl;
1774  tradeFile << "i am buy" << std::endl;
1775  tradeFile << "i am sell" << std::endl;
1776  tradeFile << "i am trade" << std::endl;
1777  tradeFile << "i am trading" << std::endl;
1778  tradeFile << "i'm buy" << std::endl;
1779  tradeFile << "i'm sell" << std::endl;
1780  tradeFile << "i'm trade" << std::endl;
1781  tradeFile << "i'm trading" << std::endl;
1782  }
1783  else
1784  {
1785  reportAlways("Error opening file for writing: %s",
1786  tradeListName.c_str());
1787  }
1788  tradeFile.close();
1789  }
1790 }
1791 
1792 bool Client::isTmw()
1793 {
1794  const std::string &name = settings.serverName;
1795  if (name == "server.themanaworld.org" ||
1796  name == "themanaworld.org" ||
1797  name == "167.114.129.72")
1798  {
1799  return true;
1800  }
1801  return false;
1802 }
1803 
1804 void Client::moveButtons(const int width)
1805 {
1806  if (mSetupButton != nullptr)
1807  {
1808  int x = width - mSetupButton->getWidth() - mButtonPadding;
1809  mSetupButton->setPosition(x, mButtonPadding);
1810 #ifndef WIN32
1811  x -= mPerfomanceButton->getWidth() + mButtonSpacing;
1812  mPerfomanceButton->setPosition(x, mButtonPadding);
1813 
1814  x -= mVideoButton->getWidth() + mButtonSpacing;
1815  mVideoButton->setPosition(x, mButtonPadding);
1816 
1817  x -= mThemesButton->getWidth() + mButtonSpacing;
1818  mThemesButton->setPosition(x, mButtonPadding);
1819 
1820  x -= mAboutButton->getWidth() + mButtonSpacing;
1821  mAboutButton->setPosition(x, mButtonPadding);
1822 
1823  x -= mHelpButton->getWidth() + mButtonSpacing;
1824  mHelpButton->setPosition(x, mButtonPadding);
1825 #ifdef ANDROID
1826  x -= mCloseButton->getWidth() + mButtonSpacing;
1827  mCloseButton->setPosition(x, mButtonPadding);
1828 #endif // ANDROID
1829 #endif // WIN32
1830  }
1831 }
1832 
1833 void Client::windowRemoved(const Window *const window)
1834 {
1835  if (mCurrentDialog == window)
1836  mCurrentDialog = nullptr;
1837 }
1838 
1839 void Client::logVars()
1840 {
1841 #ifdef ANDROID
1842  logger->log("APPDIR: %s", getenv("APPDIR"));
1843  logger->log("DATADIR2: %s", getSdStoragePath().c_str());
1844 #endif // ANDROID
1845 }
1846 
1847 void Client::slowLogic()
1848 {
1849  if ((gameHandler == nullptr) ||
1850  !gameHandler->mustPing())
1851  {
1852  return;
1853  }
1854 
1855  if (get_elapsed_time1(mPing) > 1500)
1856  {
1857  mPing = tick_time;
1858  if (mState == State::UPDATE ||
1859  mState == State::LOGIN ||
1860  mState == State::LOGIN_ATTEMPT ||
1861  mState == State::REGISTER ||
1862  mState == State::REGISTER_ATTEMPT)
1863  {
1864  if (loginHandler != nullptr)
1865  loginHandler->ping();
1866  if (generalHandler != nullptr)
1868  }
1869  else if (mState == State::CHAR_SELECT)
1870  {
1871  if (charServerHandler != nullptr)
1873  if (generalHandler != nullptr)
1875  }
1876  }
1877 }
1878 
1880 {
1881  // If another data path has been set,
1882  // we don't load any other files...
1883  if (settings.options.dataPath.empty())
1884  {
1885  // Add customdata directory
1887  "customdata/",
1888  "zip",
1889  Append_false);
1890  }
1891 
1893  {
1895  settings.updatesDir + "/local/",
1896  "zip",
1897  Append_false);
1898 
1902  "local/"),
1903  Append_false);
1904  }
1905 
1906  logger->log("Init paths");
1907  paths.init("paths.xml", UseVirtFs_true);
1909  initPaths();
1910  if (SpriteReference::Empty == nullptr)
1911  {
1913  paths.getStringValue("spriteErrorFile"),
1914  0);
1915  }
1916 
1917  if (BeingInfo::unknown == nullptr)
1919 
1920  initFeatures();
1923  PlayerInfo::stateChange(mState);
1924 
1927 
1928  delete spellManager;
1929  spellManager = new SpellManager;
1930  delete spellShortcut;
1932 
1934 
1936 
1937  if (desktop != nullptr)
1939 }
1940 
1942 {
1944  mCurrentServer.supportUrl.clear();
1945  settings.supportUrl.clear();
1946  if (settings.options.dataPath.empty())
1947  {
1948  // Add customdata directory
1950  "customdata/",
1951  "zip");
1952  }
1953 
1954  if (!settings.oldUpdates.empty())
1955  {
1957  settings.oldUpdates.clear();
1958  }
1959 
1961  {
1963  pathJoin(settings.updatesDir, "local/"),
1964  "zip");
1965 
1969  "local/"));
1970  }
1971 
1973 
1975  serverVersion = 0;
1976  packetVersion = 0;
1977  tmwServerVersion = 0;
1978  evolPacketOffset = 0;
1979 }
1980 
1982 {
1983  loadData();
1985 
1987  unloadData();
1988  delete2(client);
1989  VirtFs::deinit();
1990  exit(0);
1991 }
Definition: logger.h:67
void setSize(const int width, const int height)
Definition: widget.cpp:366
void gameInit()
Definition: client.cpp:157
virtual void updatePacketVersion() const =0
#define A_DELETE_COPY(func)
Definition: localconsts.h:52
Configuration branding
void stateSwitchLogin1()
Definition: client.cpp:917
void testsClear()
Definition: client.cpp:152
static void unloadUpdates(const std::string &dir)
bool ipc
Definition: options.h:99
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:875
void deinit()
Definition: playerinfo.cpp:450
static bool isTmw()
Definition: client.cpp:804
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:73
int packetVersion
Definition: logindata.h:72
void logic()
Definition: gui.cpp:301
void unload()
Definition: net.cpp:169
static void initTempDir()
Definition: dirs.cpp:376
volatile bool isTerminate
Definition: client.cpp:197
int getWidth() const
Definition: widget.h:220
void log1(const char *const log_text)
Definition: logger.cpp:222
static SpriteReference * Empty
void unloadData()
Definition: client.cpp:1941
void activateTab(const std::string &name)
ImageHelper * imageHelper
Definition: imagehelper.cpp:43
std::string logFileName
Definition: options.h:82
int packetVersion
Definition: client.cpp:120
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:121
std::string linkCommandSymbol
Definition: settings.h:125
#define PROFILER_END()
Definition: perfomance.h:77
volatile bool runCounters
Definition: client.cpp:117
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:181
static void stop()
Definition: ipc.cpp:153
std::string onlineListUrl
Definition: settings.h:114
static void initUsersDir()
Definition: dirs.cpp:590
time_t start_time
Definition: client.cpp:122
Joystick * joystick
Definition: joystick.cpp:42
virtual const Worlds & getWorlds() const =0
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:471
static void initFeatures()
Definition: client.cpp:1727
bool fixDeadAnimation
Definition: settings.h:157
void init()
Definition: playerinfo.cpp:446
SpellManager * spellManager
Options options
Definition: settings.h:128
static void initLang()
static void deleteRenderers()
bool registerLogin
Definition: logindata.h:74
static void extractDataDir() A_CONST
Definition: dirs.cpp:178
int textures_count
Definition: client.cpp:125
static void backupConfig(const std::string &name)
virtual void getRegistrationDetails() const =0
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:729
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 unmountDirSilent(std::string oldDir)
Definition: fs.cpp:553
virtual void unload() const =0
#define BLOCK_START(name)
Definition: perfomance.h:78
Definition: button.h:94
SoundManager soundManager
Configuration config
#define final
Definition: localconsts.h:45
void clear()
Definition: playerinfo.cpp:464
static void updateDataPath()
Definition: dirs.cpp:160
static ServerTypeT parseType(const std::string &serverType)
Definition: serverinfo.h:196
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
#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
void loadDb()
Definition: dbmanager.cpp:61
Client * client
Definition: client.cpp:113
#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:85
Definition: gui.h:115
static void clearParties()
Definition: party.cpp:328
void clear()
Definition: chatlogger.cpp:228
Net::GeneralHandler * generalHandler
Definition: net.cpp:81
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:1752
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:160
virtual void clear() const =0
void stateConnectGame1()
Definition: client.cpp:777
Logger * logger
Definition: logger.cpp:95
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:148
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:111
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:389
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 & 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:83
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:378
static void loadLocalUpdates(const std::string &dir)
int getHeight() const
Definition: graphics.cpp:647
bool unknownSkillsAutoTab
Definition: settings.h:162
virtual void ping() const =0
virtual void add(Widget *const widget)
void loadData()
Definition: client.cpp:1879
void moveButtons(const int width)
Definition: client.cpp:752
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:178
ErrorListener errorListener
void optionChanged(const std::string &name)
Definition: client.cpp:1636
int gameExec()
Definition: client.cpp:557
static void loadCurrentLang()
bool skipUpdate
Definition: options.h:94
Graphics * mainGraphics
Definition: graphics.cpp:108
bool isWindowVisible() const
Definition: window.h:476
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:799
void fadeOutMusic(const int ms=1000)
static std::string savedPassword
Definition: logindialog.h:79
anonymous_namespace{client.cpp}::AccountListener accountListener
#define PRAGMA48(str)
Definition: localconsts.h:214
unsigned int mLastHost
Definition: client.cpp:123
#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:370
Definition: client.h:48
std::string dataPath
Definition: options.h:80
ItemShortcut * itemShortcut[SHORTCUT_TABS]
const std::string & getName() const
Definition: being.h:233
void stateConnectServer1()
Definition: client.cpp:787
void setMusicVolume(const int volume)
void setMinimumOpacity(const float minimumOpacity)
Definition: theme.cpp:271
Net::InventoryHandler * inventoryHandler
Definition: net.cpp:82
virtual void clearWorlds() const =0
AssertListener * assertListener
void slowLogic()
Definition: client.cpp:795
EventsManager eventsManager
int serverVersion
Definition: client.cpp:119
void dumpLibs()
Definition: dumplibs.cpp:111
bool handleEvents() const
void connectToServer(const ServerInfo &server)
Definition: net.cpp:119
void initRand()
Definition: mrand.cpp:34
Skin * load(const std::string &filename, const std::string &filename2, const bool full=true, const std::string &defaultPath=getThemePath())
Definition: theme.cpp:178
Structure holding the state and timing information of the framerate controller.
Configuration paths
bool isSafeMode
Definition: client.cpp:118
std::string password
Definition: options.h:76
static void clearDialogs()
Definition: npcdialog.cpp:1213
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:171
bool Visible
Definition: visible.h:29
Widget * getTop() const
Definition: gui.h:247
void runValidate() __attribute__((noreturn))
Definition: client.cpp:1981
Net::ChatHandler * chatHandler
Definition: net.cpp:80
void loadData()
Definition: playerinfo.cpp:457
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
void reloadWallpaper()
Definition: desktop.cpp:114
void initLogger()
Definition: sdlhelper.cpp:186
static void start()
Definition: ipc.cpp:162
virtual bool mustPing() const =0
Client()
Definition: client.cpp:127
std::string password
Definition: logindata.h:59
Configuration features
void windowRemoved(const Window *const window)
Definition: client.cpp:781
int renderer
Definition: options.h:90
virtual void connect() const =0
~Client()
Definition: client.cpp:362
void unloadDb()
Definition: dbmanager.cpp:103
void detect()
Definition: cpu.cpp:45
virtual bool isConnected() const =0
void stateWorldSelect1()
Definition: client.cpp:865
Net::PartyHandler * partyHandler
Definition: net.cpp:87
virtual void logout() const =0
void stopTimers()
Definition: timer.cpp:120
void setLogFile(const std::string &logFilename)
Definition: logger.cpp:118
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:482
void dumpSizes()
Definition: dumpsizes.cpp:32
std::string configDir
Definition: settings.h:109
void setConfigDefaults2(Configuration &cfg)
Definition: defaults.cpp:424
UpdateType ::T UpdateTypeT
Definition: updatetype.h:35
KeyboardConfig keyboard
static void logVars()
Definition: client.cpp:787
void gameClear()
Definition: client.cpp:415
static void initGraphics()
Definition: client.cpp:393
#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:305
static void initScreenshotDir()
Definition: dirs.cpp:535
void initConfigListeners()
Definition: client.cpp:556
InputManager inputManager
TouchManager touchManager
void init(const std::string &filename, const UseVirtFs useResManager=UseVirtFs_false, const SkipError skipError=SkipError_false)
void error(const std::string &error_text) __attribute__((noreturn))
Definition: logger.cpp:415
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:243
static void initUpdatesDir()
Definition: dirs.cpp:442
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:145
virtual void ping() const =0
unsigned long mSearchHash
Definition: client.cpp:124
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:312
Net::GameHandler * gameHandler
Definition: net.cpp:84
void action(const ActionEvent &event)
Definition: client.cpp:710
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:79
PlayerRelationsManager playerRelations
bool enableNewMailSystem
Definition: settings.h:163
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:181
static void initHomeDir()
Definition: dirs.cpp:325
void init()
Definition: settings.cpp:33
#define ADDBUTTON(var, object)
Definition: client.cpp:772
static void checkConfigVersion()
void createValidateWindows()
static void unload()
static void initPaths()
Definition: client.cpp:816
void loadIgnorePackets()
Definition: net.cpp:183
SpellShortcut * spellShortcut
static void initLocalDataDir()
Definition: dirs.cpp:332
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:531