00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <cassert>
00023 #include <sstream>
00024 #include <list>
00025
00026 #include "account-server/serverhandler.hpp"
00027
00028 #include "account-server/accountclient.hpp"
00029 #include "account-server/accounthandler.hpp"
00030 #include "account-server/character.hpp"
00031 #include "account-server/dalstorage.hpp"
00032 #include "chat-server/post.hpp"
00033 #include "common/transaction.hpp"
00034 #include "net/connectionhandler.hpp"
00035 #include "net/messageout.hpp"
00036 #include "net/netcomputer.hpp"
00037 #include "serialize/characterdata.hpp"
00038 #include "utils/logger.h"
00039 #include "utils/tokendispenser.hpp"
00040
00041 struct MapStatistics
00042 {
00043 std::vector< int > players;
00044 unsigned short nbThings;
00045 unsigned short nbMonsters;
00046 };
00047
00048 typedef std::map< unsigned short, MapStatistics > ServerStatistics;
00049
00053 struct GameServer: NetComputer
00054 {
00055 GameServer(ENetPeer *peer): NetComputer(peer), port(0) {}
00056
00057 std::string address;
00058 NetComputer *server;
00059 ServerStatistics maps;
00060 short port;
00061 };
00062
00063 static GameServer *getGameServerFromMap(int);
00064
00068 class ServerHandler: public ConnectionHandler
00069 {
00070 friend GameServer *getGameServerFromMap(int);
00071 friend void GameServerHandler::dumpStatistics(std::ostream &);
00072
00073 protected:
00077 void processMessage(NetComputer *computer, MessageIn &message);
00078
00083 NetComputer *computerConnected(ENetPeer *peer);
00084
00088 void computerDisconnected(NetComputer *comp);
00089 };
00090
00091 static ServerHandler *serverHandler;
00092
00093 bool GameServerHandler::initialize(int port)
00094 {
00095 serverHandler = new ServerHandler;
00096 LOG_INFO("Game server handler started:");
00097 return serverHandler->startListen(port);
00098 }
00099
00100 void GameServerHandler::deinitialize()
00101 {
00102 serverHandler->stopListen();
00103 delete serverHandler;
00104 }
00105
00106 void GameServerHandler::process()
00107 {
00108 serverHandler->process(50);
00109 }
00110
00111 NetComputer *ServerHandler::computerConnected(ENetPeer *peer)
00112 {
00113 return new GameServer(peer);
00114 }
00115
00116 void ServerHandler::computerDisconnected(NetComputer *comp)
00117 {
00118 delete comp;
00119 }
00120
00121 static GameServer *getGameServerFromMap(int mapId)
00122 {
00123 for (ServerHandler::NetComputers::const_iterator
00124 i = serverHandler->clients.begin(),
00125 i_end = serverHandler->clients.end(); i != i_end; ++i)
00126 {
00127 GameServer *server = static_cast< GameServer * >(*i);
00128 ServerStatistics::const_iterator i = server->maps.find(mapId);
00129 if (i == server->maps.end()) continue;
00130 return server;
00131 }
00132 return NULL;
00133 }
00134
00135 bool GameServerHandler::getGameServerFromMap
00136 (int mapId, std::string &address, int &port)
00137 {
00138 if (GameServer *s = ::getGameServerFromMap(mapId))
00139 {
00140 address = s->address;
00141 port = s->port;
00142 return true;
00143 }
00144 return false;
00145 }
00146
00147 static void registerGameClient(GameServer *s, const std::string &token,
00148 Character *ptr)
00149 {
00150 MessageOut msg(AGMSG_PLAYER_ENTER);
00151 msg.writeString(token, MAGIC_TOKEN_LENGTH);
00152 msg.writeLong(ptr->getDatabaseID());
00153 msg.writeString(ptr->getName());
00154 serializeCharacterData(*ptr, msg);
00155 s->send(msg);
00156 }
00157
00158 void GameServerHandler::registerClient(const std::string &token,
00159 Character *ptr)
00160 {
00161 GameServer *s = ::getGameServerFromMap(ptr->getMapId());
00162 assert(s);
00163 registerGameClient(s, token, ptr);
00164 }
00165
00166 void ServerHandler::processMessage(NetComputer *comp, MessageIn &msg)
00167 {
00168 MessageOut result;
00169 GameServer *server = static_cast< GameServer * >(comp);
00170
00171 switch (msg.getId())
00172 {
00173 case GAMSG_REGISTER:
00174 {
00175 LOG_DEBUG("GAMSG_REGISTER");
00176
00177 server->address = msg.readString();
00178 server->port = msg.readShort();
00179
00180
00181 unsigned int dbversion = msg.readLong();
00182 LOG_INFO("Game server uses itemsdatabase with version " << dbversion);
00183
00184 LOG_DEBUG("AGMSG_REGISTER_RESPONSE");
00185 MessageOut outMsg(AGMSG_REGISTER_RESPONSE);
00186 if (dbversion == storage->getItemDatabaseVersion())
00187 {
00188 LOG_DEBUG("Item databases between account server and "
00189 "gameserver are in sync");
00190 outMsg.writeShort(DATA_VERSION_OK);
00191 }
00192 else
00193 {
00194 LOG_DEBUG("Item database of game server has a wrong version");
00195 outMsg.writeShort(DATA_VERSION_OUTDATED);
00196 }
00197 comp->send(outMsg);
00198
00199 LOG_INFO("Game server " << server->address << ':' << server->port
00200 << " wants to register " << (msg.getUnreadLength() / 2)
00201 << " maps.");
00202
00203 while (msg.getUnreadLength())
00204 {
00205 int id = msg.readShort();
00206 LOG_INFO("Registering map " << id << '.');
00207 if (GameServer *s = getGameServerFromMap(id))
00208 {
00209 LOG_ERROR("Server Handler: map is already registered by "
00210 << s->address << ':' << s->port << '.');
00211 }
00212 else
00213 {
00214 MessageOut outMsg(AGMSG_ACTIVE_MAP);
00215 outMsg.writeShort(id);
00216 comp->send(outMsg);
00217 MapStatistics &m = server->maps[id];
00218 m.nbThings = 0;
00219 m.nbMonsters = 0;
00220 }
00221 }
00222 } break;
00223
00224 case GAMSG_PLAYER_DATA:
00225 {
00226 LOG_DEBUG("GAMSG_PLAYER_DATA");
00227 int id = msg.readLong();
00228 if (Character *ptr = storage->getCharacter(id, NULL))
00229 {
00230 deserializeCharacterData(*ptr, msg);
00231 if (!storage->updateCharacter(ptr))
00232 {
00233 LOG_ERROR("Failed to update character "
00234 << id << '.');
00235 }
00236 delete ptr;
00237 }
00238 else
00239 {
00240 LOG_ERROR("Received data for non-existing character "
00241 << id << '.');
00242 }
00243 } break;
00244
00245 case GAMSG_PLAYER_SYNC:
00246 {
00247 LOG_DEBUG("GAMSG_PLAYER_SYNC");
00248 GameServerHandler::syncDatabase(msg);
00249 } break;
00250
00251 case GAMSG_REDIRECT:
00252 {
00253 LOG_DEBUG("GAMSG_REDIRECT");
00254 int id = msg.readLong();
00255 std::string magic_token(utils::getMagicToken());
00256 if (Character *ptr = storage->getCharacter(id, NULL))
00257 {
00258 int mapId = ptr->getMapId();
00259 if (GameServer *s = getGameServerFromMap(mapId))
00260 {
00261 registerGameClient(s, magic_token, ptr);
00262 result.writeShort(AGMSG_REDIRECT_RESPONSE);
00263 result.writeLong(id);
00264 result.writeString(magic_token, MAGIC_TOKEN_LENGTH);
00265 result.writeString(s->address);
00266 result.writeShort(s->port);
00267 }
00268 else
00269 {
00270 LOG_ERROR("Server Change: No game server for map " <<
00271 mapId << '.');
00272 }
00273 delete ptr;
00274 }
00275 else
00276 {
00277 LOG_ERROR("Received data for non-existing character "
00278 << id << '.');
00279 }
00280 } break;
00281
00282 case GAMSG_PLAYER_RECONNECT:
00283 {
00284 LOG_DEBUG("GAMSG_PLAYER_RECONNECT");
00285 int id = msg.readLong();
00286 std::string magic_token = msg.readString(MAGIC_TOKEN_LENGTH);
00287
00288 if (Character *ptr = storage->getCharacter(id, NULL))
00289 {
00290 int accountID = ptr->getAccountID();
00291 AccountClientHandler::prepareReconnect(magic_token, accountID);
00292 delete ptr;
00293 }
00294 else
00295 {
00296 LOG_ERROR("Received data for non-existing character "
00297 << id << '.');
00298 }
00299 } break;
00300
00301 case GAMSG_GET_QUEST:
00302 {
00303 int id = msg.readLong();
00304 std::string name = msg.readString();
00305 std::string value = storage->getQuestVar(id, name);
00306 result.writeShort(AGMSG_GET_QUEST_RESPONSE);
00307 result.writeLong(id);
00308 result.writeString(name);
00309 result.writeString(value);
00310 } break;
00311
00312 case GAMSG_SET_QUEST:
00313 {
00314 int id = msg.readLong();
00315 std::string name = msg.readString();
00316 std::string value = msg.readString();
00317 storage->setQuestVar(id, name, value);
00318 } break;
00319
00320 case GAMSG_BAN_PLAYER:
00321 {
00322 int id = msg.readLong();
00323 int duration = msg.readShort();
00324 storage->banCharacter(id, duration);
00325 } break;
00326
00327 case GAMSG_CHANGE_PLAYER_LEVEL:
00328 {
00329 int id = msg.readLong();
00330 int level = msg.readShort();
00331 storage->setPlayerLevel(id, level);
00332 } break;
00333
00334 case GAMSG_CHANGE_ACCOUNT_LEVEL:
00335 {
00336 int id = msg.readLong();
00337 int level = msg.readShort();
00338
00339
00340 Character *c = storage->getCharacter(id, NULL);
00341 if (c)
00342 {
00343 storage->setAccountLevel(c->getAccountID(), level);
00344 }
00345 } break;
00346
00347 case GAMSG_STATISTICS:
00348 {
00349 while (msg.getUnreadLength())
00350 {
00351 int mapId = msg.readShort();
00352 ServerStatistics::iterator i = server->maps.find(mapId);
00353 if (i == server->maps.end())
00354 {
00355 LOG_ERROR("Server " << server->address << ':'
00356 << server->port << " should not be sending stati"
00357 "stics for map " << mapId << '.');
00358
00359 break;
00360 }
00361 MapStatistics &m = i->second;
00362 m.nbThings = msg.readShort();
00363 m.nbMonsters = msg.readShort();
00364 int nb = msg.readShort();
00365 m.players.resize(nb);
00366 for (int j = 0; j < nb; ++j)
00367 {
00368 m.players[j] = msg.readLong();
00369 }
00370 }
00371 } break;
00372
00373 case GCMSG_REQUEST_POST:
00374 {
00375
00376 LOG_DEBUG("GCMSG_REQUEST_POST");
00377 result.writeShort(CGMSG_POST_RESPONSE);
00378
00379
00380 int characterId = msg.readLong();
00381
00382
00383 result.writeLong(characterId);
00384
00385
00386 Character *ptr = storage->getCharacter(characterId, NULL);
00387 if (!ptr)
00388 {
00389
00390 LOG_ERROR("Error finding character id for post");
00391 break;
00392 }
00393
00394
00395 Post *post = postalManager->getPost(ptr);
00396
00397
00398 if (post)
00399 {
00400 for (unsigned int i = 0; i < post->getNumberOfLetters(); ++i)
00401 {
00402
00403
00404 Letter *letter = post->getLetter(i);
00405 result.writeString(letter->getSender()->getName());
00406 result.writeString(letter->getContents());
00407 std::vector<InventoryItem> items = letter->getAttachments();
00408 for (unsigned int j = 0; j < items.size(); ++j)
00409 {
00410 result.writeShort(items[j].itemId);
00411 result.writeShort(items[j].amount);
00412 }
00413 }
00414
00415
00416 postalManager->clearPost(ptr);
00417 }
00418
00419 } break;
00420
00421 case GCMSG_STORE_POST:
00422 {
00423
00424 LOG_DEBUG("GCMSG_STORE_POST");
00425 result.writeShort(CGMSG_STORE_POST_RESPONSE);
00426
00427
00428 int senderId = msg.readLong();
00429 std::string receiverName = msg.readString();
00430
00431
00432 result.writeLong(senderId);
00433
00434
00435 Character *sender = storage->getCharacter(senderId, NULL);
00436 Character *receiver = storage->getCharacter(receiverName);
00437 if (!sender || !receiver)
00438 {
00439
00440 LOG_ERROR("Error finding character id for post");
00441 result.writeByte(ERRMSG_INVALID_ARGUMENT);
00442 break;
00443 }
00444
00445
00446 std::string contents = msg.readString();
00447
00448 std::vector< std::pair<int, int> > items;
00449 while (msg.getUnreadLength())
00450 {
00451 items.push_back(std::pair<int, int>(msg.readShort(), msg.readShort()));
00452 }
00453
00454
00455 LOG_DEBUG("Creating letter");
00456 Letter *letter = new Letter(0, sender, receiver);
00457 letter->addText(contents);
00458 for (unsigned int i = 0; i < items.size(); ++i)
00459 {
00460 InventoryItem item;
00461 item.itemId = items[i].first;
00462 item.amount = items[i].second;
00463 letter->addAttachment(item);
00464 }
00465 postalManager->addLetter(letter);
00466
00467 result.writeByte(ERRMSG_OK);
00468 } break;
00469
00470 case GAMSG_TRANSACTION:
00471 {
00472 LOG_DEBUG("TRANSACTION");
00473 int id = msg.readLong();
00474 int action = msg.readLong();
00475 std::string message = msg.readString();
00476
00477 Transaction trans;
00478 trans.mCharacterId = id;
00479 trans.mAction = action;
00480 trans.mMessage = message;
00481 storage->addTransaction(trans);
00482 } break;
00483
00484 default:
00485 LOG_WARN("ServerHandler::processMessage, Invalid message type: "
00486 << msg.getId());
00487 result.writeShort(XXMSG_INVALID);
00488 break;
00489 }
00490
00491
00492 if (result.getLength() > 0)
00493 comp->send(result);
00494 }
00495
00496 void GameServerHandler::dumpStatistics(std::ostream &os)
00497 {
00498 for (ServerHandler::NetComputers::const_iterator
00499 i = serverHandler->clients.begin(),
00500 i_end = serverHandler->clients.end(); i != i_end; ++i)
00501 {
00502 GameServer *server = static_cast< GameServer * >(*i);
00503 if (!server->port) continue;
00504 os << "<gameserver address=\"" << server->address << "\" port=\""
00505 << server->port << "\">\n";
00506
00507 for (ServerStatistics::const_iterator j = server->maps.begin(),
00508 j_end = server->maps.end(); j != j_end; ++j)
00509 {
00510 const MapStatistics &m = j->second;
00511 os << "<map id=\"" << j->first << "\" nb_things=\"" << m.nbThings
00512 << "\" nb_monsters=\"" << m.nbMonsters << "\">\n";
00513 for (std::vector< int >::const_iterator k = m.players.begin(),
00514 k_end = m.players.end(); k != k_end; ++k)
00515 {
00516 os << "<character id=\"" << *k << "\"/>\n";
00517 }
00518 os << "</map>\n";
00519 }
00520 os << "</gameserver>\n";
00521 }
00522 }
00523
00524 void GameServerHandler::sendPartyChange(Character *ptr, int partyId)
00525 {
00526 GameServer *s = ::getGameServerFromMap(ptr->getMapId());
00527 if (s)
00528 {
00529 MessageOut msg(CGMSG_CHANGED_PARTY);
00530 msg.writeLong(ptr->getDatabaseID());
00531 msg.writeLong(partyId);
00532 s->send(msg);
00533 }
00534 }
00535
00536 void GameServerHandler::syncDatabase(MessageIn &msg)
00537 {
00538 int msgType = msg.readByte();
00539 while( msgType != SYNC_END_OF_BUFFER )
00540 {
00541 switch (msgType)
00542 {
00543 case SYNC_CHARACTER_POINTS:
00544 {
00545 LOG_DEBUG("received SYNC_CHARACTER_POINTS");
00546 int CharId = msg.readLong();
00547 int CharPoints = msg.readLong();
00548 int CorrPoints = msg.readLong();
00549 int AttribId = msg.readByte();
00550 int AttribValue = msg.readLong();
00551 storage->updateCharacterPoints(CharId, CharPoints, CorrPoints,
00552 AttribId, AttribValue);
00553 } break;
00554
00555 case SYNC_CHARACTER_SKILL:
00556 {
00557 LOG_DEBUG("received SYNC_CHARACTER_SKILL");
00558 int CharId = msg.readLong();
00559 int SkillId = msg.readByte();
00560 int SkillValue = msg.readLong();
00561 storage->updateExperience(CharId, SkillId, SkillValue);
00562 } break;
00563
00564 case SYNC_ONLINE_STATUS:
00565 {
00566 LOG_DEBUG("received SYNC_ONLINE_STATUS");
00567 int CharId = msg.readLong();
00568 bool online;
00569 msg.readByte() == 0x00 ? online = false : online = true;
00570 storage->setOnlineStatus(CharId, online);
00571 }
00572 }
00573
00574
00575 msgType = msg.readByte();
00576 }
00577 }