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 (loginHandler != nullptr &&
885  {
886  mState = State::PRE_LOGIN;
887  }
888 }
889 
891 {
892  if (mOldState == State::UPDATE &&
893  (loginHandler != nullptr))
894  {
895  if (loginHandler->getWorlds().size() < 2)
896  mState = State::PRE_LOGIN;
897  }
898 }
899 
901 {
902  if (gui == nullptr)
903  return;
904 
905  BasicContainer2 *const top = static_cast<BasicContainer2*>(
906  gui->getTop());
907 
908  if (top == nullptr)
909  return;
910 
911  CREATEWIDGETV(desktop, Desktop, nullptr);
912  top->add(desktop);
913  int x = top->getWidth() - mButtonPadding;
914  ADDBUTTON(mSetupButton, new Button(desktop,
915  // TRANSLATORS: setup tab quick button
916  _("Setup"), "Setup", BUTTON_SKIN, this))
917  ADDBUTTON(mPerfomanceButton, new Button(desktop,
918  // TRANSLATORS: perfoamance tab quick button
919  _("Performance"), "Perfomance", BUTTON_SKIN, this))
920  ADDBUTTON(mVideoButton, new Button(desktop,
921  // TRANSLATORS: video tab quick button
922  _("Video"), "Video", BUTTON_SKIN, this))
923  ADDBUTTON(mThemesButton, new Button(desktop,
924  // TRANSLATORS: theme tab quick button
925  _("Theme"), "Themes", BUTTON_SKIN, this))
926  ADDBUTTON(mAboutButton, new Button(desktop,
927  // TRANSLATORS: theme tab quick button
928  _("About"), "about", BUTTON_SKIN, this))
929  ADDBUTTON(mHelpButton, new Button(desktop,
930  // TRANSLATORS: theme tab quick button
931  _("Help"), "help", BUTTON_SKIN, this))
932 #ifdef ANDROID
933  ADDBUTTON(mCloseButton, new Button(desktop,
934  // TRANSLATORS: close quick button
935  _("Close"), "close", BUTTON_SKIN, this))
936 #endif // ANDROID
937 
940 }
941 
943 {
944  if (mOldState == State::GAME &&
945  (gameHandler != nullptr))
946  {
948  }
949 }
950 
951 int Client::gameExec()
952 {
953  int lastTickTime = tick_time;
954 
955  Perf::init();
956 
957  while (mState != State::EXIT)
958  {
959  PROFILER_START();
960  PERF_STAT(0);
962  continue;
963 
964  PERF_STAT(1);
965 
966  BLOCK_START("Client::gameExec 3")
967  if (generalHandler != nullptr)
969  BLOCK_END("Client::gameExec 3")
970 
971  PERF_STAT(2);
972 
973  BLOCK_START("Client::gameExec 4")
974  if (gui != nullptr)
975  gui->logic();
976 
977  PERF_STAT(3);
978 
979  cur_time = time(nullptr);
980  int k = 0;
981  while (lastTickTime != tick_time &&
982  k < 40)
983  {
984  if (mGame != nullptr)
985  mGame->logic();
986  else if (gui != nullptr)
987  gui->handleInput();
988 
989  ++lastTickTime;
990  k ++;
991  }
992 
993  PERF_STAT(4);
994 
996 
997  PERF_STAT(5);
998 
999  logic_count += k;
1000  if (gui != nullptr)
1001  gui->slowLogic();
1002 
1003  PERF_STAT(6);
1004 
1005  if (mGame != nullptr)
1006  mGame->slowLogic();
1007 
1008  PERF_STAT(7);
1009 
1010  slowLogic();
1011 
1012  PERF_STAT(8);
1013 
1014  BLOCK_END("Client::gameExec 4")
1015 
1016  // This is done because at some point tick_time will wrap.
1017  lastTickTime = tick_time;
1018 
1019  BLOCK_START("Client::gameExec 6")
1020  if (mState == State::CONNECT_GAME)
1021  {
1022  stateConnectGame1();
1023  }
1024  else if (mState == State::CONNECT_SERVER)
1025  {
1026  stateConnectServer1();
1027  }
1028  else if (mState == State::WORLD_SELECT)
1029  {
1030  stateWorldSelect1();
1031  }
1032  else if (mOldState == State::START ||
1033  (mOldState == State::GAME && mState != State::GAME))
1034  {
1035  stateGame1();
1036  }
1037  else if (mState == State::SWITCH_LOGIN)
1038  {
1039  stateSwitchLogin1();
1040  }
1041  BLOCK_END("Client::gameExec 6")
1042 
1043  PERF_STAT(9);
1044 
1045  if (mState != mOldState)
1046  {
1047  BLOCK_START("Client::gameExec 7")
1048  PlayerInfo::stateChange(mState);
1049 
1050  if (mOldState == State::GAME)
1051  {
1052  delete2(mGame);
1059  if (guildHandler != nullptr)
1060  guildHandler->clear();
1061  if (partyHandler != nullptr)
1062  partyHandler->clear();
1063  if (chatLogger != nullptr)
1064  chatLogger->clear();
1065  if (!settings.options.dataPath.empty())
1067  else
1071  }
1072  else if (mOldState == State::CHAR_SELECT)
1073  {
1074  if (mState != State::CHANGEPASSWORD &&
1075  charServerHandler != nullptr)
1076  {
1078  }
1079  }
1080 
1081  mOldState = mState;
1082 
1083  // Get rid of the dialog of the previous state
1084  delete2(mCurrentDialog);
1085 
1086  // State has changed, while the quitDialog was active, it might
1087  // not be correct anymore
1088  if (mQuitDialog != nullptr)
1089  {
1090  mQuitDialog->scheduleDelete();
1091  mQuitDialog = nullptr;
1092  }
1093  BLOCK_END("Client::gameExec 7")
1094 
1095  BLOCK_START("Client::gameExec 8")
1096  switch (mState)
1097  {
1098  case State::CHOOSE_SERVER:
1099  {
1100  BLOCK_START("Client::gameExec STATE_CHOOSE_SERVER")
1101  logger->log1("State: CHOOSE SERVER");
1102  unloadData();
1104 
1105  // Allow changing this using a server choice dialog
1106  // We show the dialog box only if the command-line
1107  // options weren't set.
1108  if (settings.options.serverName.empty() &&
1109  settings.options.serverPort == 0 &&
1110  !branding.getValue("onlineServerList", "a").empty())
1111  {
1112  // Don't allow an alpha opacity
1113  // lower than the default value
1114  theme->setMinimumOpacity(0.8F);
1115 
1116  CREATEWIDGETV(mCurrentDialog, ServerDialog,
1117  &mCurrentServer,
1119  }
1120  else
1121  {
1122  mState = State::CONNECT_SERVER;
1123 
1124  // Reset options so that cancelling or connect
1125  // timeout will show the server dialog.
1126  settings.options.serverName.clear();
1128  }
1129  BLOCK_END("Client::gameExec STATE_CHOOSE_SERVER")
1130  break;
1131  }
1132 
1133  case State::CONNECT_SERVER:
1134  BLOCK_START("Client::gameExec State::CONNECT_SERVER")
1135  logger->log1("State: CONNECT SERVER");
1136  loginData.updateHosts.clear();
1137  CREATEWIDGETV(mCurrentDialog, ConnectionDialog,
1138  // TRANSLATORS: connection dialog header
1139  _("Connecting to server"),
1143  pincodeManager.init();
1144  BLOCK_END("Client::gameExec State::CONNECT_SERVER")
1145  break;
1146 
1147  case State::PRE_LOGIN:
1148  logger->log1("State: PRE_LOGIN");
1149  break;
1150 
1151  case State::LOGIN:
1152  BLOCK_START("Client::gameExec State::LOGIN")
1153  logger->log1("State: LOGIN");
1154  // Don't allow an alpha opacity
1155  // lower than the default value
1156  theme->setMinimumOpacity(0.8F);
1157 
1158  if (packetVersion == 0)
1159  {
1161  if (packetVersion != 0)
1162  {
1164  logger->log("Preconfigured packet version: %d",
1165  packetVersion);
1166  }
1167  }
1168 
1169  loginData.updateType = static_cast<UpdateTypeT>(
1170  serverConfig.getValue("updateType", 0));
1171 
1173  const_cast<char*>(mCurrentServer.hostname.c_str()),
1174  CAST_S32(mCurrentServer.hostname.size()));
1175  if (settings.options.username.empty() ||
1176  settings.options.password.empty())
1177  {
1178  CREATEWIDGETV(mCurrentDialog, LoginDialog,
1179  loginData,
1180  &mCurrentServer,
1182  }
1183  else
1184  {
1185  mState = State::LOGIN_ATTEMPT;
1186  // Clear the password so that when login fails, the
1187  // dialog will show up next time.
1188  settings.options.password.clear();
1189  }
1190  BLOCK_END("Client::gameExec State::LOGIN")
1191  break;
1192 
1193  case State::LOGIN_ATTEMPT:
1194  BLOCK_START("Client::gameExec State::LOGIN_ATTEMPT")
1195  logger->log1("State: LOGIN ATTEMPT");
1196  CREATEWIDGETV(mCurrentDialog, ConnectionDialog,
1197  // TRANSLATORS: connection dialog header
1198  _("Logging in"),
1200  if (loginHandler != nullptr)
1202  BLOCK_END("Client::gameExec State::LOGIN_ATTEMPT")
1203  break;
1204 
1205  case State::WORLD_SELECT:
1206  BLOCK_START("Client::gameExec State::WORLD_SELECT")
1207  logger->log1("State: WORLD SELECT");
1208  {
1211  if (loginHandler == nullptr)
1212  {
1213  BLOCK_END("Client::gameExec State::WORLD_SELECT")
1214  break;
1215  }
1216  Worlds worlds = loginHandler->getWorlds();
1217 
1218  if (worlds.empty())
1219  {
1220  // Trust that the netcode knows what it's doing
1221  mState = State::UPDATE;
1222  }
1223  else if (worlds.size() == 1)
1224  {
1226  0, mCurrentServer.persistentIp);
1227  mState = State::UPDATE;
1228  }
1229  else
1230  {
1231  CREATEWIDGETV(mCurrentDialog, WorldSelectDialog,
1232  worlds);
1234  {
1235  static_cast<WorldSelectDialog*>(mCurrentDialog)
1236  ->action(ActionEvent(nullptr, "ok"));
1237  }
1238  }
1239  }
1240  BLOCK_END("Client::gameExec State::WORLD_SELECT")
1241  break;
1242 
1244  BLOCK_START("Client::gameExec State::WORLD_SELECT_ATTEMPT")
1245  logger->log1("State: WORLD SELECT ATTEMPT");
1246  CREATEWIDGETV(mCurrentDialog, ConnectionDialog,
1247  // TRANSLATORS: connection dialog header
1248  _("Entering game world"),
1250  BLOCK_END("Client::gameExec State::WORLD_SELECT_ATTEMPT")
1251  break;
1252 
1253  case State::UPDATE:
1254  BLOCK_START("Client::gameExec State::UPDATE")
1255  logger->log1("State: UPDATE");
1256 
1257  // Determine which source to use for the update host
1258  if (!settings.options.updateHost.empty())
1260  else
1263 
1264  if (!settings.oldUpdates.empty())
1266 
1268  {
1269  mState = State::LOAD_DATA;
1270  settings.oldUpdates.clear();
1272  }
1273  else if ((loginData.updateType & UpdateType::Skip) != 0)
1274  {
1278  mState = State::LOAD_DATA;
1279  }
1280  else
1281  {
1284  CREATEWIDGETV(mCurrentDialog, UpdaterWindow,
1287  settings.options.dataPath.empty(),
1289  }
1290  BLOCK_END("Client::gameExec State::UPDATE")
1291  break;
1292 
1293  case State::LOAD_DATA:
1294  {
1295  BLOCK_START("Client::gameExec State::LOAD_DATA")
1296  logger->log1("State: LOAD DATA");
1297 
1298  loadData();
1299 
1300  mState = State::GET_CHARACTERS;
1301  BLOCK_END("Client::gameExec State::LOAD_DATA")
1302  break;
1303  }
1304  case State::GET_CHARACTERS:
1305  BLOCK_START("Client::gameExec State::GET_CHARACTERS")
1306  logger->log1("State: GET CHARACTERS");
1307  CREATEWIDGETV(mCurrentDialog, ConnectionDialog,
1308  // TRANSLATORS: connection dialog header
1309  _("Requesting characters"),
1311  if (charServerHandler != nullptr)
1313  BLOCK_END("Client::gameExec State::GET_CHARACTERS")
1314  break;
1315 
1316  case State::CHAR_SELECT:
1317  BLOCK_START("Client::gameExec State::CHAR_SELECT")
1318  logger->log1("State: CHAR SELECT");
1319  // Don't allow an alpha opacity
1320  // lower than the default value
1321  theme->setMinimumOpacity(0.8F);
1322 
1325 
1326  CREATEWIDGETV(mCurrentDialog, CharSelectDialog,
1327  loginData);
1329 
1330  if (!(static_cast<CharSelectDialog*>(mCurrentDialog))
1331  ->selectByName(settings.options.character,
1333  {
1334  (static_cast<CharSelectDialog*>(mCurrentDialog))
1335  ->selectByName(
1336  serverConfig.getValue("lastCharacter", ""),
1340  }
1341 
1342  // Choosing character on the command line should work only
1343  // once, clear it so that 'switch character' works.
1344  settings.options.character.clear();
1345  BLOCK_END("Client::gameExec State::CHAR_SELECT")
1346  break;
1347 
1348  case State::CONNECT_GAME:
1349  BLOCK_START("Client::gameExec State::CONNECT_GAME")
1350  logger->log1("State: CONNECT GAME");
1351  CREATEWIDGETV(mCurrentDialog, ConnectionDialog,
1352  // TRANSLATORS: connection dialog header
1353  _("Connecting to the game server"),
1355  if (gameHandler != nullptr)
1356  gameHandler->connect();
1357  BLOCK_END("Client::gameExec State::CONNECT_GAME")
1358  break;
1359 
1360  case State::CHANGE_MAP:
1361  BLOCK_START("Client::gameExec State::CHANGE_MAP")
1362  logger->log1("State: CHANGE_MAP");
1363  CREATEWIDGETV(mCurrentDialog, ConnectionDialog,
1364  // TRANSLATORS: connection dialog header
1365  _("Changing game servers"),
1367  if (gameHandler != nullptr)
1368  gameHandler->connect();
1369  BLOCK_END("Client::gameExec State::CHANGE_MAP")
1370  break;
1371 
1372  case State::GAME:
1373  BLOCK_START("Client::gameExec State::GAME")
1374  if (localPlayer != nullptr)
1375  {
1376  logger->log("Memorizing selected character %s",
1377  localPlayer->getName().c_str());
1378  serverConfig.setValue("lastCharacter",
1379  localPlayer->getName());
1380 #ifdef USE_MUMBLE
1381  if (mumbleManager)
1382  mumbleManager->setPlayer(localPlayer->getName());
1383 #endif // USE_MUMBLE
1384  Perf::init();
1385  }
1386 
1387  // Fade out logon-music here too to give the desired effect
1388  // of "flowing" into the game.
1389  soundManager.fadeOutMusic(1000);
1390 
1391  // Allow any alpha opacity
1392  theme->setMinimumOpacity(-1.0F);
1393 
1394  if (chatLogger != nullptr)
1396 
1397 #ifdef ANDROID
1398  delete2(mCloseButton);
1399 #endif // ANDROID
1400 
1401  delete2(mSetupButton);
1402  delete2(mVideoButton);
1403  delete2(mThemesButton);
1404  delete2(mAboutButton);
1405  delete2(mHelpButton);
1406  delete2(mPerfomanceButton);
1407  delete2(desktop);
1408 
1409  mCurrentDialog = nullptr;
1410 
1411  logger->log1("State: GAME");
1412  if (generalHandler != nullptr)
1414  mGame = new Game;
1415  BLOCK_END("Client::gameExec State::GAME")
1416  break;
1417 
1418  case State::LOGIN_ERROR:
1419  BLOCK_START("Client::gameExec State::LOGIN_ERROR")
1420  logger->log1("State: LOGIN ERROR");
1421  CREATEWIDGETV(mCurrentDialog, OkDialog,
1422  // TRANSLATORS: error dialog header
1423  _("Error"),
1424  errorMessage,
1425  // TRANSLATORS: ok dialog button
1426  _("Close"),
1428  Modal_true,
1430  nullptr,
1431  260);
1432  mCurrentDialog->addActionListener(&loginListener);
1433  mCurrentDialog = nullptr; // OkDialog deletes itself
1434  BLOCK_END("Client::gameExec State::LOGIN_ERROR")
1435  break;
1436 
1438  BLOCK_START("Client::gameExec State::ACCOUNTCHANGE_ERROR")
1439  logger->log1("State: ACCOUNT CHANGE ERROR");
1440  CREATEWIDGETV(mCurrentDialog, OkDialog,
1441  // TRANSLATORS: error dialog header
1442  _("Error"),
1443  errorMessage,
1444  // TRANSLATORS: ok dialog button
1445  _("Close"),
1447  Modal_true,
1449  nullptr,
1450  260);
1451  mCurrentDialog->addActionListener(&accountListener);
1452  mCurrentDialog = nullptr; // OkDialog deletes itself
1453  BLOCK_END("Client::gameExec State::ACCOUNTCHANGE_ERROR")
1454  break;
1455 
1456  case State::REGISTER_PREP:
1457  BLOCK_START("Client::gameExec State::REGISTER_PREP")
1458  logger->log1("State: REGISTER_PREP");
1459  CREATEWIDGETV(mCurrentDialog, ConnectionDialog,
1460  // TRANSLATORS: connection dialog header
1461  _("Requesting registration details"),
1462  State::LOGIN);
1464  BLOCK_END("Client::gameExec State::REGISTER_PREP")
1465  break;
1466 
1467  case State::REGISTER:
1468  logger->log1("State: REGISTER");
1469  CREATEWIDGETV(mCurrentDialog, RegisterDialog,
1470  loginData);
1471  break;
1472 
1474  BLOCK_START("Client::gameExec State::REGISTER_ATTEMPT")
1475  logger->log("Username is %s", loginData.username.c_str());
1476  if (loginHandler != nullptr)
1478  BLOCK_END("Client::gameExec State::REGISTER_ATTEMPT")
1479  break;
1480 
1481  case State::CHANGEPASSWORD:
1482  BLOCK_START("Client::gameExec State::CHANGEPASSWORD")
1483  logger->log1("State: CHANGE PASSWORD");
1484  CREATEWIDGETV(mCurrentDialog, ChangePasswordDialog,
1485  loginData);
1486  mCurrentDialog->setVisible(Visible_true);
1487  BLOCK_END("Client::gameExec State::CHANGEPASSWORD")
1488  break;
1489 
1491  BLOCK_START("Client::gameExec "
1492  "State::CHANGEPASSWORD_ATTEMPT")
1493  logger->log1("State: CHANGE PASSWORD ATTEMPT");
1494  if (loginHandler != nullptr)
1495  {
1498  }
1499  BLOCK_END("Client::gameExec State::CHANGEPASSWORD_ATTEMPT")
1500  break;
1501 
1503  BLOCK_START("Client::gameExec "
1504  "State::CHANGEPASSWORD_SUCCESS")
1505  logger->log1("State: CHANGE PASSWORD SUCCESS");
1506  CREATEWIDGETV(mCurrentDialog, OkDialog,
1507  // TRANSLATORS: password change message header
1508  _("Password Change"),
1509  // TRANSLATORS: password change message text
1510  _("Password changed successfully!"),
1511  // TRANSLATORS: ok dialog button
1512  _("OK"),
1514  Modal_true,
1516  nullptr,
1517  260);
1518  mCurrentDialog->addActionListener(&accountListener);
1519  mCurrentDialog = nullptr; // OkDialog deletes itself
1521  loginData.newPassword.clear();
1522  BLOCK_END("Client::gameExec State::CHANGEPASSWORD_SUCCESS")
1523  break;
1524 
1525  case State::CHANGEEMAIL:
1526  logger->log1("State: CHANGE EMAIL");
1527  CREATEWIDGETV(mCurrentDialog,
1529  loginData);
1530  mCurrentDialog->setVisible(Visible_true);
1531  break;
1532 
1534  logger->log1("State: CHANGE EMAIL ATTEMPT");
1535  if (loginHandler != nullptr)
1537  break;
1538 
1540  logger->log1("State: CHANGE EMAIL SUCCESS");
1541  CREATEWIDGETV(mCurrentDialog, OkDialog,
1542  // TRANSLATORS: email change message header
1543  _("Email Change"),
1544  // TRANSLATORS: email change message text
1545  _("Email changed successfully!"),
1546  // TRANSLATORS: ok dialog button
1547  _("OK"),
1549  Modal_true,
1551  nullptr,
1552  260);
1553  mCurrentDialog->addActionListener(&accountListener);
1554  mCurrentDialog = nullptr; // OkDialog deletes itself
1555  break;
1556 
1557  case State::SWITCH_SERVER:
1558  BLOCK_START("Client::gameExec State::SWITCH_SERVER")
1559  logger->log1("State: SWITCH SERVER");
1560 
1561  if (loginHandler != nullptr)
1563  if (gameHandler != nullptr)
1564  {
1566  gameHandler->clear();
1567  }
1568  settings.serverName.clear();
1569  settings.login.clear();
1571  serverConfig.write();
1572  serverConfig.unload();
1573  if (setupWindow != nullptr)
1575 
1576  mState = State::CHOOSE_SERVER;
1577  BLOCK_END("Client::gameExec State::SWITCH_SERVER")
1578  break;
1579 
1580  case State::SWITCH_LOGIN:
1581  BLOCK_START("Client::gameExec State::SWITCH_LOGIN")
1582  logger->log1("State: SWITCH LOGIN");
1583 
1584  if (loginHandler != nullptr)
1585  {
1586  loginHandler->logout();
1588  }
1589  if (gameHandler != nullptr)
1591  if (loginHandler != nullptr)
1592  loginHandler->connect();
1593 
1594  settings.login.clear();
1596  mState = State::LOGIN;
1597  BLOCK_END("Client::gameExec State::SWITCH_LOGIN")
1598  break;
1599 
1601  BLOCK_START("Client::gameExec State::SWITCH_CHARACTER")
1602  logger->log1("State: SWITCH CHARACTER");
1603 
1604  // Done with game
1605  if (gameHandler != nullptr)
1607 
1608  settings.login.clear();
1610  mState = State::GET_CHARACTERS;
1611  BLOCK_END("Client::gameExec State::SWITCH_CHARACTER")
1612  break;
1613 
1614  case State::LOGOUT_ATTEMPT:
1615  logger->log1("State: LOGOUT ATTEMPT");
1616  break;
1617 
1618  case State::WAIT:
1619  logger->log1("State: WAIT");
1620  break;
1621 
1622  case State::EXIT:
1623  BLOCK_START("Client::gameExec State::EXIT")
1624  logger->log1("State: EXIT");
1625  Net::unload();
1626  BLOCK_END("Client::gameExec State::EXIT")
1627  break;
1628 
1629  case State::FORCE_QUIT:
1630  BLOCK_START("Client::gameExec State::FORCE_QUIT")
1631  logger->log1("State: FORCE QUIT");
1632  if (generalHandler != nullptr)
1634  mState = State::EXIT;
1635  BLOCK_END("Client::gameExec State::FORCE_QUIT")
1636  break;
1637 
1638  case State::ERROR:
1639  BLOCK_START("Client::gameExec State::ERROR")
1640  config.write();
1641  if (mOldState == State::GAME)
1642  serverConfig.write();
1643  logger->log1("State: ERROR");
1644  logger->log("Error: %s\n", errorMessage.c_str());
1646  mCurrentDialog = DialogsManager::openErrorDialog(
1647  // TRANSLATORS: error message header
1648  _("Error"),
1649  errorMessage,
1650  Modal_true);
1651  mCurrentDialog->addActionListener(&errorListener);
1652  mCurrentDialog = nullptr; // OkDialog deletes itself
1654  BLOCK_END("Client::gameExec State::ERROR")
1655  break;
1656 
1658  // ++++++
1659  break;
1660 
1661  case State::START:
1662  default:
1663  mState = State::FORCE_QUIT;
1664  break;
1665  }
1666  BLOCK_END("Client::gameExec 8")
1667  }
1668 
1669  PERF_STAT(10);
1670 
1671  // Update the screen when application is visible, delay otherwise.
1673  {
1674  frame_count++;
1675  if (gui != nullptr)
1676  gui->draw();
1678  }
1679  else
1680  {
1681  SDL_Delay(100);
1682  }
1683 
1684  PERF_STAT(11);
1685 
1686  BLOCK_START("~Client::SDL_framerateDelay")
1687  if (settings.limitFps)
1689  BLOCK_END("~Client::SDL_framerateDelay")
1690 
1691  PERF_STAT(12);
1692  PERF_NEXTFRAME();
1693  PROFILER_END();
1694  }
1695 
1696  return 0;
1697 }
1698 
1699 void Client::optionChanged(const std::string &name)
1700 {
1701  if (name == "fpslimit")
1702  {
1703  const int fpsLimit = config.getIntValue("fpslimit");
1704  settings.limitFps = fpsLimit > 0;
1705  WindowManager::setFramerate(fpsLimit);
1706  }
1707  else if (name == "guialpha" ||
1708  name == "enableGuiOpacity")
1709  {
1710  const float alpha = config.getFloatValue("guialpha");
1711  settings.guiAlpha = alpha;
1712  ImageHelper::setEnableAlpha(alpha != 1.0F &&
1713  config.getBoolValue("enableGuiOpacity"));
1714  }
1715  else if (name == "gamma" ||
1716  name == "enableGamma")
1717  {
1719  }
1720  else if (name == "particleEmitterSkip")
1721  {
1723  config.getIntValue("particleEmitterSkip") + 1;
1724  }
1725  else if (name == "vsync")
1726  {
1728  }
1729  else if (name == "repeateInterval" ||
1730  name == "repeateDelay")
1731  {
1733  }
1734 }
1735 
1736 void Client::action(const ActionEvent &event)
1737 {
1738  std::string tab;
1739  const std::string &eventId = event.getId();
1740 
1741  if (eventId == "close")
1742  {
1743  setState(State::FORCE_QUIT);
1744  return;
1745  }
1746  if (eventId == "Setup")
1747  {
1748  tab.clear();
1749  }
1750  else if (eventId == "help")
1751  {
1753  return;
1754  }
1755  else if (eventId == "about")
1756  {
1758  return;
1759  }
1760  else if (eventId == "Video")
1761  {
1762  tab = "Video";
1763  }
1764  else if (eventId == "Themes")
1765  {
1766  tab = "Theme";
1767  }
1768  else if (eventId == "Perfomance")
1769  {
1770  tab = "Perfomance";
1771  }
1772  else
1773  {
1774  return;
1775  }
1776 
1777  if (setupWindow != nullptr)
1778  {
1782  {
1783  if (!tab.empty())
1784  setupWindow->activateTab(tab);
1786  }
1787  }
1788 }
1789 
1791 {
1792  features.init(paths.getStringValue("featuresFile"),
1794  SkipError_true);
1796  settings.fixDeadAnimation = features.getBoolValue("fixDeadAnimation");
1797 }
1798 
1799 void Client::initPaths()
1800 {
1801  settings.gmCommandSymbol = paths.getStringValue("gmCommandSymbol");
1802  settings.gmCharCommandSymbol = paths.getStringValue("gmCharCommandSymbol");
1803  settings.linkCommandSymbol = paths.getStringValue("linkCommandSymbol");
1804  if (settings.linkCommandSymbol.empty())
1806  settings.overweightPercent = paths.getIntValue("overweightPercent");
1808  "playerNameOffset");
1810  "playerBadgeAtRightOffset");
1811  settings.unknownSkillsAutoTab = paths.getBoolValue("unknownSkillsAutoTab");
1812  settings.enableNewMailSystem = paths.getBoolValue("enableNewMailSystem");
1813 }
1814 
1816 {
1817  const std::string tradeListName =
1818  settings.serverConfigDir + "/tradefilter.txt";
1819 
1820  std::ofstream tradeFile;
1821  struct stat statbuf;
1822 
1823  if ((stat(tradeListName.c_str(), &statbuf) != 0) ||
1824  !S_ISREG(statbuf.st_mode))
1825  {
1826  tradeFile.open(tradeListName.c_str(),
1827  std::ios::out);
1828  if (tradeFile.is_open())
1829  {
1830  tradeFile << ": sell" << std::endl;
1831  tradeFile << ": buy" << std::endl;
1832  tradeFile << ": trade" << std::endl;
1833  tradeFile << "i sell" << std::endl;
1834  tradeFile << "i buy" << std::endl;
1835  tradeFile << "i trade" << std::endl;
1836  tradeFile << "i trading" << std::endl;
1837  tradeFile << "i am buy" << std::endl;
1838  tradeFile << "i am sell" << std::endl;
1839  tradeFile << "i am trade" << std::endl;
1840  tradeFile << "i am trading" << std::endl;
1841  tradeFile << "i'm buy" << std::endl;
1842  tradeFile << "i'm sell" << std::endl;
1843  tradeFile << "i'm trade" << std::endl;
1844  tradeFile << "i'm trading" << std::endl;
1845  }
1846  else
1847  {
1848  reportAlways("Error opening file for writing: %s",
1849  tradeListName.c_str());
1850  }
1851  tradeFile.close();
1852  }
1853 }
1854 
1855 bool Client::isTmw()
1856 {
1857  const std::string &name = settings.serverName;
1858  if (name == "server.themanaworld.org" ||
1859  name == "themanaworld.org" ||
1860  name == "167.114.129.72")
1861  {
1862  return true;
1863  }
1864  return false;
1865 }
1866 
1867 void Client::moveButtons(const int width)
1868 {
1869  if (mSetupButton != nullptr)
1870  {
1871  int x = width - mSetupButton->getWidth() - mButtonPadding;
1872  mSetupButton->setPosition(x, mButtonPadding);
1873 #ifndef WIN32
1874  x -= mPerfomanceButton->getWidth() + mButtonSpacing;
1875  mPerfomanceButton->setPosition(x, mButtonPadding);
1876 
1877  x -= mVideoButton->getWidth() + mButtonSpacing;
1878  mVideoButton->setPosition(x, mButtonPadding);
1879 
1880  x -= mThemesButton->getWidth() + mButtonSpacing;
1881  mThemesButton->setPosition(x, mButtonPadding);
1882 
1883  x -= mAboutButton->getWidth() + mButtonSpacing;
1884  mAboutButton->setPosition(x, mButtonPadding);
1885 
1886  x -= mHelpButton->getWidth() + mButtonSpacing;
1887  mHelpButton->setPosition(x, mButtonPadding);
1888 #ifdef ANDROID
1889  x -= mCloseButton->getWidth() + mButtonSpacing;
1890  mCloseButton->setPosition(x, mButtonPadding);
1891 #endif // ANDROID
1892 #endif // WIN32
1893  }
1894 }
1895 
1896 void Client::windowRemoved(const Window *const window)
1897 {
1898  if (mCurrentDialog == window)
1899  mCurrentDialog = nullptr;
1900 }
1901 
1902 void Client::focusWindow()
1903 {
1904  if (mCurrentDialog != nullptr)
1905  {
1906  mCurrentDialog->requestFocus();
1907  }
1908 }
1909 
1911 {
1912  if (mCurrentDialog == nullptr ||
1913  mState != State::CHAR_SELECT)
1914  {
1915  return;
1916  }
1917  CharSelectDialog *const dialog =
1918  dynamic_cast<CharSelectDialog*>(mCurrentDialog);
1919  if (dialog != nullptr)
1921 }
1922 
1923 void Client::logVars()
1924 {
1925 #ifdef ANDROID
1926  logger->log("APPDIR: %s", getenv("APPDIR"));
1927  logger->log("DATADIR2: %s", getSdStoragePath().c_str());
1928 #endif // ANDROID
1929 }
1930 
1931 void Client::slowLogic()
1932 {
1933  if ((gameHandler == nullptr) ||
1934  !gameHandler->mustPing())
1935  {
1936  return;
1937  }
1938 
1939  if (get_elapsed_time1(mPing) > 1500)
1940  {
1941  mPing = tick_time;
1942  if (mState == State::UPDATE ||
1943  mState == State::LOGIN ||
1944  mState == State::LOGIN_ATTEMPT ||
1945  mState == State::REGISTER ||
1946  mState == State::REGISTER_ATTEMPT)
1947  {
1948  if (loginHandler != nullptr)
1949  loginHandler->ping();
1950  if (generalHandler != nullptr)
1952  }
1953  else if (mState == State::CHAR_SELECT)
1954  {
1955  if (charServerHandler != nullptr)
1957  if (generalHandler != nullptr)
1959  }
1960  }
1961 }
1962 
1964 {
1965  // If another data path has been set,
1966  // we don't load any other files...
1967  if (settings.options.dataPath.empty())
1968  {
1969  // Add customdata directory
1971  "customdata/",
1972  "zip",
1973  Append_false);
1974  }
1975 
1977  {
1979  settings.updatesDir + "/local/",
1980  "zip",
1981  Append_false);
1982 
1986  "local/"),
1987  Append_false);
1988  }
1989 
1990  logger->log("Init paths");
1991  paths.init("paths.xml",
1993  SkipError_false);
1995  initPaths();
1996  if (SpriteReference::Empty == nullptr)
1997  {
1999  paths.getStringValue("spriteErrorFile"),
2000  0);
2001  }
2002 
2003  if (BeingInfo::unknown == nullptr)
2005 
2006  initFeatures();
2009  PlayerInfo::stateChange(mState);
2010 
2013 
2014  delete spellManager;
2015  spellManager = new SpellManager;
2016  delete spellShortcut;
2018 
2020 
2022 
2023  if (desktop != nullptr)
2025 }
2026 
2028 {
2030  mCurrentServer.supportUrl.clear();
2031  settings.supportUrl.clear();
2032  if (settings.options.dataPath.empty())
2033  {
2034  // Add customdata directory
2036  "customdata/",
2037  "zip");
2038  }
2039 
2040  if (!settings.oldUpdates.empty())
2041  {
2043  settings.oldUpdates.clear();
2044  }
2045 
2047  {
2049  pathJoin(settings.updatesDir, "local/"),
2050  "zip");
2051 
2055  "local/"));
2056  }
2057 
2059 
2061  localClan.clear();
2062  serverVersion = 0;
2063  packetVersion = 0;
2064  packetVersionMain = 0;
2065  packetVersionRe = 0;
2066  packetVersionZero = 0;
2067  tmwServerVersion = 0;
2068  evolPacketOffset = 0;
2069 }
2070 
2072 {
2073  loadData();
2075 
2077  unloadData();
2078  delete2(client);
2079  VirtFs::deinit();
2080  exit(0);
2081 }
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:942
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:900
void deinit()
Definition: playerinfo.cpp:436
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:175
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:2027
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:1790
bool fixDeadAnimation
Definition: settings.h:157
void init()
Definition: playerinfo.cpp:432
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:450
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:89
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:85
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:1815
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:397
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:87
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:1963
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:1699
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:198
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:86
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:125
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:159
PincodeManager pincodeManager
bool Visible
Definition: visible.h:29
Widget * getTop() const
Definition: gui.h:247
void runValidate() __attribute__((noreturn))
Definition: client.cpp:2071
Net::ChatHandler * chatHandler
Definition: net.cpp:83
void loadData()
Definition: playerinfo.cpp:443
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:890
Net::PartyHandler * partyHandler
Definition: net.cpp:91
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:468
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:276
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:88
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:82
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:189
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