From 3d055667592239188b3bcd7c4ce0a8c197549da8 Mon Sep 17 00:00:00 2001 From: ErikasKontenis Date: Sun, 10 Nov 2019 19:45:03 +0200 Subject: [PATCH] issiauskinau kad checksum yra nahuj reikalingas ir kad onConnect turejo buti uzkomentuotas. Reikia issiaiskinti kodel luzta onLogin clientas. Kitus failus reikia perziureti ir isvalyti siuksles --- config.lua | 2 +- data/world/mymap-house.xml | 2 + data/world/mymap-spawn.xml | 2 + data/world/mymap.otbm | Bin 0 -> 10923 bytes src/configmanager.cpp | 1 + src/configmanager.h | 1 + src/connection.cpp | 19 +----- src/iologindata.cpp | 9 ++- src/luascript.cpp | 39 ++++++++++- src/luascript.h | 3 + src/monsters.cpp | 4 ++ src/outputmessage.h | 112 ++++++++++++++++---------------- src/protocolgame.cpp | 55 ++++++++-------- src/protocollogin.cpp | 51 +++------------ src/protocollogin.h | 2 +- src/server.cpp | 34 +++++----- src/server.h | 129 ++++++++++++++++++------------------- 17 files changed, 233 insertions(+), 232 deletions(-) create mode 100644 data/world/mymap-house.xml create mode 100644 data/world/mymap-spawn.xml create mode 100644 data/world/mymap.otbm diff --git a/config.lua b/config.lua index e354f60..0383f6a 100644 --- a/config.lua +++ b/config.lua @@ -52,7 +52,7 @@ timeBetweenExActions = 1000 -- Map -- NOTE: set mapName WITHOUT .otbm at the end -mapName = "map" +mapName = "mymap" mapAuthor = "CipSoft" -- MySQL diff --git a/data/world/mymap-house.xml b/data/world/mymap-house.xml new file mode 100644 index 0000000..9d137e4 --- /dev/null +++ b/data/world/mymap-house.xml @@ -0,0 +1,2 @@ + + diff --git a/data/world/mymap-spawn.xml b/data/world/mymap-spawn.xml new file mode 100644 index 0000000..2bde032 --- /dev/null +++ b/data/world/mymap-spawn.xml @@ -0,0 +1,2 @@ + + diff --git a/data/world/mymap.otbm b/data/world/mymap.otbm new file mode 100644 index 0000000000000000000000000000000000000000..b0ed9ec5f5dfe57b6037d2c7e14d434a6aa29908 GIT binary patch literal 10923 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 0) { - checksum = adlerChecksum(msg.getBuffer() + msg.getBufferPosition() + NetworkMessage::CHECKSUM_LENGTH, len); - } - else { - checksum = 0; - } - - uint32_t recvChecksum = msg.get(); - if (recvChecksum != checksum) { - // it might not have been the checksum, step back - msg.skipBytes(-NetworkMessage::CHECKSUM_LENGTH); - } - if (!receivedFirst) { // First message received receivedFirst = true; if (!protocol) { // Game protocol has already been created at this point - protocol = service_port->make_protocol(recvChecksum == checksum, msg, shared_from_this()); + protocol = service_port->make_protocol(msg, shared_from_this()); if (!protocol) { close(FORCE_CLOSE); return; @@ -242,6 +226,7 @@ void Connection::parsePacket(const boost::system::error_code& error) } + void Connection::send(const OutputMessage_ptr& msg) { std::lock_guard lockClass(connectionLock); diff --git a/src/iologindata.cpp b/src/iologindata.cpp index 4fb9fbc..3a52c64 100644 --- a/src/iologindata.cpp +++ b/src/iologindata.cpp @@ -188,7 +188,7 @@ bool IOLoginData::preloadPlayer(Player* player, const std::string& name) bool IOLoginData::loadPlayerById(Player* player, uint32_t id) { std::ostringstream query; - query << "SELECT `id`, `name`, `account_id`, `group_id`, `sex`, `vocation`, `experience`, `level`, `maglevel`, `health`, `healthmax`, `blessings`, `mana`, `manamax`, `manaspent`, `soul`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `posx`, `posy`, `posz`, `cap`, `lastlogin`, `lastlogout`, `lastip`, `conditions`, `skulltime`, `skull`, `town_id`, `balance`, `skill_fist`, `skill_fist_tries`, `skill_club`, `skill_club_tries`, `skill_sword`, `skill_sword_tries`, `skill_axe`, `skill_axe_tries`, `skill_dist`, `skill_dist_tries`, `skill_shielding`, `skill_shielding_tries`, `skill_fishing`, `skill_fishing_tries` FROM `players` WHERE `id` = " << id; + query << "SELECT `id`, `name`, `account_id`, `group_id`, `sex`, `vocation`, `experience`, `level`, `maglevel`, `health`, `healthmax`, `blessings`, `mana`, `manamax`, `manaspent`, `soul`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `lookaddons`, `posx`, `posy`, `posz`, `cap`, `lastlogin`, `lastlogout`, `lastip`, `conditions`, `skulltime`, `skull`, `town_id`, `balance`, `stamina`, `skill_fist`, `skill_fist_tries`, `skill_club`, `skill_club_tries`, `skill_sword`, `skill_sword_tries`, `skill_axe`, `skill_axe_tries`, `skill_dist`, `skill_dist_tries`, `skill_shielding`, `skill_shielding_tries`, `skill_fishing`, `skill_fishing_tries` FROM `players` WHERE `id` = " << id; return loadPlayer(player, Database::getInstance()->storeQuery(query.str())); } @@ -196,7 +196,7 @@ bool IOLoginData::loadPlayerByName(Player* player, const std::string& name) { Database* db = Database::getInstance(); std::ostringstream query; - query << "SELECT `id`, `name`, `account_id`, `group_id`, `sex`, `vocation`, `experience`, `level`, `maglevel`, `health`, `healthmax`, `blessings`, `mana`, `manamax`, `manaspent`, `soul`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `posx`, `posy`, `posz`, `cap`, `lastlogin`, `lastlogout`, `lastip`, `conditions`, `skulltime`, `skull`, `town_id`, `balance`, `skill_fist`, `skill_fist_tries`, `skill_club`, `skill_club_tries`, `skill_sword`, `skill_sword_tries`, `skill_axe`, `skill_axe_tries`, `skill_dist`, `skill_dist_tries`, `skill_shielding`, `skill_shielding_tries`, `skill_fishing`, `skill_fishing_tries` FROM `players` WHERE `name` = " << db->escapeString(name); + query << "SELECT `id`, `name`, `account_id`, `group_id`, `sex`, `vocation`, `experience`, `level`, `maglevel`, `health`, `healthmax`, `blessings`, `mana`, `manamax`, `manaspent`, `soul`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `lookaddons`, `posx`, `posy`, `posz`, `cap`, `lastlogin`, `lastlogout`, `lastip`, `conditions`, `skulltime`, `skull`, `town_id`, `balance`, `stamina`, `skill_fist`, `skill_fist_tries`, `skill_club`, `skill_club_tries`, `skill_sword`, `skill_sword_tries`, `skill_axe`, `skill_axe_tries`, `skill_dist`, `skill_dist_tries`, `skill_shielding`, `skill_shielding_tries`, `skill_fishing`, `skill_fishing_tries` FROM `players` WHERE `name` = " << db->escapeString(name); return loadPlayer(player, db->storeQuery(query.str())); } @@ -296,6 +296,7 @@ bool IOLoginData::loadPlayer(Player* player, DBResult_ptr result) player->defaultOutfit.lookBody = result->getNumber("lookbody"); player->defaultOutfit.lookLegs = result->getNumber("looklegs"); player->defaultOutfit.lookFeet = result->getNumber("lookfeet"); + player->defaultOutfit.lookAddons = result->getNumber("lookaddons"); player->currentOutfit = player->defaultOutfit; if (g_game.getWorldType() != WORLD_TYPE_PVP_ENFORCED) { @@ -331,6 +332,8 @@ bool IOLoginData::loadPlayer(Player* player, DBResult_ptr result) player->loginPosition = player->getTemplePosition(); } + player->staminaMinutes = result->getNumber("stamina"); + static const std::string skillNames[] = {"skill_fist", "skill_club", "skill_sword", "skill_axe", "skill_dist", "skill_shielding", "skill_fishing"}; static const std::string skillNameTries[] = {"skill_fist_tries", "skill_club_tries", "skill_sword_tries", "skill_axe_tries", "skill_dist_tries", "skill_shielding_tries", "skill_fishing_tries"}; static constexpr size_t size = sizeof(skillNames) / sizeof(std::string); @@ -616,6 +619,7 @@ bool IOLoginData::savePlayer(Player* player) query << "`lookhead` = " << static_cast(player->defaultOutfit.lookHead) << ','; query << "`looklegs` = " << static_cast(player->defaultOutfit.lookLegs) << ','; query << "`looktype` = " << player->defaultOutfit.lookType << ','; + query << "`lookaddons` = " << static_cast(player->defaultOutfit.lookAddons) << ','; query << "`maglevel` = " << player->magLevel << ','; query << "`mana` = " << player->mana << ','; query << "`manamax` = " << player->manaMax << ','; @@ -654,6 +658,7 @@ bool IOLoginData::savePlayer(Player* player) query << "`lastlogout` = " << player->getLastLogout() << ','; query << "`balance` = " << player->bankBalance << ','; + query << "`stamina` = " << player->getStaminaMinutes() << ','; query << "`skill_fist` = " << player->skills[SKILL_FIST].level << ','; query << "`skill_fist_tries` = " << player->skills[SKILL_FIST].tries << ','; diff --git a/src/luascript.cpp b/src/luascript.cpp index 8099d24..3401679 100644 --- a/src/luascript.cpp +++ b/src/luascript.cpp @@ -730,6 +730,8 @@ Position LuaScriptInterface::getPosition(lua_State* L, int32_t arg) Outfit_t LuaScriptInterface::getOutfit(lua_State* L, int32_t arg) { Outfit_t outfit; + outfit.lookAddons = getField(L, arg, "lookAddons"); + outfit.lookFeet = getField(L, arg, "lookFeet"); outfit.lookLegs = getField(L, arg, "lookLegs"); outfit.lookBody = getField(L, arg, "lookBody"); @@ -882,6 +884,7 @@ void LuaScriptInterface::pushOutfit(lua_State* L, const Outfit_t& outfit) setField(L, "lookBody", outfit.lookBody); setField(L, "lookLegs", outfit.lookLegs); setField(L, "lookFeet", outfit.lookFeet); + setField(L, "lookAddons", outfit.lookAddons); } #define registerEnum(value) { std::string enumName = #value; registerGlobalVariable(enumName.substr(enumName.find_last_of(':') + 1), value); } @@ -1607,6 +1610,7 @@ void LuaScriptInterface::registerFunctions() registerEnumIn("configKeys", ConfigManager::ALLOW_CLONES) registerEnumIn("configKeys", ConfigManager::BIND_ONLY_GLOBAL_ADDRESS) registerEnumIn("configKeys", ConfigManager::OPTIMIZE_DATABASE) + registerEnumIn("configKeys", ConfigManager::STAMINA_SYSTEM) registerEnumIn("configKeys", ConfigManager::WARN_UNSAFE_SCRIPTS) registerEnumIn("configKeys", ConfigManager::CONVERT_UNSAFE_SCRIPTS) registerEnumIn("configKeys", ConfigManager::TELEPORT_NEWBIES) @@ -2008,6 +2012,9 @@ void LuaScriptInterface::registerFunctions() registerMethod("Player", "getGroup", LuaScriptInterface::luaPlayerGetGroup); registerMethod("Player", "setGroup", LuaScriptInterface::luaPlayerSetGroup); + registerMethod("Player", "getStamina", LuaScriptInterface::luaPlayerGetStamina); + registerMethod("Player", "setStamina", LuaScriptInterface::luaPlayerSetStamina); + registerMethod("Player", "getSoul", LuaScriptInterface::luaPlayerGetSoul); registerMethod("Player", "addSoul", LuaScriptInterface::luaPlayerAddSoul); registerMethod("Player", "getMaxSoul", LuaScriptInterface::luaPlayerGetMaxSoul); @@ -7757,6 +7764,35 @@ int LuaScriptInterface::luaPlayerSetGroup(lua_State* L) return 1; } +int LuaScriptInterface::luaPlayerGetStamina(lua_State* L) +{ + // player:getStamina() + Player* player = getUserdata(L, 1); + if (player) { + lua_pushnumber(L, player->getStaminaMinutes()); + } + else { + lua_pushnil(L); + } + return 1; +} + +int LuaScriptInterface::luaPlayerSetStamina(lua_State* L) +{ + // player:setStamina(stamina) + uint16_t stamina = getNumber(L, 2); + Player* player = getUserdata(L, 1); + if (player) { + player->staminaMinutes = std::min(2520, stamina); + player->sendStats(); + pushBoolean(L, true); + } + else { + lua_pushnil(L); + } + return 1; +} + int LuaScriptInterface::luaPlayerGetSoul(lua_State* L) { // player:getSoul() @@ -10616,11 +10652,12 @@ int LuaScriptInterface::luaConditionSetSpeedDelta(lua_State* L) int LuaScriptInterface::luaConditionSetOutfit(lua_State* L) { // condition:setOutfit(outfit) - // condition:setOutfit(lookTypeEx, lookType, lookHead, lookBody, lookLegs, lookFeet) + // condition:setOutfit(lookTypeEx, lookType, lookHead, lookBody, lookLegs, lookFeet[, lookAddons]) Outfit_t outfit; if (isTable(L, 2)) { outfit = getOutfit(L, 2); } else { + outfit.lookAddons = getNumber(L, 8, outfit.lookAddons); outfit.lookFeet = getNumber(L, 7); outfit.lookLegs = getNumber(L, 6); outfit.lookBody = getNumber(L, 5); diff --git a/src/luascript.h b/src/luascript.h index 8b90a48..90c2dd0 100644 --- a/src/luascript.h +++ b/src/luascript.h @@ -849,6 +849,9 @@ class LuaScriptInterface static int luaPlayerGetGroup(lua_State* L); static int luaPlayerSetGroup(lua_State* L); + static int luaPlayerGetStamina(lua_State* L); + static int luaPlayerSetStamina(lua_State* L); + static int luaPlayerGetSoul(lua_State* L); static int luaPlayerAddSoul(lua_State* L); static int luaPlayerGetMaxSoul(lua_State* L); diff --git a/src/monsters.cpp b/src/monsters.cpp index bf46bd1..9b5c467 100644 --- a/src/monsters.cpp +++ b/src/monsters.cpp @@ -759,6 +759,10 @@ bool Monsters::loadMonster(const std::string& file, const std::string& monsterNa if ((attr = node.attribute("feet"))) { mType->info.outfit.lookFeet = pugi::cast(attr.value()); } + + if ((attr = node.attribute("addons"))) { + mType->info.outfit.lookAddons = pugi::cast(attr.value()); + } } else if ((attr = node.attribute("typeex"))) { mType->info.outfit.lookTypeEx = pugi::cast(attr.value()); } else { diff --git a/src/outputmessage.h b/src/outputmessage.h index 92c690d..09f5435 100644 --- a/src/outputmessage.h +++ b/src/outputmessage.h @@ -28,80 +28,76 @@ class Protocol; class OutputMessage : public NetworkMessage { - public: - OutputMessage() = default; +public: + OutputMessage() = default; - // non-copyable - OutputMessage(const OutputMessage&) = delete; - OutputMessage& operator=(const OutputMessage&) = delete; + // non-copyable + OutputMessage(const OutputMessage&) = delete; + OutputMessage& operator=(const OutputMessage&) = delete; - uint8_t* getOutputBuffer() { - return buffer + outputBufferStart; - } + uint8_t* getOutputBuffer() { + return buffer + outputBufferStart; + } - void writeMessageLength() { - add_header(info.length); - } + void writeMessageLength() { + add_header(info.length); + } - void addCryptoHeader(bool addChecksum) { - if (addChecksum) { - add_header(adlerChecksum(buffer + outputBufferStart, info.length)); - } + void addCryptoHeader(bool addChecksum) { + writeMessageLength(); + } - writeMessageLength(); - } + inline void append(const NetworkMessage& msg) { + auto msgLen = msg.getLength(); + memcpy(buffer + info.position, msg.getBuffer() + 4, msgLen); + info.length += msgLen; + info.position += msgLen; + } - inline void append(const NetworkMessage& msg) { - auto msgLen = msg.getLength(); - memcpy(buffer + info.position, msg.getBuffer() + 4, msgLen); - info.length += msgLen; - info.position += msgLen; - } + inline void append(const OutputMessage_ptr& msg) { + auto msgLen = msg->getLength(); + memcpy(buffer + info.position, msg->getBuffer() + 4, msgLen); + info.length += msgLen; + info.position += msgLen; + } - inline void append(const OutputMessage_ptr& msg) { - auto msgLen = msg->getLength(); - memcpy(buffer + info.position, msg->getBuffer() + 4, msgLen); - info.length += msgLen; - info.position += msgLen; - } +protected: + template + inline void add_header(T add) { + assert(outputBufferStart >= sizeof(T)); + outputBufferStart -= sizeof(T); + memcpy(buffer + outputBufferStart, &add, sizeof(T)); + //added header size to the message size + info.length += sizeof(T); + } - protected: - template - inline void add_header(T add) { - assert(outputBufferStart >= sizeof(T)); - outputBufferStart -= sizeof(T); - memcpy(buffer + outputBufferStart, &add, sizeof(T)); - //added header size to the message size - info.length += sizeof(T); - } - - MsgSize_t outputBufferStart = INITIAL_BUFFER_POSITION; + MsgSize_t outputBufferStart = INITIAL_BUFFER_POSITION; }; class OutputMessagePool { - public: - // non-copyable - OutputMessagePool(const OutputMessagePool&) = delete; - OutputMessagePool& operator=(const OutputMessagePool&) = delete; +public: + // non-copyable + OutputMessagePool(const OutputMessagePool&) = delete; + OutputMessagePool& operator=(const OutputMessagePool&) = delete; - static OutputMessagePool& getInstance() { - static OutputMessagePool instance; - return instance; - } + static OutputMessagePool& getInstance() { + static OutputMessagePool instance; + return instance; + } - void sendAll(); - void scheduleSendAll(); + void sendAll(); + void scheduleSendAll(); - static OutputMessage_ptr getOutputMessage(); + static OutputMessage_ptr getOutputMessage(); - void addProtocolToAutosend(Protocol_ptr protocol); - void removeProtocolFromAutosend(const Protocol_ptr& protocol); - private: - OutputMessagePool() = default; - //NOTE: A vector is used here because this container is mostly read - //and relatively rarely modified (only when a client connects/disconnects) - std::vector bufferedProtocols; + void addProtocolToAutosend(Protocol_ptr protocol); + void removeProtocolFromAutosend(const Protocol_ptr& protocol); +private: + OutputMessagePool() = default; + //NOTE: A vector is used here because this container is mostly read + //and relatively rarely modified (only when a client connects/disconnects) + std::vector bufferedProtocols; }; diff --git a/src/protocolgame.cpp b/src/protocolgame.cpp index f2536f0..3714984 100644 --- a/src/protocolgame.cpp +++ b/src/protocolgame.cpp @@ -242,8 +242,6 @@ void ProtocolGame::onRecvFirstMessage(NetworkMessage& msg) OperatingSystem_t operatingSystem = static_cast(msg.get()); version = msg.get(); - msg.skipBytes(7); // U32 client version, U8 client type, U16 dat revision - if (!Protocol::RSA_decrypt(msg)) { disconnect(); return; @@ -304,45 +302,24 @@ void ProtocolGame::onRecvFirstMessage(NetworkMessage& msg) disconnectClient("Account number or password is not correct."); return; } - + Account account; if (!IOLoginData::loginserverAuthentication(accountNumber, password, account)) { disconnectClient("Account number or password is not correct."); return; } - + //Update premium days Game::updatePremium(account); g_dispatcher.addTask(createTask(std::bind(&ProtocolGame::login, getThis(), characterName, accountId, operatingSystem))); + } void ProtocolGame::onConnect() { - auto output = OutputMessagePool::getOutputMessage(); - static std::random_device rd; - static std::ranlux24 generator(rd()); - static std::uniform_int_distribution randNumber(0x00, 0xFF); - // Skip checksum - output->skipBytes(sizeof(uint32_t)); - // Packet length & type - output->add(0x0006); - output->addByte(0x1F); - - // Add timestamp & random number - challengeTimestamp = static_cast(time(nullptr)); - output->add(challengeTimestamp); - - challengeRandom = randNumber(generator); - output->addByte(challengeRandom); - - // Go back and write checksum - output->skipBytes(-12); - output->add(adlerChecksum(output->getOutputBuffer() + sizeof(uint32_t), 8)); - - send(output); } void ProtocolGame::disconnectClient(const std::string& message) const @@ -464,12 +441,15 @@ void ProtocolGame::parsePacket(NetworkMessage& msg) void ProtocolGame::GetTileDescription(const Tile* tile, NetworkMessage& msg) { + msg.add(0x00); //environmental effects + int32_t count; Item* ground = tile->getGround(); if (ground) { msg.addItem(ground); count = 1; - } else { + } + else { count = 0; } @@ -478,7 +458,11 @@ void ProtocolGame::GetTileDescription(const Tile* tile, NetworkMessage& msg) for (auto it = items->getBeginTopItem(), end = items->getEndTopItem(); it != end; ++it) { msg.addItem(*it); - if (++count == 10) { + count++; + if (count == 9 && tile->getPosition() == player->getPosition()) { + break; + } + else if (count == 10) { return; } } @@ -486,11 +470,20 @@ void ProtocolGame::GetTileDescription(const Tile* tile, NetworkMessage& msg) const CreatureVector* creatures = tile->getCreatures(); if (creatures) { + bool playerAdded = false; for (const Creature* creature : boost::adaptors::reverse(*creatures)) { if (!player->canSeeCreature(creature)) { continue; } + if (tile->getPosition() == player->getPosition() && count == 9 && !playerAdded) { + creature = player; + } + + if (creature->getID() == player->getID()) { + playerAdded = true; + } + bool known; uint32_t removedKnown; checkCreatureAsKnown(creature->getID(), known, removedKnown); @@ -1864,12 +1857,18 @@ void ProtocolGame::AddPlayerStats(NetworkMessage& msg) msg.add(std::min(player->getMaxMana(), std::numeric_limits::max())); msg.addByte(std::min(player->getMagicLevel(), std::numeric_limits::max())); + msg.addByte(std::min(player->getBaseMagicLevel(), std::numeric_limits::max())); msg.addByte(player->getMagicLevelPercent()); msg.addByte(player->getSoul()); msg.add(player->getStaminaMinutes()); + msg.add(player->getBaseSpeed() / 2); + + Condition* condition = player->getCondition(CONDITION_REGENERATION); + msg.add(condition ? condition->getTicks() / 1000 : 0x00); + msg.add(0); // xp boost time (seconds) } diff --git a/src/protocollogin.cpp b/src/protocollogin.cpp index fad7a98..f32c17e 100644 --- a/src/protocollogin.cpp +++ b/src/protocollogin.cpp @@ -43,7 +43,7 @@ void ProtocolLogin::disconnectClient(const std::string& message, uint16_t versio disconnect(); } -void ProtocolLogin::getCharacterList(uint32_t accountNumber, const std::string& password, const std::string& token, uint16_t version) +void ProtocolLogin::getCharacterList(uint32_t accountNumber, const std::string& password, uint16_t version) { Account account; if (!IOLoginData::loginserverAuthentication(accountNumber, password, account)) { @@ -51,20 +51,7 @@ void ProtocolLogin::getCharacterList(uint32_t accountNumber, const std::string& return; } - uint32_t ticks = time(nullptr) / AUTHENTICATOR_PERIOD; - auto output = OutputMessagePool::getOutputMessage(); - if (!std::to_string(accountNumber).empty()) { - if (token.empty() || !(token == generateToken(std::to_string(accountNumber), ticks) || token == generateToken(std::to_string(accountNumber), ticks - 1) || token == generateToken(std::to_string(accountNumber), ticks + 1))) { - output->addByte(0x0D); - output->addByte(0); - send(output); - disconnect(); - return; - } - output->addByte(0x0C); - output->addByte(0); - } //Update premium days Game::updatePremium(account); @@ -79,38 +66,24 @@ void ProtocolLogin::getCharacterList(uint32_t accountNumber, const std::string& output->addString(ss.str()); } - //Add session key - output->addByte(0x28); - output->addString(std::to_string(accountNumber) + "\n" + password + "\n" + token + "\n" + std::to_string(ticks)); - - //Add char list output->addByte(0x64); - output->addByte(1); // number of worlds - - output->addByte(0); // world id - output->addString(g_config.getString(ConfigManager::SERVER_NAME)); - output->addString(g_config.getString(ConfigManager::IP)); - output->add(g_config.getNumber(ConfigManager::GAME_PORT)); - output->addByte(0); - uint8_t size = std::min(std::numeric_limits::max(), account.characters.size()); output->addByte(size); for (uint8_t i = 0; i < size; i++) { - output->addByte(0); output->addString(account.characters[i]); + output->addString(g_config.getString(ConfigManager::SERVER_NAME)); + output->add(inet_addr(g_config.getString(ConfigManager::IP).c_str())); + output->add(g_config.getNumber(ConfigManager::GAME_PORT)); } //Add premium days - output->addByte(0); if (g_config.getBoolean(ConfigManager::FREE_PREMIUM)) { - output->addByte(1); - output->add(0); + output->add(0xFFFF); } else { - output->addByte(account.premiumDays > 0 ? 1 : 0); - output->add(time(nullptr) + (account.premiumDays * 86400)); + output->add(account.premiumDays); } send(output); @@ -118,6 +91,7 @@ void ProtocolLogin::getCharacterList(uint32_t accountNumber, const std::string& disconnect(); } + void ProtocolLogin::onRecvFirstMessage(NetworkMessage& msg) { if (g_game.getGameState() == GAME_STATE_SHUTDOWN) { @@ -208,15 +182,6 @@ void ProtocolLogin::onRecvFirstMessage(NetworkMessage& msg) return; } - // read authenticator token and stay logged in flag from last 128 bytes - msg.skipBytes((msg.getLength() - 128) - msg.getBufferPosition()); - if (!Protocol::RSA_decrypt(msg)) { - disconnectClient("Invalid authentification token.", version); - return; - } - - std::string authToken = msg.getString(); - auto thisPtr = std::static_pointer_cast(shared_from_this()); - g_dispatcher.addTask(createTask(std::bind(&ProtocolLogin::getCharacterList, thisPtr, accountNumber, password, authToken, version))); + g_dispatcher.addTask(createTask(std::bind(&ProtocolLogin::getCharacterList, thisPtr, accountNumber, password, version))); } diff --git a/src/protocollogin.h b/src/protocollogin.h index 4651b50..3b75851 100644 --- a/src/protocollogin.h +++ b/src/protocollogin.h @@ -43,7 +43,7 @@ class ProtocolLogin : public Protocol private: void disconnectClient(const std::string& message, uint16_t version); - void getCharacterList(uint32_t accountNumber, const std::string& password, const std::string& token, uint16_t version); + void getCharacterList(uint32_t accountNumber, const std::string& password, uint16_t version); }; #endif diff --git a/src/server.cpp b/src/server.cpp index 1b09123..d681456 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -56,7 +56,8 @@ void ServiceManager::stop() for (auto& servicePortIt : acceptors) { try { io_service.post(std::bind(&ServicePort::onStopServer, servicePortIt.second)); - } catch (boost::system::system_error& e) { + } + catch (boost::system::system_error& e) { std::cout << "[ServiceManager::stop] Network Error: " << e.what() << std::endl; } } @@ -114,25 +115,28 @@ void ServicePort::onAccept(Connection_ptr connection, const boost::system::error Service_ptr service = services.front(); if (service->is_single_socket()) { connection->accept(service->make_protocol(connection)); - } else { + } + else { connection->accept(); } - } else { + } + else { connection->close(Connection::FORCE_CLOSE); } accept(); - } else if (error != boost::asio::error::operation_aborted) { + } + else if (error != boost::asio::error::operation_aborted) { if (!pendingStart) { close(); pendingStart = true; g_scheduler.addEvent(createSchedulerTask(15000, - std::bind(&ServicePort::openAcceptor, std::weak_ptr(shared_from_this()), serverPort))); + std::bind(&ServicePort::openAcceptor, std::weak_ptr(shared_from_this()), serverPort))); } } } -Protocol_ptr ServicePort::make_protocol(bool checksummed, NetworkMessage& msg, const Connection_ptr& connection) const +Protocol_ptr ServicePort::make_protocol(NetworkMessage& msg, const Connection_ptr& connection) const { uint8_t protocolID = msg.getByte(); for (auto& service : services) { @@ -140,9 +144,7 @@ Protocol_ptr ServicePort::make_protocol(bool checksummed, NetworkMessage& msg, c continue; } - if ((checksummed && service->is_checksummed()) || !service->is_checksummed()) { - return service->make_protocol(connection); - } + return service->make_protocol(connection); } return nullptr; } @@ -169,21 +171,23 @@ void ServicePort::open(uint16_t port) try { if (g_config.getBoolean(ConfigManager::BIND_ONLY_GLOBAL_ADDRESS)) { acceptor.reset(new boost::asio::ip::tcp::acceptor(io_service, boost::asio::ip::tcp::endpoint( - boost::asio::ip::address(boost::asio::ip::address_v4::from_string(g_config.getString(ConfigManager::IP))), serverPort))); - } else { + boost::asio::ip::address(boost::asio::ip::address_v4::from_string(g_config.getString(ConfigManager::IP))), serverPort))); + } + else { acceptor.reset(new boost::asio::ip::tcp::acceptor(io_service, boost::asio::ip::tcp::endpoint( - boost::asio::ip::address(boost::asio::ip::address_v4(INADDR_ANY)), serverPort))); + boost::asio::ip::address(boost::asio::ip::address_v4(INADDR_ANY)), serverPort))); } acceptor->set_option(boost::asio::ip::tcp::no_delay(true)); accept(); - } catch (boost::system::system_error& e) { + } + catch (boost::system::system_error& e) { std::cout << "[ServicePort::open] Error: " << e.what() << std::endl; pendingStart = true; g_scheduler.addEvent(createSchedulerTask(15000, - std::bind(&ServicePort::openAcceptor, std::weak_ptr(shared_from_this()), port))); + std::bind(&ServicePort::openAcceptor, std::weak_ptr(shared_from_this()), port))); } } @@ -197,7 +201,7 @@ void ServicePort::close() bool ServicePort::add_service(const Service_ptr& new_svc) { - if (std::any_of(services.begin(), services.end(), [](const Service_ptr& svc) {return svc->is_single_socket();})) { + if (std::any_of(services.begin(), services.end(), [](const Service_ptr& svc) {return svc->is_single_socket(); })) { return false; } diff --git a/src/server.h b/src/server.h index 02e5278..e1d9aa2 100644 --- a/src/server.h +++ b/src/server.h @@ -27,98 +27,94 @@ class Protocol; class ServiceBase { - public: - virtual bool is_single_socket() const = 0; - virtual bool is_checksummed() const = 0; - virtual uint8_t get_protocol_identifier() const = 0; - virtual const char* get_protocol_name() const = 0; +public: + virtual bool is_single_socket() const = 0; + virtual uint8_t get_protocol_identifier() const = 0; + virtual const char* get_protocol_name() const = 0; - virtual Protocol_ptr make_protocol(const Connection_ptr& c) const = 0; + virtual Protocol_ptr make_protocol(const Connection_ptr& c) const = 0; }; template class Service final : public ServiceBase { - public: - bool is_single_socket() const override { - return ProtocolType::server_sends_first; - } - bool is_checksummed() const override { - return ProtocolType::use_checksum; - } - uint8_t get_protocol_identifier() const override { - return ProtocolType::protocol_identifier; - } - const char* get_protocol_name() const override { - return ProtocolType::protocol_name(); - } +public: + bool is_single_socket() const final { + return ProtocolType::server_sends_first; + } + uint8_t get_protocol_identifier() const final { + return ProtocolType::protocol_identifier; + } + const char* get_protocol_name() const final { + return ProtocolType::protocol_name(); + } - Protocol_ptr make_protocol(const Connection_ptr& c) const override { - return std::make_shared(c); - } + Protocol_ptr make_protocol(const Connection_ptr& c) const final { + return std::make_shared(c); + } }; class ServicePort : public std::enable_shared_from_this { - public: - explicit ServicePort(boost::asio::io_service& io_service) : io_service(io_service) {} - ~ServicePort(); +public: + explicit ServicePort(boost::asio::io_service& io_service) : io_service(io_service) {} + ~ServicePort(); - // non-copyable - ServicePort(const ServicePort&) = delete; - ServicePort& operator=(const ServicePort&) = delete; + // non-copyable + ServicePort(const ServicePort&) = delete; + ServicePort& operator=(const ServicePort&) = delete; - static void openAcceptor(std::weak_ptr weak_service, uint16_t port); - void open(uint16_t port); - void close(); - bool is_single_socket() const; - std::string get_protocol_names() const; + static void openAcceptor(std::weak_ptr weak_service, uint16_t port); + void open(uint16_t port); + void close(); + bool is_single_socket() const; + std::string get_protocol_names() const; - bool add_service(const Service_ptr& new_svc); - Protocol_ptr make_protocol(bool checksummed, NetworkMessage& msg, const Connection_ptr& connection) const; + bool add_service(const Service_ptr& new_svc); + Protocol_ptr make_protocol(NetworkMessage& msg, const Connection_ptr& connection) const; - void onStopServer(); - void onAccept(Connection_ptr connection, const boost::system::error_code& error); + void onStopServer(); + void onAccept(Connection_ptr connection, const boost::system::error_code& error); - protected: - void accept(); +protected: + void accept(); - boost::asio::io_service& io_service; - std::unique_ptr acceptor; - std::vector services; + boost::asio::io_service& io_service; + std::unique_ptr acceptor; + std::vector services; - uint16_t serverPort = 0; - bool pendingStart = false; + uint16_t serverPort = 0; + bool pendingStart = false; }; class ServiceManager { - public: - ServiceManager() = default; - ~ServiceManager(); +public: + ServiceManager() = default; + ~ServiceManager(); - // non-copyable - ServiceManager(const ServiceManager&) = delete; - ServiceManager& operator=(const ServiceManager&) = delete; + // non-copyable + ServiceManager(const ServiceManager&) = delete; + ServiceManager& operator=(const ServiceManager&) = delete; - void run(); - void stop(); + void run(); + void stop(); - template - bool add(uint16_t port); + template + bool add(uint16_t port); - bool is_running() const { - return acceptors.empty() == false; - } + bool is_running() const { + return acceptors.empty() == false; + } - protected: - void die(); +protected: + void die(); - std::unordered_map acceptors; + std::unordered_map acceptors; - boost::asio::io_service io_service; - boost::asio::deadline_timer death_timer { io_service }; - bool running = false; + boost::asio::io_service io_service; + boost::asio::deadline_timer death_timer{ io_service }; + bool running = false; }; template @@ -137,13 +133,14 @@ bool ServiceManager::add(uint16_t port) service_port = std::make_shared(io_service); service_port->open(port); acceptors[port] = service_port; - } else { + } + else { service_port = foundServicePort->second; if (service_port->is_single_socket() || ProtocolType::server_sends_first) { std::cout << "ERROR: " << ProtocolType::protocol_name() << - " and " << service_port->get_protocol_names() << - " cannot use the same port " << port << '.' << std::endl; + " and " << service_port->get_protocol_names() << + " cannot use the same port " << port << '.' << std::endl; return false; } }