00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021 #include <cstdlib>
00022 #include <getopt.h>
00023 #include <iostream>
00024 #include <signal.h>
00025 #include <physfs.h>
00026 #include <enet/enet.h>
00027
00028 #ifdef HAVE_CONFIG_H
00029 #include "../config.h"
00030 #endif
00031
00032 #include "common/configuration.hpp"
00033 #include "game-server/accountconnection.hpp"
00034 #include "game-server/gamehandler.hpp"
00035 #include "game-server/itemmanager.hpp"
00036 #include "game-server/mapmanager.hpp"
00037 #include "game-server/monstermanager.hpp"
00038 #include "game-server/postman.hpp"
00039 #include "game-server/resourcemanager.hpp"
00040 #include "game-server/state.hpp"
00041 #include "net/bandwidth.hpp"
00042 #include "net/connectionhandler.hpp"
00043 #include "net/messageout.hpp"
00044 #include "utils/logger.h"
00045 #include "utils/processorutils.hpp"
00046 #include "utils/stringfilter.h"
00047 #include "utils/timer.h"
00048 #include "utils/mathutils.h"
00049
00050
00051 #define DEFAULT_LOG_FILE "tmwserv-game.log"
00052 #define DEFAULT_CONFIG_FILE "tmwserv.xml"
00053 #define DEFAULT_ITEMSDB_FILE "items.xml"
00054 #define DEFAULT_MAPSDB_FILE "maps.xml"
00055 #define DEFAULT_MONSTERSDB_FILE "monsters.xml"
00056
00057 utils::Timer worldTimer(100, false);
00058 int worldTime = 0;
00059 bool running = true;
00061 utils::StringFilter *stringFilter;
00064 GameHandler *gameHandler;
00065
00067 AccountConnection *accountHandler;
00068
00070 PostMan *postMan;
00071
00073 BandwidthMonitor *gBandwidth;
00074
00076 void closeGracefully(int)
00077 {
00078 running = false;
00079 }
00080
00084 void initialize()
00085 {
00086
00087 signal(SIGSEGV, SIG_DFL);
00088
00089
00090 #if (defined __USE_UNIX98 || defined __FreeBSD__)
00091 signal(SIGQUIT, closeGracefully);
00092 #endif
00093 signal(SIGINT, closeGracefully);
00094
00095
00096
00097
00098
00099
00100 #if defined CONFIG_FILE
00101 std::string configPath = CONFIG_FILE;
00102 #else
00103
00104 #if (defined __USE_UNIX98 || defined __FreeBSD__)
00105 std::string configPath = getenv("HOME");
00106 configPath += "/.";
00107 configPath += DEFAULT_CONFIG_FILE;
00108 #else // Win32, ...
00109 std::string configPath = DEFAULT_CONFIG_FILE;
00110 #endif
00111
00112 #endif // defined CONFIG_FILE
00113
00114
00115 #if defined LOG_FILE
00116 std::string logPath = LOG_FILE;
00117 #else
00118
00119 #if (defined __USE_UNIX98 || defined __FreeBSD__)
00120 std::string logPath = getenv("HOME");
00121 logPath += "/.";
00122 logPath += DEFAULT_LOG_FILE;
00123 #else // Win32, ...
00124 std::string logPath = DEFAULT_LOG_FILE;
00125 #endif
00126
00127 #endif // defined LOG_FILE
00128
00129
00130 PHYSFS_init("");
00131
00132
00133 using namespace utils;
00134 Logger::setLogFile(logPath);
00135
00136
00137 Logger::setTeeMode(true);
00138
00139 Configuration::initialize(configPath);
00140 LOG_INFO("Using config file: " << configPath);
00141 LOG_INFO("Using log file: " << logPath);
00142
00143
00144
00145 stringFilter = new StringFilter;
00146
00147 ResourceManager::initialize();
00148 MapManager::initialize(DEFAULT_MAPSDB_FILE);
00149 ItemManager::initialize(DEFAULT_ITEMSDB_FILE);
00150 MonsterManager::initialize(DEFAULT_MONSTERSDB_FILE);
00151
00152
00153
00154
00155 gameHandler = new GameHandler;
00156 accountHandler = new AccountConnection;
00157 postMan = new PostMan;
00158 gBandwidth = new BandwidthMonitor;
00159
00160
00161 if (enet_initialize() != 0) {
00162 LOG_FATAL("An error occurred while initializing ENet");
00163 exit(2);
00164 }
00165
00166
00167 atexit(enet_deinitialize);
00168
00169
00170 utils::math::init();
00171
00172
00173 utils::processor::init();
00174
00175
00176 std::srand( time(NULL) );
00177 }
00178
00179
00183 void deinitialize()
00184 {
00185
00186 Configuration::deinitialize();
00187
00188
00189 worldTimer.stop();
00190
00191
00192 delete gameHandler;
00193 delete accountHandler;
00194 delete postMan;
00195 delete gBandwidth;
00196
00197
00198 delete stringFilter;
00199 MonsterManager::deinitialize();
00200 ItemManager::deinitialize();
00201 MapManager::deinitialize();
00202
00203 PHYSFS_deinit();
00204 }
00205
00206
00210 void printHelp()
00211 {
00212 std::cout << "tmwserv" << std::endl << std::endl
00213 << "Options: " << std::endl
00214 << " -h --help : Display this help" << std::endl
00215 << " --verbosity <n> : Set the verbosity level" << std::endl
00216 << " --port <n> : Set the default port to listen on" << std::endl;
00217 exit(0);
00218 }
00219
00223 void parseOptions(int argc, char *argv[])
00224 {
00225 const char *optstring = "h";
00226
00227 const struct option long_options[] = {
00228 { "help", no_argument, 0, 'h' },
00229 { "verbosity", required_argument, 0, 'v' },
00230 { "port", required_argument, 0, 'p' },
00231 { 0 }
00232 };
00233
00234 while (optind < argc) {
00235 int result = getopt_long(argc, argv, optstring, long_options, NULL);
00236
00237 if (result == -1) {
00238 break;
00239 }
00240
00241 switch (result) {
00242 default:
00243 case 'h':
00244
00245 printHelp();
00246 break;
00247 case 'v':
00248
00249 unsigned short verbosityLevel;
00250 verbosityLevel = atoi(optarg);
00251 utils::Logger::setVerbosity(utils::Logger::Level(verbosityLevel));
00252 LOG_INFO("Setting log verbosity level to " << verbosityLevel);
00253 break;
00254 case 'p':
00255
00256 unsigned short portToListenOn;
00257 portToListenOn = atoi(optarg);
00258 Configuration::setValue("net_gameServerPort", portToListenOn);
00259 LOG_INFO("Setting default port to " << portToListenOn);
00260 break;
00261 }
00262 }
00263 }
00264
00265
00269 int main(int argc, char *argv[])
00270 {
00271 int elapsedWorldTicks;
00272 #ifdef PACKAGE_VERSION
00273 LOG_INFO("The Mana World Game Server v" << PACKAGE_VERSION);
00274 #endif
00275
00276
00277 parseOptions(argc, argv);
00278
00279
00280 initialize();
00281
00282
00283 accountHandler->start();
00284
00285 int gameServerPort =
00286 Configuration::getValue("net_gameServerPort", DEFAULT_SERVER_PORT + 3);
00287
00288 if (!gameHandler->startListen(gameServerPort))
00289 {
00290 LOG_FATAL("Unable to create an ENet server host.");
00291 return 3;
00292 }
00293
00294
00295 worldTimer.start();
00296
00297 while (running) {
00298 elapsedWorldTicks = worldTimer.poll();
00299 if (elapsedWorldTicks > 0)
00300 {
00301 worldTime += elapsedWorldTicks;
00302
00303 if (elapsedWorldTicks > 1)
00304 {
00305 LOG_WARN("Not enough time to calculate "<< elapsedWorldTicks -1
00306 << " World Tick(s) - skipping. Please buy a faster "
00307 "machine ;-)");
00308 };
00309
00310
00311 if (worldTime % 100 == 0) {
00312 LOG_INFO("World time: " << worldTime);
00313
00314 }
00315
00316 if (accountHandler->isConnected())
00317 {
00318
00319 accountHandler->process();
00320
00321 if (worldTime % 100 == 0) {
00322 accountHandler->syncChanges(true);
00323
00324 }
00325
00326 if (worldTime % 300 == 0)
00327 {
00328 accountHandler->sendStatistics();
00329 LOG_INFO("Total Account Output: " << gBandwidth->totalInterServerOut() << " Bytes");
00330 LOG_INFO("Total Account Input: " << gBandwidth->totalInterServerIn() << " Bytes");
00331 LOG_INFO("Total Client Output: " << gBandwidth->totalClientOut() << " Bytes");
00332 LOG_INFO("Total Client Input: " << gBandwidth->totalClientIn() << " Bytes");
00333 }
00334 }
00335 else
00336 {
00337 if (worldTime % 200 == 0)
00338 {
00339 accountHandler->start();
00340 }
00341 }
00342 gameHandler->process();
00343
00344 GameState::update(worldTime);
00345
00346 gameHandler->flush();
00347 }
00348 else
00349 {
00350 worldTimer.sleep();
00351 }
00352 }
00353
00354 LOG_INFO("Received: Quit signal, closing down...");
00355 gameHandler->stopListen();
00356 accountHandler->stop();
00357 deinitialize();
00358 }