void ServerHandler::processMessage(NetComputer *comp, MessageIn &msg) { MessageOut result; GameServer *server = static_cast<GameServer *>(comp); switch (msg.getId()) { case GAMSG_REGISTER: { LOG_DEBUG("GAMSG_REGISTER"); // TODO: check the credentials of the game server server->address = msg.readString(); server->port = msg.readInt16(); const std::string password = msg.readString(); // checks the version of the remote item database with our local copy unsigned int dbversion = msg.readInt32(); LOG_INFO("Game server uses itemsdatabase with version " << dbversion); LOG_DEBUG("AGMSG_REGISTER_RESPONSE"); MessageOut outMsg(AGMSG_REGISTER_RESPONSE); if (dbversion == storage->getItemDatabaseVersion()) { LOG_DEBUG("Item databases between account server and " "gameserver are in sync"); outMsg.writeInt16(DATA_VERSION_OK); } else { LOG_DEBUG("Item database of game server has a wrong version"); outMsg.writeInt16(DATA_VERSION_OUTDATED); } if (password == Configuration::getValue("net_password", "changeMe")) { outMsg.writeInt16(PASSWORD_OK); comp->send(outMsg); // transmit global world state variables std::map<std::string, std::string> variables; variables = storage->getAllWorldStateVars(0); for (std::map<std::string, std::string>::iterator i = variables.begin(); i != variables.end(); i++) { outMsg.writeString(i->first); outMsg.writeString(i->second); } } else { LOG_INFO("The password given by " << server->address << ':' << server->port << " was bad."); outMsg.writeInt16(PASSWORD_BAD); comp->disconnect(outMsg); break; } LOG_INFO("Game server " << server->address << ':' << server->port << " wants to register " << (msg.getUnreadLength() / 2) << " maps."); while (msg.getUnreadLength()) { int id = msg.readInt16(); LOG_INFO("Registering map " << id << '.'); if (GameServer *s = getGameServerFromMap(id)) { LOG_ERROR("Server Handler: map is already registered by " << s->address << ':' << s->port << '.'); } else { MessageOut outMsg(AGMSG_ACTIVE_MAP); outMsg.writeInt16(id); std::map<std::string, std::string> variables; variables = storage->getAllWorldStateVars(id); for (std::map<std::string, std::string>::iterator i = variables.begin(); i != variables.end(); i++) { outMsg.writeString(i->first); outMsg.writeString(i->second); } comp->send(outMsg); MapStatistics &m = server->maps[id]; m.nbThings = 0; m.nbMonsters = 0; } } } break; case GAMSG_PLAYER_DATA: { LOG_DEBUG("GAMSG_PLAYER_DATA"); int id = msg.readInt32(); if (Character *ptr = storage->getCharacter(id, NULL)) { deserializeCharacterData(*ptr, msg); if (!storage->updateCharacter(ptr)) { LOG_ERROR("Failed to update character " << id << '.'); } delete ptr; } else { LOG_ERROR("Received data for non-existing character " << id << '.'); } } break; case GAMSG_PLAYER_SYNC: { LOG_DEBUG("GAMSG_PLAYER_SYNC"); GameServerHandler::syncDatabase(msg); } break; case GAMSG_REDIRECT: { LOG_DEBUG("GAMSG_REDIRECT"); int id = msg.readInt32(); std::string magic_token(utils::getMagicToken()); if (Character *ptr = storage->getCharacter(id, NULL)) { int mapId = ptr->getMapId(); if (GameServer *s = getGameServerFromMap(mapId)) { registerGameClient(s, magic_token, ptr); result.writeInt16(AGMSG_REDIRECT_RESPONSE); result.writeInt32(id); result.writeString(magic_token, MAGIC_TOKEN_LENGTH); result.writeString(s->address); result.writeInt16(s->port); } else { LOG_ERROR("Server Change: No game server for map " << mapId << '.'); } delete ptr; } else { LOG_ERROR("Received data for non-existing character " << id << '.'); } } break; case GAMSG_PLAYER_RECONNECT: { LOG_DEBUG("GAMSG_PLAYER_RECONNECT"); int id = msg.readInt32(); std::string magic_token = msg.readString(MAGIC_TOKEN_LENGTH); if (Character *ptr = storage->getCharacter(id, NULL)) { int accountID = ptr->getAccountID(); AccountClientHandler::prepareReconnect(magic_token, accountID); delete ptr; } else { LOG_ERROR("Received data for non-existing character " << id << '.'); } } break; case GAMSG_GET_VAR_CHR: { int id = msg.readInt32(); std::string name = msg.readString(); std::string value = storage->getQuestVar(id, name); result.writeInt16(AGMSG_GET_VAR_CHR_RESPONSE); result.writeInt32(id); result.writeString(name); result.writeString(value); } break; case GAMSG_SET_VAR_CHR: { int id = msg.readInt32(); std::string name = msg.readString(); std::string value = msg.readString(); storage->setQuestVar(id, name, value); } break; case GAMSG_SET_VAR_WORLD: { std::string name = msg.readString(); std::string value = msg.readString(); // save the new value to the database storage->setWorldStateVar(name, value); // relay the new value to all gameservers for (ServerHandler::NetComputers::iterator i = clients.begin(); i != clients.end(); i++) { MessageOut varUpdateMessage(AGMSG_SET_VAR_WORLD); varUpdateMessage.writeString(name); varUpdateMessage.writeString(value); (*i)->send(varUpdateMessage); } } break; case GAMSG_SET_VAR_MAP: { int mapid = msg.readInt32(); std::string name = msg.readString(); std::string value = msg.readString(); storage->setWorldStateVar(name, mapid, value); } break; case GAMSG_BAN_PLAYER: { int id = msg.readInt32(); int duration = msg.readInt32(); storage->banCharacter(id, duration); } break; case GAMSG_CHANGE_PLAYER_LEVEL: { int id = msg.readInt32(); int level = msg.readInt16(); storage->setPlayerLevel(id, level); } break; case GAMSG_CHANGE_ACCOUNT_LEVEL: { int id = msg.readInt32(); int level = msg.readInt16(); // get the character so we can get the account id Character *c = storage->getCharacter(id, NULL); if (c) { storage->setAccountLevel(c->getAccountID(), level); } } break; case GAMSG_STATISTICS: { while (msg.getUnreadLength()) { int mapId = msg.readInt16(); ServerStatistics::iterator i = server->maps.find(mapId); if (i == server->maps.end()) { LOG_ERROR("Server " << server->address << ':' << server->port << " should not be sending stati" "stics for map " << mapId << '.'); // Skip remaining data. break; } MapStatistics &m = i->second; m.nbThings = msg.readInt16(); m.nbMonsters = msg.readInt16(); int nb = msg.readInt16(); m.players.resize(nb); for (int j = 0; j < nb; ++j) { m.players[j] = msg.readInt32(); } } } break; case GCMSG_REQUEST_POST: { // Retrieve the post for user LOG_DEBUG("GCMSG_REQUEST_POST"); result.writeInt16(CGMSG_POST_RESPONSE); // get the character id int characterId = msg.readInt32(); // send the character id of sender result.writeInt32(characterId); // get the character based on the id Character *ptr = storage->getCharacter(characterId, NULL); if (!ptr) { // Invalid character LOG_ERROR("Error finding character id for post"); break; } // get the post for that character Post *post = postalManager->getPost(ptr); // send the post if valid if (post) { for (unsigned int i = 0; i < post->getNumberOfLetters(); ++i) { // get each letter, send the sender's name, // the contents and any attachments Letter *letter = post->getLetter(i); result.writeString(letter->getSender()->getName()); result.writeString(letter->getContents()); std::vector<InventoryItem> items = letter->getAttachments(); for (unsigned int j = 0; j < items.size(); ++j) { result.writeInt16(items[j].itemId); result.writeInt16(items[j].amount); } } // clean up postalManager->clearPost(ptr); } } break; case GCMSG_STORE_POST: { // Store the letter for the user LOG_DEBUG("GCMSG_STORE_POST"); result.writeInt16(CGMSG_STORE_POST_RESPONSE); // get the sender and receiver int senderId = msg.readInt32(); std::string receiverName = msg.readString(); // for sending it back result.writeInt32(senderId); // get their characters Character *sender = storage->getCharacter(senderId, NULL); Character *receiver = storage->getCharacter(receiverName); if (!sender || !receiver) { // Invalid character LOG_ERROR("Error finding character id for post"); result.writeInt8(ERRMSG_INVALID_ARGUMENT); break; } // get the letter contents std::string contents = msg.readString(); std::vector< std::pair<int, int> > items; while (msg.getUnreadLength()) { items.push_back(std::pair<int, int>(msg.readInt16(), msg.readInt16())); } // save the letter LOG_DEBUG("Creating letter"); Letter *letter = new Letter(0, sender, receiver); letter->addText(contents); for (unsigned int i = 0; i < items.size(); ++i) { InventoryItem item; item.itemId = items[i].first; item.amount = items[i].second; letter->addAttachment(item); } postalManager->addLetter(letter); result.writeInt8(ERRMSG_OK); } break; case GAMSG_TRANSACTION: { LOG_DEBUG("TRANSACTION"); int id = msg.readInt32(); int action = msg.readInt32(); std::string message = msg.readString(); Transaction trans; trans.mCharacterId = id; trans.mAction = action; trans.mMessage = message; storage->addTransaction(trans); } break; case GCMSG_PARTY_INVITE: chatHandler->handlePartyInvite(msg); break; default: LOG_WARN("ServerHandler::processMessage, Invalid message type: " << msg.getId()); result.writeInt16(XXMSG_INVALID); break; } // return result if (result.getLength() > 0) comp->send(result); }
void CharacterComponent::serialize(Entity &entity, MessageOut &msg) { auto *beingComponent = entity.getComponent<BeingComponent>(); // general character properties msg.writeInt8(getAccountLevel()); msg.writeInt8(beingComponent->getGender()); msg.writeInt8(getHairStyle()); msg.writeInt8(getHairColor()); msg.writeInt16(getAttributePoints()); msg.writeInt16(getCorrectionPoints()); const AttributeMap &attributes = beingComponent->getAttributes(); std::map<const AttributeInfo *, const Attribute *> attributesToSend; for (auto &attributeIt : attributes) { if (attributeIt.first->persistent) attributesToSend.insert(std::make_pair(attributeIt.first, &attributeIt.second)); } msg.writeInt16(attributesToSend.size()); for (auto &attributeIt : attributesToSend) { msg.writeInt16(attributeIt.first->id); msg.writeDouble(attributeIt.second->getBase()); msg.writeDouble(attributeIt.second->getModifiedAttribute()); } // status effects currently affecting the character auto &statusEffects = beingComponent->getStatusEffects(); msg.writeInt16(statusEffects.size()); for (auto &statusIt : statusEffects) { msg.writeInt16(statusIt.first); msg.writeInt16(statusIt.second.time); } // location msg.writeInt16(entity.getMap()->getID()); const Point &pos = entity.getComponent<ActorComponent>()->getPosition(); msg.writeInt16(pos.x); msg.writeInt16(pos.y); // kill count msg.writeInt16(getKillCountSize()); for (auto &killCountIt : mKillCount) { msg.writeInt16(killCountIt.first); msg.writeInt32(killCountIt.second); } // character abilities auto &abilities = entity.getComponent<AbilityComponent>()->getAbilities(); msg.writeInt16(abilities.size()); for (auto &abilityIt : abilities) { msg.writeInt32(abilityIt.first); } // questlog msg.writeInt16(mQuestlog.size()); for (auto questlogIt : mQuestlog) { QuestInfo &quest = questlogIt.second; msg.writeInt16(quest.id); msg.writeInt8(quest.state); msg.writeString(quest.title); msg.writeString(quest.description); } // inventory - must be last because size isn't transmitted const Possessions &poss = getPossessions(); const InventoryData &inventoryData = poss.getInventory(); for (InventoryData::const_iterator itemIt = inventoryData.begin(), itemIt_end = inventoryData.end(); itemIt != itemIt_end; ++itemIt) { msg.writeInt16(itemIt->first); // slot id msg.writeInt16(itemIt->second.itemId); msg.writeInt16(itemIt->second.amount); msg.writeInt8(itemIt->second.equipmentSlot); } }
void ChatHandler::processRaw(MessageOut &outMsg, const std::string &line) { size_t pos = line.find(":"); if (pos == std::string::npos) { const int i = atoi(line.c_str()); if (line.length() <= 3) outMsg.writeInt8(static_cast<unsigned char>(i)); else if (line.length() <= 5) outMsg.writeInt16(static_cast<int16_t>(i)); else outMsg.writeInt32(i); } else { const std::string header = line.substr(0, pos); if (header.length() != 1) return; std::string data = line.substr(pos + 1); int i = 0; switch (header[0]) { case '1': case '2': case '4': i = atoi(data.c_str()); break; default: break; } switch (header[0]) { case '1': outMsg.writeInt8(static_cast<unsigned char>(i)); break; case '2': outMsg.writeInt16(static_cast<int16_t>(i)); break; case '4': outMsg.writeInt32(i); break; case 'c': { pos = line.find(","); if (pos != std::string::npos) { const uint16_t x = static_cast<const uint16_t>( atoi(data.substr(0, pos).c_str())); data = data.substr(pos + 1); pos = line.find(","); if (pos == std::string::npos) break; const uint16_t y = static_cast<const uint16_t>( atoi(data.substr(0, pos).c_str())); const int dir = atoi(data.substr(pos + 1).c_str()); outMsg.writeCoordinates(x, y, static_cast<unsigned char>(dir)); } break; } case 't': outMsg.writeString(data, static_cast<int>(data.length())); break; default: break; } } }