Advertisement
Guest User

teste

a guest
May 16th, 2014
293
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 29.64 KB | None | 0 0
  1. ////////////////////////////////////////////////////////////////////////
  2. // OpenTibia - an opensource roleplaying game
  3. ////////////////////////////////////////////////////////////////////////
  4. // This program is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // This program is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU General Public License
  15. // along with this program.  If not, see <http://www.gnu.org/licenses/>.
  16. ////////////////////////////////////////////////////////////////////////
  17.  
  18. #include "otpch.h"
  19. #include "otsystem.h"
  20. #include <signal.h>
  21.  
  22. #include <iostream>
  23. #include <fstream>
  24. #include <iomanip>
  25.  
  26. #ifndef WINDOWS
  27. #include <unistd.h>
  28. #include <termios.h>
  29. #else
  30. #include <conio.h>
  31. #endif
  32.  
  33. #include <boost/config.hpp>
  34.  
  35. #include <openssl/rsa.h>
  36. #include <openssl/bn.h>
  37. #include <openssl/err.h>
  38.  
  39. #include "server.h"
  40. #ifdef __LOGIN_SERVER__
  41. #include "gameservers.h"
  42. #endif
  43. #include "networkmessage.h"
  44.  
  45. #include "game.h"
  46. #include "chat.h"
  47. #include "tools.h"
  48.  
  49. #include "protocollogin.h"
  50. #include "protocolgame.h"
  51. #include "protocolold.h"
  52. #include "protocolhttp.h"
  53.  
  54. #include "status.h"
  55. #include "manager.h"
  56. #ifdef __OTADMIN__
  57. #include "admin.h"
  58. #endif
  59.  
  60. #include "configmanager.h"
  61. #include "scriptmanager.h"
  62. #include "databasemanager.h"
  63.  
  64. #include "iologindata.h"
  65. #include "ioban.h"
  66.  
  67. #include "outfit.h"
  68. #include "vocation.h"
  69. #include "group.h"
  70.  
  71. #include "quests.h"
  72. #include "raids.h"
  73.  
  74. #include "monsters.h"
  75. #ifdef __OTSERV_ALLOCATOR__
  76. #include "allocator.h"
  77. #endif
  78. #ifdef __EXCEPTION_TRACER__
  79. #include "exception.h"
  80. #endif
  81. #ifndef __OTADMIN__
  82. #include "textlogger.h"
  83. #endif
  84.  
  85. #ifdef __NO_BOOST_EXCEPTIONS__
  86. #include <exception>
  87.  
  88. inline void boost::throw_exception(std::exception const & e)
  89. {
  90.     std::clog << "Boost exception: " << e.what() << std::endl;
  91. }
  92. #endif
  93.  
  94. RSA* g_RSA;
  95. ConfigManager g_config;
  96. Game g_game;
  97. Chat g_chat;
  98. Monsters g_monsters;
  99. Npcs g_npcs;
  100.  
  101. boost::mutex g_loaderLock;
  102. boost::condition_variable g_loaderSignal;
  103. boost::unique_lock<boost::mutex> g_loaderUniqueLock(g_loaderLock);
  104. std::list<std::pair<uint32_t, uint32_t> > serverIps;
  105.  
  106. bool argumentsHandler(StringVec args)
  107. {
  108.     StringVec tmp;
  109.     for(StringVec::iterator it = args.begin(); it != args.end(); ++it)
  110.     {
  111.         if((*it) == "--help")
  112.         {
  113.             std::clog << "Usage:\n"
  114.             "\n"
  115.             "\t--config=$1\t\tAlternate configuration file path.\n"
  116.             "\t--data-directory=$1\tAlternate data directory path.\n"
  117.             "\t--ip=$1\t\t\tIP address of the server.\n"
  118.             "\t\t\t\tShould be equal to the global IP.\n"
  119.             "\t--login-port=$1\tPort for login server to listen on.\n"
  120.             "\t--game-port=$1\tPort for game server to listen on.\n"
  121.             "\t--admin-port=$1\tPort for admin server to listen on.\n"
  122.             "\t--manager-port=$1\tPort for manager server to listen on.\n"
  123.             "\t--status-port=$1\tPort for status server to listen on.\n";
  124. #ifndef WINDOWS
  125.             std::clog << "\t--runfile=$1\t\tSpecifies run file. Will contain the pid\n"
  126.             "\t\t\t\tof the server process as long as run status.\n";
  127. #endif
  128.             std::clog << "\t--log=$1\t\tWhole standard output will be logged to\n"
  129.             "\t\t\t\tthis file.\n"
  130.             "\t--closed\t\t\tStarts the server as closed.\n"
  131.             "\t--no-script\t\t\tStarts the server without script system.\n";
  132.             return false;
  133.         }
  134.  
  135.         if((*it) == "--version" || (*it) == "-v")
  136.         {
  137.             std::clog << SOFTWARE_NAME << ", version " << SOFTWARE_VERSION << " (" << SOFTWARE_CODENAME << ")\n"
  138.             "Compiled with " << BOOST_COMPILER << " (x86_64: " << __x86_64__ << ") at " << __DATE__ << ", " << __TIME__ << ".\n"
  139.             "A server developed by " << SOFTWARE_DEVELOPERS << ".\n"
  140.             "Visit our forum for updates, support and resources: http://otland.net.\n";
  141.             return false;
  142.         }
  143.  
  144.         tmp = explodeString((*it), "=");
  145.         if(tmp[0] == "--config")
  146.             g_config.setString(ConfigManager::CONFIG_FILE, tmp[1]);
  147.         else if(tmp[0] == "--data-directory")
  148.             g_config.setString(ConfigManager::DATA_DIRECTORY, tmp[1]);
  149.         else if(tmp[0] == "--logs-directory")
  150.             g_config.setString(ConfigManager::LOGS_DIRECTORY, tmp[1]);
  151.         else if(tmp[0] == "--ip")
  152.             g_config.setString(ConfigManager::IP, tmp[1]);
  153.         else if(tmp[0] == "--login-port")
  154.             g_config.setNumber(ConfigManager::LOGIN_PORT, atoi(tmp[1].c_str()));
  155.         else if(tmp[0] == "--game-port")
  156.             g_config.setNumber(ConfigManager::GAME_PORT, atoi(tmp[1].c_str()));
  157.         else if(tmp[0] == "--admin-port")
  158.             g_config.setNumber(ConfigManager::ADMIN_PORT, atoi(tmp[1].c_str()));
  159.         else if(tmp[0] == "--manager-port")
  160.             g_config.setNumber(ConfigManager::MANAGER_PORT, atoi(tmp[1].c_str()));
  161.         else if(tmp[0] == "--status-port")
  162.             g_config.setNumber(ConfigManager::STATUS_PORT, atoi(tmp[1].c_str()));
  163. #ifndef WINDOWS
  164.         else if(tmp[0] == "--runfile" || tmp[0] == "--run-file" || tmp[0] == "--pidfile" || tmp[0] == "--pid-file")
  165.             g_config.setString(ConfigManager::RUNFILE, tmp[1]);
  166. #endif
  167.         else if(tmp[0] == "--log")
  168.             g_config.setString(ConfigManager::OUTPUT_LOG, tmp[1]);
  169. #ifndef WINDOWS
  170.         else if(tmp[0] == "--daemon" || tmp[0] == "-d")
  171.             g_config.setBool(ConfigManager::DAEMONIZE, true);
  172. #endif
  173.         else if(tmp[0] == "--closed")
  174.             g_config.setBool(ConfigManager::START_CLOSED, true);
  175.         else if(tmp[0] == "--no-script" || tmp[0] == "--noscript")
  176.             g_config.setBool(ConfigManager::SCRIPT_SYSTEM, false);
  177.     }
  178.  
  179.     return true;
  180. }
  181.  
  182. #ifndef WINDOWS
  183. int32_t OTSYS_getch()
  184. {
  185.     struct termios oldt;
  186.     tcgetattr(STDIN_FILENO, &oldt);
  187.  
  188.     struct termios newt = oldt;
  189.     newt.c_lflag &= ~(ICANON | ECHO);
  190.     tcsetattr(STDIN_FILENO, TCSANOW, &newt);
  191.  
  192.     int32_t ch = getchar();
  193.     tcsetattr(STDIN_FILENO, TCSANOW, &oldt);
  194.     return ch;
  195. }
  196.  
  197. void signalHandler(int32_t sig)
  198. {
  199.     switch(sig)
  200.     {
  201.         case SIGHUP:
  202.             Dispatcher::getInstance().addTask(createTask(
  203.                 boost::bind(&Game::saveGameState, &g_game, (uint8_t)SAVE_PLAYERS | (uint8_t)SAVE_MAP | (uint8_t)SAVE_STATE)));
  204.             break;
  205.  
  206.         case SIGTRAP:
  207.             g_game.cleanMap();
  208.             break;
  209.  
  210.         case SIGCHLD:
  211.             g_game.proceduralRefresh();
  212.             break;
  213.  
  214.         case SIGUSR1:
  215.             Dispatcher::getInstance().addTask(createTask(
  216.                 boost::bind(&Game::setGameState, &g_game, GAMESTATE_CLOSED)));
  217.             break;
  218.  
  219.         case SIGUSR2:
  220.             g_game.setGameState(GAMESTATE_NORMAL);
  221.             break;
  222.  
  223.         case SIGCONT:
  224.             Dispatcher::getInstance().addTask(createTask(
  225.                 boost::bind(&Game::reloadInfo, &g_game, RELOAD_ALL, 0, false)));
  226.             break;
  227.  
  228.         case SIGQUIT:
  229.             Dispatcher::getInstance().addTask(createTask(
  230.                 boost::bind(&Game::setGameState, &g_game, GAMESTATE_SHUTDOWN)));
  231.             break;
  232.  
  233.         case SIGTERM:
  234.             Dispatcher::getInstance().addTask(createTask(
  235.                 boost::bind(&Game::shutdown, &g_game)));
  236.  
  237.             Dispatcher::getInstance().stop();
  238.             Scheduler::getInstance().stop();
  239.             break;
  240.  
  241.         default:
  242.             break;
  243.     }
  244. }
  245.  
  246. void runfileHandler(void)
  247. {
  248.     std::ofstream runfile(g_config.getString(ConfigManager::RUNFILE).c_str(), std::ios::trunc | std::ios::out);
  249.     runfile.close();
  250. }
  251. #else
  252. int32_t OTSYS_getch()
  253. {
  254.     return (int32_t)getchar();
  255. }
  256. #endif
  257.  
  258. void allocationHandler()
  259. {
  260.     puts("Allocation failed, server out of memory!\nDecrease size of your map or compile in a 64-bit mode.");
  261.     OTSYS_getch();
  262.     std::exit(-1);
  263. }
  264.  
  265. void startupErrorMessage(std::string error = "")
  266. {
  267.     // we will get a crash here as the threads aren't going down smoothly
  268.     if(error.length() > 0)
  269.         std::clog << std::endl << "> ERROR: " << error << std::endl;
  270.  
  271.     OTSYS_getch();
  272.     std::exit(-1);
  273. }
  274.  
  275. void otserv(StringVec args, ServiceManager* services);
  276. int main(int argc, char* argv[])
  277. {
  278.     std::srand((uint32_t)OTSYS_TIME());
  279.     StringVec args = StringVec(argv, argv + argc);
  280.     if(argc > 1 && !argumentsHandler(args))
  281.         return 0;
  282.  
  283.     std::set_new_handler(allocationHandler);
  284.     ServiceManager servicer;
  285.     g_config.startup();
  286.  
  287. #ifdef __OTSERV_ALLOCATOR_STATS__
  288.     //boost::thread(boost::bind(&allocatorStatsThread, (void*)NULL));
  289.     // TODO: this thread needs a shutdown (timed_lock + interrupt? .interrupt + .unlock)
  290. #endif
  291. #ifdef __EXCEPTION_TRACER__
  292.     ExceptionHandler mainExceptionHandler;
  293.     mainExceptionHandler.InstallHandler();
  294. #endif
  295. #ifndef WINDOWS
  296.  
  297.     // ignore sigpipe...
  298.     struct sigaction sigh;
  299.     sigh.sa_handler = SIG_IGN;
  300.     sigh.sa_flags = 0;
  301.  
  302.     sigemptyset(&sigh.sa_mask);
  303.     sigaction(SIGPIPE, &sigh, NULL);
  304.  
  305.     // register signals
  306.     signal(SIGHUP, signalHandler); //save
  307.     signal(SIGTRAP, signalHandler); //clean
  308.     signal(SIGCHLD, signalHandler); //refresh
  309.     signal(SIGUSR1, signalHandler); //close server
  310.     signal(SIGUSR2, signalHandler); //open server
  311.     signal(SIGCONT, signalHandler); //reload all
  312.     signal(SIGQUIT, signalHandler); //save & shutdown
  313.     signal(SIGTERM, signalHandler); //shutdown
  314. #endif
  315.  
  316.     OutputHandler::getInstance();
  317.     Dispatcher::getInstance().addTask(createTask(boost::bind(otserv, args, &servicer)));
  318.     g_loaderSignal.wait(g_loaderUniqueLock);
  319.  
  320.     boost::this_thread::sleep(boost::posix_time::milliseconds(1000));
  321.     if(servicer.isRunning())
  322.     {
  323.         Status::getInstance();
  324.         std::clog << ">> " << g_config.getString(ConfigManager::SERVER_NAME) << " server Online!" << std::endl << std::endl;
  325.         servicer.run();
  326.     }
  327.     else
  328.         std::clog << ">> " << g_config.getString(ConfigManager::SERVER_NAME) << " server Offline! No services available..." << std::endl << std::endl;
  329.  
  330.     Dispatcher::getInstance().exit();
  331.     Scheduler::getInstance().exit();
  332.  
  333. #ifdef __EXCEPTION_TRACER__
  334.     mainExceptionHandler.RemoveHandler();
  335. #endif
  336.     return 0;
  337. }
  338.  
  339. void otserv(StringVec, ServiceManager* services)
  340. {
  341.     std::srand((uint32_t)OTSYS_TIME());
  342. #if defined(WINDOWS)
  343.     SetConsoleTitle(SOFTWARE_NAME);
  344.  
  345. #endif
  346.     g_game.setGameState(GAMESTATE_STARTUP);
  347. #if !defined(WINDOWS) && !defined(__ROOT_PERMISSION__)
  348.     if(!getuid() || !geteuid())
  349.     {
  350.         std::clog << "> WARNING: " << SOFTWARE_NAME << " has been executed as super user! It is "
  351.             << "recommended to run as a normal user." << std::endl << "Continue? (y/N)" << std::endl;
  352.         char buffer = OTSYS_getch();
  353.         if(buffer != 121 && buffer != 89)
  354.             startupErrorMessage("Aborted.");
  355.     }
  356. #endif
  357.  
  358.     std::clog << SOFTWARE_NAME << ", version " << SOFTWARE_VERSION << " (" << SOFTWARE_CODENAME << ")" << std::endl
  359.         << "Compiled with " << BOOST_COMPILER << " (x86_64: " << __x86_64__ << ") at " << __DATE__ << ", " << __TIME__ << "." << std::endl
  360.         << "A server developed by " << SOFTWARE_DEVELOPERS << "." << std::endl
  361.         << "Visit our forum for updates, support and resources: http://otland.net." << std::endl << std::endl;
  362.     std::stringstream ss;
  363. #ifdef __DEBUG__
  364.     ss << " GLOBAL";
  365. #endif
  366. #ifdef __DEBUG_MOVESYS__
  367.     ss << " MOVESYS";
  368. #endif
  369. #ifdef __DEBUG_CHAT__
  370.     ss << " CHAT";
  371. #endif
  372. #ifdef __DEBUG_HOUSES__
  373.     ss << " HOUSES";
  374. #endif
  375. #ifdef __DEBUG_LUASCRIPTS__
  376.     ss << " LUA-SCRIPTS";
  377. #endif
  378. #ifdef __DEBUG_MAILBOX__
  379.     ss << " MAILBOX";
  380. #endif
  381. #ifdef __DEBUG_NET__
  382.     ss << " NET";
  383. #endif
  384. #ifdef __DEBUG_NET_DETAIL__
  385.     ss << " NET-DETAIL";
  386. #endif
  387. #ifdef __DEBUG_RAID__
  388.     ss << " RAIDS";
  389. #endif
  390. #ifdef __DEBUG_SCHEDULER__
  391.     ss << " SCHEDULER";
  392. #endif
  393. #ifdef __DEBUG_SPAWN__
  394.     ss << " SPAWNS";
  395. #endif
  396. #ifdef __SQL_QUERY_DEBUG__
  397.     ss << " SQL-QUERIES";
  398. #endif
  399.  
  400.     std::string debug = ss.str();
  401.     if(!debug.empty())
  402.         std::clog << ">> Debugging:" << debug << "." << std::endl;
  403.  
  404.     std::clog << ">> Loading config (" << g_config.getString(ConfigManager::CONFIG_FILE) << ")" << std::endl;
  405.     if(!g_config.load())
  406.         startupErrorMessage("Unable to load " + g_config.getString(ConfigManager::CONFIG_FILE) + "!");
  407.  
  408. #ifndef WINDOWS
  409.     if(g_config.getBool(ConfigManager::DAEMONIZE))
  410.     {
  411.         std::clog << "> Daemonization... ";
  412.         if(fork())
  413.         {
  414.             std::clog << "succeed, bye!" << std::endl;
  415.             exit(0);
  416.         }
  417.         else
  418.             std::clog << "failed, continuing." << std::endl;
  419.     }
  420.  
  421. #endif
  422.     // silently append trailing slash
  423.     std::string path = g_config.getString(ConfigManager::DATA_DIRECTORY);
  424.     g_config.setString(ConfigManager::DATA_DIRECTORY, path.erase(path.find_last_not_of("/") + 1) + "/");
  425.  
  426.     path = g_config.getString(ConfigManager::LOGS_DIRECTORY);
  427.     g_config.setString(ConfigManager::LOGS_DIRECTORY, path.erase(path.find_last_not_of("/") + 1) + "/");
  428.  
  429.     std::clog << "> Opening logs" << std::endl;
  430.     Logger::getInstance()->open();
  431.  
  432.     IntegerVec cores = vectorAtoi(explodeString(g_config.getString(ConfigManager::CORES_USED), ","));
  433.     if(cores[0] != -1)
  434.     {
  435. #ifdef WINDOWS
  436.         int32_t mask = 0;
  437.         for(IntegerVec::iterator it = cores.begin(); it != cores.end(); ++it)
  438.             mask += 1 << (*it);
  439.  
  440.         SetProcessAffinityMask(GetCurrentProcess(), mask);
  441.     }
  442.  
  443.     std::stringstream mutexName;
  444.     mutexName << "forgottenserver_" << g_config.getNumber(ConfigManager::WORLD_ID);
  445.  
  446.     CreateMutex(NULL, FALSE, mutexName.str().c_str());
  447.     if(GetLastError() == ERROR_ALREADY_EXISTS)
  448.         startupErrorMessage("Another instance of The Forgotten Server is already running with the same worldId.\nIf you want to run multiple servers, please change the worldId in configuration file.");
  449.  
  450.     std::string defaultPriority = asLowerCaseString(g_config.getString(ConfigManager::DEFAULT_PRIORITY));
  451.     if(defaultPriority == "realtime" || defaultPriority == "real")
  452.         SetPriorityClass(GetCurrentProcess(), REALTIME_PRIORITY_CLASS);
  453.     else if(defaultPriority == "high" || defaultPriority == "regular")
  454.         SetPriorityClass(GetCurrentProcess(), HIGH_PRIORITY_CLASS);
  455.     else if(defaultPriority == "higher" || defaultPriority == "above" || defaultPriority == "normal")
  456.         SetPriorityClass(GetCurrentProcess(), ABOVE_NORMAL_PRIORITY_CLASS);
  457.  
  458. #else
  459. #ifndef __APPLE__
  460.         cpu_set_t mask;
  461.         CPU_ZERO(&mask);
  462.         for(IntegerVec::iterator it = cores.begin(); it != cores.end(); ++it)
  463.             CPU_SET((*it), &mask);
  464.  
  465.         sched_setaffinity(getpid(), (int32_t)sizeof(mask), &mask);
  466.     }
  467. #endif
  468.  
  469.     std::string runPath = g_config.getString(ConfigManager::RUNFILE);
  470.     if(!runPath.empty() && runPath.length() > 2)
  471.     {
  472.         std::ofstream runFile(runPath.c_str(), std::ios::trunc | std::ios::out);
  473.         runFile << getpid();
  474.         runFile.close();
  475.         atexit(runfileHandler);
  476.     }
  477.  
  478.     if(!nice(g_config.getNumber(ConfigManager::NICE_LEVEL))) {}
  479. #endif
  480.     std::string encryptionType = asLowerCaseString(g_config.getString(ConfigManager::ENCRYPTION_TYPE));
  481.     if(encryptionType == "md5")
  482.     {
  483.         g_config.setNumber(ConfigManager::ENCRYPTION, ENCRYPTION_MD5);
  484.         std::clog << "> Using MD5 encryption" << std::endl;
  485.     }
  486.     else if(encryptionType == "sha1")
  487.     {
  488.         g_config.setNumber(ConfigManager::ENCRYPTION, ENCRYPTION_SHA1);
  489.         std::clog << "> Using SHA1 encryption" << std::endl;
  490.     }
  491.     else if(encryptionType == "sha256")
  492.     {
  493.         g_config.setNumber(ConfigManager::ENCRYPTION, ENCRYPTION_SHA256);
  494.         std::clog << "> Using SHA256 encryption" << std::endl;
  495.     }
  496.     else if(encryptionType == "sha512")
  497.     {
  498.         g_config.setNumber(ConfigManager::ENCRYPTION, ENCRYPTION_SHA512);
  499.         std::clog << "> Using SHA512 encryption" << std::endl;
  500.     }
  501.     else
  502.     {
  503.         g_config.setNumber(ConfigManager::ENCRYPTION, ENCRYPTION_PLAIN);
  504.         std::clog << "> Using plaintext encryption" << std::endl << std::endl
  505.             << "> WARNING: This method is completely unsafe!" << std::endl
  506.             << "> Please set encryptionType = \"sha1\" (or any other available method) in config.lua" << std::endl;
  507.         boost::this_thread::sleep(boost::posix_time::seconds(15));
  508.     }
  509.     std::clog << ">> Loading RSA key";
  510.     g_RSA = RSA_new();
  511.  
  512.     BN_dec2bn(&g_RSA->p, g_config.getString(ConfigManager::RSA_PRIME1).c_str());
  513.     BN_dec2bn(&g_RSA->q, g_config.getString(ConfigManager::RSA_PRIME2).c_str());
  514.     BN_dec2bn(&g_RSA->d, g_config.getString(ConfigManager::RSA_PRIVATE).c_str());
  515.     BN_dec2bn(&g_RSA->n, g_config.getString(ConfigManager::RSA_MODULUS).c_str());
  516.     BN_dec2bn(&g_RSA->e, g_config.getString(ConfigManager::RSA_PUBLIC).c_str());
  517.  
  518.     // This check will verify keys set in config.lua
  519.     if(RSA_check_key(g_RSA))
  520.     {
  521.         std::clog << std::endl << "> Calculating dmp1, dmq1 and iqmp for RSA...";
  522.  
  523.         // Ok, now we calculate a few things, dmp1, dmq1 and iqmp
  524.         BN_CTX* ctx = BN_CTX_new();
  525.         BN_CTX_start(ctx);
  526.  
  527.         BIGNUM *r1 = BN_CTX_get(ctx), *r2 = BN_CTX_get(ctx);
  528.         BN_mod(g_RSA->dmp1, g_RSA->d, r1, ctx);
  529.         BN_mod(g_RSA->dmq1, g_RSA->d, r2, ctx);
  530.  
  531.         BN_mod_inverse(g_RSA->iqmp, g_RSA->q, g_RSA->p, ctx);
  532.         std::clog << " done" << std::endl;
  533.     }
  534.     else
  535.     {
  536.         ERR_load_crypto_strings();
  537.         std::stringstream s;
  538.  
  539.         s << std::endl << "> OpenSSL failed - " << ERR_error_string(ERR_get_error(), NULL);
  540.         startupErrorMessage(s.str());
  541.     }
  542.  
  543.     std::clog << ">> Starting SQL connection" << std::endl;
  544.     Database* db = Database::getInstance();
  545.     if(db && db->isConnected())
  546.     {
  547.         std::clog << ">> Running Database Manager" << std::endl;
  548.         if(DatabaseManager::getInstance()->isDatabaseSetup())
  549.         {
  550.             uint32_t version = 0;
  551.             do
  552.             {
  553.                 version = DatabaseManager::getInstance()->updateDatabase();
  554.                 if(version == 0)
  555.                     break;
  556.  
  557.                 std::clog << "> Database has been updated to version: " << version << "." << std::endl;
  558.             }
  559.             while(version < VERSION_DATABASE);
  560.         }
  561.         else
  562.             startupErrorMessage("The database you have specified in config.lua is empty, please import schemas/<engine>.sql to the database.");
  563.  
  564.         DatabaseManager::getInstance()->checkTriggers();
  565.         DatabaseManager::getInstance()->checkEncryption();
  566.         if(g_config.getBool(ConfigManager::OPTIMIZE_DATABASE) && !DatabaseManager::getInstance()->optimizeTables())
  567.             std::clog << "> No tables were optimized." << std::endl;
  568.     }
  569.     else
  570.         startupErrorMessage("Couldn't estabilish connection to SQL database!");
  571.        
  572.     std::clog << ">> Checking for duplicated items" << std::endl;
  573. DBQuery query;
  574. query << "SELECT unitedItems.serial, COUNT(1) AS duplicatesCount FROM (SELECT serial FROM `player_items` UNION ALL SELECT serial FROM `player_depotitems` UNION ALL SELECT serial FROM `tile_items`) unitedItems GROUP BY unitedItems.serial HAVING COUNT(1) > 1;";
  575. std::string logText = "";
  576.  
  577. DBResult* result;
  578. bool duplicated = false;
  579.  
  580. if(result = db->storeQuery(query.str()))
  581. {
  582.     do
  583.     {
  584.         std::string serial = result->getDataString("serial");
  585.         DBResult* result_;
  586.         DBQuery query_playeritems;
  587.         query_playeritems << "SELECT `player_id`, `pid`, `sid`, `itemtype`, `count`, `attributes`, `serial` FROM `player_items` WHERE `serial` = " << db->escapeString(serial) << ";";
  588.         if(result_ = db->storeQuery(query_playeritems.str()))
  589.         {
  590.             duplicated = true;
  591.             do
  592.             {
  593.                 std::string name;
  594.                 IOLoginData::getInstance()->getNameByGuid((uint32_t)result_->getDataInt("player_id"), name, false);
  595.                 std::clog << ">> Deleted item from 'player_items' with SERIAL: [" << serial.c_str() << "] PLAYER: [" << result_->getDataInt("player_id") << "] PLAYER NAME: [" << name.c_str() << "] ITEM: [" << result_->getDataInt("itemtype") << "] COUNT: [" << result_->getDataInt("count") << "]" << std::endl;
  596.                 std::stringstream logText;
  597.                 logText << "Deleted item from 'player_items' with SERIAL: [" << serial << "] PLAYER: [" << result_->getDataInt("player_id") << "] PLAYER NAME: [" << name << "] ITEM: [" << result_->getDataInt("itemtype") << "] COUNT: [" << result_->getDataInt("count") << "]";
  598.                 Logger::getInstance()->eFile("anti_dupe.log", logText.str(), true);
  599.             }
  600.             while(result_->next());
  601.             result_->free();
  602.         }
  603.  
  604.         query_playeritems.clear();
  605.         DBQuery query_playerdepotitems;
  606.         query_playerdepotitems << "SELECT `player_id`, `sid`, `pid`, `itemtype`, `count`, `attributes`, `serial` FROM `player_depotitems` WHERE `serial` = " << db->escapeString(serial) << ";";
  607.         if(result_ = db->storeQuery(query_playerdepotitems.str()))
  608.         {
  609.             duplicated = true;
  610.             do
  611.             {
  612.                 std::string name;
  613.                 IOLoginData::getInstance()->getNameByGuid((uint32_t)result_->getDataInt("player_id"), name, false);
  614.                 std::clog << ">> Deleted item from 'player_depotitems' with SERIAL: [" << serial.c_str() << "] PLAYER: [" << result_->getDataInt("player_id") << "] PLAYER NAME: [" << name.c_str() << "] ITEM: [" << result_->getDataInt("itemtype") << "] COUNT: [" << result_->getDataInt("count") << "]" << std::endl;
  615.                 std::stringstream logText;
  616.                 logText << "Deleted item from 'player_depotitems' with SERIAL: [" << serial << "] PLAYER: [" << result_->getDataInt("player_id") << "] PLAYER NAME: [" << name << "] ITEM: [" << result_->getDataInt("itemtype") << "] COUNT: [" << result_->getDataInt("count") << "]";
  617.                 Logger::getInstance()->eFile("anti_dupe.log", logText.str(), true);
  618.             }
  619.             while(result_->next());
  620.             result_->free();
  621.         }
  622.  
  623.         query_playerdepotitems.clear();
  624.         DBQuery query_tileitems;
  625.         query_tileitems << "SELECT `tile_id`, `world_id`, `sid`, `pid`, `itemtype`, `count`, `attributes`, `serial` FROM `tile_items` WHERE `serial` = " << db->escapeString(serial) << ";";
  626.         if(result_ = db->storeQuery(query_tileitems.str()))
  627.         {
  628.             duplicated = true;
  629.             do
  630.             {
  631.                 std::clog << ">> Deleted item from 'tile_items' with SERIAL: [" << serial.c_str() << "] TILE ID: [" << result_->getDataInt("tile_id") << "] WORLD ID: [" << result_->getDataInt("world_id") << "] ITEM: [" << result_->getDataInt("itemtype") << "] COUNT: [" << result_->getDataInt("count") << "]" << std::endl;
  632.                 std::stringstream logText;
  633.                 logText << "Deleted item from 'tile_items' with SERIAL: [" << serial << "] TILE ID: [" << result_->getDataInt("tile_id") << "] WORLD ID: [" << result_->getDataInt("world_id") << "] ITEM: [" << result_->getDataInt("itemtype") << "] COUNT: [" << result_->getDataInt("count") << "]";
  634.                 Logger::getInstance()->eFile("anti_dupe.log", logText.str(), true);
  635.             }
  636.             while(result_->next());
  637.             result_->free();
  638.         }
  639.         query_tileitems.clear();
  640.         DBQuery query_deletepi;
  641.         query_deletepi << "DELETE FROM `player_items` WHERE `serial` = " << db->escapeString(serial) << ";";
  642.         if(!db->query(query_deletepi.str()))
  643.             std::clog << ">> Cannot delete duplicated items from 'player_items'!" << std::endl;
  644.  
  645.         query_deletepi.clear();
  646.         DBQuery query_deletedi;
  647.         query_deletedi << "DELETE FROM `player_depotitems` WHERE `serial` = " << db->escapeString(serial) << ";";
  648.         if(!db->query(query_deletedi.str()))
  649.             std::clog << ">> Cannot delete duplicated items from 'player_depotitems'!" << std::endl;
  650.  
  651.         query_deletedi.clear();
  652.         DBQuery query_deleteti;
  653.         query_deleteti << "DELETE FROM `tile_items` WHERE `serial` = " << db->escapeString(serial) << ";";
  654.         if(!db->query(query_deleteti.str()))
  655.             std::clog << ">> Cannot delete duplicated items from 'tile_items'!" << std::endl;
  656.  
  657.         query_deleteti.clear();
  658.     }
  659.     while(result->next());
  660.     result->free();
  661.     if(duplicated)
  662.         std::clog << ">> Duplicated items successfully removed." << std::endl;
  663. }
  664. else
  665.     std::clog << ">> There wasn't duplicated items in the server." << std::endl;
  666.  
  667.     std::clog << ">> Loading items (OTB)" << std::endl;
  668.     if(Item::items.loadFromOtb(getFilePath(FILE_TYPE_OTHER, "items/items.otb")))
  669.         startupErrorMessage("Unable to load items (OTB)!");
  670.  
  671.     std::clog << ">> Loading items (XML)" << std::endl;
  672.     if(!Item::items.loadFromXml())
  673.     {
  674.         std::clog << "Unable to load items (XML)! Continue? (y/N)" << std::endl;
  675.         char buffer = OTSYS_getch();
  676.         if(buffer != 121 && buffer != 89)
  677.             startupErrorMessage("Unable to load items (XML)!");
  678.     }
  679.  
  680.     std::clog << ">> Loading groups" << std::endl;
  681.     if(!Groups::getInstance()->loadFromXml())
  682.         startupErrorMessage("Unable to load groups!");
  683.  
  684.     std::clog << ">> Loading vocations" << std::endl;
  685.     if(!Vocations::getInstance()->loadFromXml())
  686.         startupErrorMessage("Unable to load vocations!");
  687.  
  688.     std::clog << ">> Loading outfits" << std::endl;
  689.     if(!Outfits::getInstance()->loadFromXml())
  690.         startupErrorMessage("Unable to load outfits!");
  691.  
  692.     std::clog << ">> Loading chat channels" << std::endl;
  693.     if(!g_chat.loadFromXml())
  694.         startupErrorMessage("Unable to load chat channels!");
  695.  
  696.     if(g_config.getBool(ConfigManager::SCRIPT_SYSTEM))
  697.     {
  698.         std::clog << ">> Loading script systems" << std::endl;
  699.         if(!ScriptManager::getInstance()->loadSystem())
  700.             startupErrorMessage();
  701.     }
  702.     else
  703.         ScriptManager::getInstance();
  704.  
  705.     std::clog << ">> Loading mods..." << std::endl;
  706.     if(!ScriptManager::getInstance()->loadMods())
  707.         startupErrorMessage();
  708.  
  709.     #ifdef __LOGIN_SERVER__
  710.     std::clog << ">> Loading game servers" << std::endl;
  711.     if(!GameServers::getInstance()->loadFromXml(true))
  712.         startupErrorMessage("Unable to load game servers!");
  713.  
  714.     #endif
  715.     std::clog << ">> Loading experience stages" << std::endl;
  716.     if(!g_game.loadExperienceStages())
  717.         startupErrorMessage("Unable to load experience stages!");
  718.  
  719.     std::clog << ">> Loading quests" << std::endl;
  720.     Quests::getInstance()->loadFromXml();
  721.  
  722.     std::clog << ">> Loading monsters" << std::endl;
  723.     if(!g_monsters.loadFromXml())
  724.     {
  725.         std::clog << "Unable to load monsters! Continue? (y/N)" << std::endl;
  726.         char buffer = OTSYS_getch();
  727.         if(buffer != 121 && buffer != 89)
  728.             startupErrorMessage("Unable to load monsters!");
  729.     }
  730.  
  731.     if(fileExists(getFilePath(FILE_TYPE_OTHER, "npc/npcs.xml").c_str()))
  732.     {
  733.         std::clog << ">> Loading npcs" << std::endl;
  734.         if(!g_npcs.loadFromXml())
  735.         {
  736.             std::clog << "Unable to load npcs! Continue? (y/N)" << std::endl;
  737.             char buffer = OTSYS_getch();
  738.             if(buffer != 121 && buffer != 89)
  739.                 startupErrorMessage("Unable to load npcs!");
  740.         }
  741.     }
  742.  
  743.     std::clog << ">> Loading raids" << std::endl;
  744.     Raids::getInstance()->loadFromXml();
  745.  
  746.     std::clog << ">> Loading map and spawns..." << std::endl;
  747.     if(!g_game.loadMap(g_config.getString(ConfigManager::MAP_NAME)))
  748.         startupErrorMessage();
  749.  
  750.     std::clog << ">> Checking world type... ";
  751.     std::string worldType = asLowerCaseString(g_config.getString(ConfigManager::WORLD_TYPE));
  752.     if(worldType == "open" || worldType == "2" || worldType == "openpvp")
  753.     {
  754.         g_game.setWorldType(WORLDTYPE_OPEN);
  755.         std::clog << "Open PvP" << std::endl;
  756.     }
  757.     else if(worldType == "optional" || worldType == "1" || worldType == "optionalpvp")
  758.     {
  759.         g_game.setWorldType(WORLDTYPE_OPTIONAL);
  760.         std::clog << "Optional PvP" << std::endl;
  761.     }
  762.     else if(worldType == "hardcore" || worldType == "3" || worldType == "hardcorepvp")
  763.     {
  764.         g_game.setWorldType(WORLDTYPE_HARDCORE);
  765.         std::clog << "Hardcore PvP" << std::endl;
  766.     }
  767.     else
  768.     {
  769.         std::clog << std::endl;
  770.         startupErrorMessage("Unknown world type: " + g_config.getString(ConfigManager::WORLD_TYPE));
  771.     }
  772.  
  773.     std::clog << ">> Starting to dominate the world... done." << std::endl
  774.         << ">> Initializing game state and binding services..." << std::endl;
  775.     g_game.setGameState(GAMESTATE_INIT);
  776.     IPAddressList ipList;
  777.  
  778.     StringVec ip = explodeString(g_config.getString(ConfigManager::IP), ",");
  779.     if(asLowerCaseString(ip[0]) == "auto")
  780.     {
  781.         // TODO: automatic shit
  782.     }
  783.  
  784.     IPAddress m_ip;
  785.     std::clog << "> Global IP address(es): ";
  786.     for(StringVec::iterator it = ip.begin(); it != ip.end(); ++it)
  787.     {
  788.         uint32_t resolvedIp = inet_addr(it->c_str());
  789.         if(resolvedIp == INADDR_NONE)
  790.         {
  791.             struct hostent* host = gethostbyname(it->c_str());
  792.             if(!host)
  793.             {
  794.                 std::clog << "..." << std::endl;
  795.                 startupErrorMessage("Cannot resolve " + (*it) + "!");
  796.             }
  797.  
  798.             resolvedIp = *(uint32_t*)host->h_addr;
  799.         }
  800.  
  801.         serverIps.push_front(std::make_pair(resolvedIp, 0));
  802.         m_ip = boost::asio::ip::address_v4(swap_uint32(resolvedIp));
  803.  
  804.         ipList.push_back(m_ip);
  805.         std::clog << m_ip.to_string() << std::endl;
  806.     }
  807.  
  808.     ipList.push_back(boost::asio::ip::address_v4(INADDR_LOOPBACK));
  809.     if(!g_config.getBool(ConfigManager::BIND_ONLY_GLOBAL_ADDRESS))
  810.     {
  811.         char hostName[128];
  812.         if(!gethostname(hostName, 128))
  813.         {
  814.             if(hostent* host = gethostbyname(hostName))
  815.             {
  816.                 std::stringstream s;
  817.                 for(uint8_t** addr = (uint8_t**)host->h_addr_list; addr[0]; addr++)
  818.                 {
  819.                     uint32_t resolved = swap_uint32(*(uint32_t*)(*addr));
  820.                     if(m_ip.to_v4().to_ulong() == resolved)
  821.                         continue;
  822.  
  823.                     ipList.push_back(boost::asio::ip::address_v4(resolved));
  824.                     serverIps.push_front(std::make_pair(*(uint32_t*)(*addr), 0x0000FFFF));
  825.  
  826.                     s << (int32_t)(addr[0][0]) << "." << (int32_t)(addr[0][1]) << "."
  827.                         << (int32_t)(addr[0][2]) << "." << (int32_t)(addr[0][3]) << "\t";
  828.                 }
  829.  
  830.                 if(s.str().size())
  831.                     std::clog << "> Local IP address(es): " << s.str() << std::endl;
  832.             }
  833.         }
  834.  
  835.         if(m_ip.to_v4().to_ulong() != LOCALHOST)
  836.             ipList.push_back(boost::asio::ip::address_v4(LOCALHOST));
  837.     }
  838.     else if(ipList.size() < 2)
  839.         startupErrorMessage("Unable to bind any IP address! You may want to disable \"bindOnlyGlobalAddress\" setting in config.lua");
  840.  
  841.     services->add<ProtocolStatus>(g_config.getNumber(ConfigManager::STATUS_PORT), ipList);
  842.     services->add<ProtocolManager>(g_config.getNumber(ConfigManager::MANAGER_PORT), ipList);
  843.     #ifdef __OTADMIN__
  844.     services->add<ProtocolAdmin>(g_config.getNumber(ConfigManager::ADMIN_PORT), ipList);
  845.     #endif
  846.  
  847.     //services->add<ProtocolHTTP>(8080, ipList);
  848.     if(
  849. #ifdef __LOGIN_SERVER__
  850.     true
  851. #else
  852.     !g_config.getBool(ConfigManager::LOGIN_ONLY_LOGINSERVER)
  853. #endif
  854.     )
  855.     {
  856.         services->add<ProtocolLogin>(g_config.getNumber(ConfigManager::LOGIN_PORT), ipList);
  857.         services->add<ProtocolOldLogin>(g_config.getNumber(ConfigManager::LOGIN_PORT), ipList);
  858.     }
  859.  
  860.     services->add<ProtocolOldGame>(g_config.getNumber(ConfigManager::LOGIN_PORT), ipList);
  861.     IntegerVec games = vectorAtoi(explodeString(g_config.getString(ConfigManager::GAME_PORT), ","));
  862.     for(IntegerVec::const_iterator it = games.begin(); it != games.end(); ++it)
  863.     {
  864.         services->add<ProtocolGame>(*it, ipList);
  865.         break; // CRITICAL: more ports are causing crashes- either find the issue or drop the "feature"
  866.     }
  867.  
  868.     std::clog << "> Bound ports: ";
  869.     std::list<uint16_t> ports = services->getPorts();
  870.     for(std::list<uint16_t>::iterator it = ports.begin(); it != ports.end(); ++it)
  871.         std::clog << (*it) << "\t";
  872.  
  873.     std::clog << std::endl << ">> Everything smells good, server is starting up..." << std::endl;
  874.     g_game.start(services);
  875.     g_game.setGameState(g_config.getBool(ConfigManager::START_CLOSED) ? GAMESTATE_CLOSED : GAMESTATE_NORMAL);
  876.     g_loaderSignal.notify_all();
  877. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement