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