void ProtocolSpectator::onRecvFirstMessage(NetworkMessage& msg) { if (g_game.getGameState() == GAME_STATE_SHUTDOWN) { getConnection()->close(); return; } operatingSystem = (OperatingSystem_t)msg.get<uint16_t>(); version = msg.get<uint16_t>(); msg.skipBytes(7); // U32 clientVersion, U8 clientType if (!RSA_decrypt(msg)) { getConnection()->close(); return; } uint32_t key[4]; key[0] = msg.get<uint32_t>(); key[1] = msg.get<uint32_t>(); key[2] = msg.get<uint32_t>(); key[3] = msg.get<uint32_t>(); enableXTEAEncryption(); setXTEAKey(key); if (operatingSystem >= CLIENTOS_OTCLIENT_LINUX) { NetworkMessage opcodeMessage; opcodeMessage.addByte(0x32); opcodeMessage.addByte(0x00); opcodeMessage.add<uint16_t>(0x00); writeToOutputBuffer(opcodeMessage); } msg.skipBytes(1); // gamemaster flag std::string password = msg.getString(); std::string characterName = msg.getString(); uint32_t timeStamp = msg.get<uint32_t>(); uint8_t randNumber = msg.getByte(); if (m_challengeTimestamp != timeStamp || m_challengeRandom != randNumber) { getConnection()->close(); return; } auto dispatchDisconnectClient = [this](const std::string& msg) { g_dispatcher.addTask(createTask( std::bind(&ProtocolSpectator::disconnectSpectator, this, msg))); }; if (version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX) { dispatchDisconnectClient("Only clients with protocol " CLIENT_VERSION_STR " allowed!"); return; } if (g_game.getGameState() == GAME_STATE_STARTUP) { dispatchDisconnectClient("Gameworld is starting up. Please wait."); return; } if (g_game.getGameState() == GAME_STATE_MAINTAIN) { dispatchDisconnectClient("Gameworld is under maintenance. Please re-connect in a while."); return; } BanInfo banInfo; if (IOBan::isIpBanned(getIP(), banInfo)) { if (banInfo.reason.empty()) { banInfo.reason = "(none)"; } std::ostringstream ss; ss << "Your IP has been banned until " << formatDateShort(banInfo.expiresAt) << " by " << banInfo.bannedBy << ".\n\nReason specified:\n" << banInfo.reason; dispatchDisconnectClient(ss.str()); return; } password.erase(password.begin()); g_dispatcher.addTask(createTask(std::bind(&ProtocolSpectator::login, this, characterName, password))); }
bool ProtocolLogin::parseFirstPacket(NetworkMessage& msg) { if (g_game.getGameState() == GAME_STATE_SHUTDOWN) { getConnection()->closeConnection(); return false; } uint32_t clientip = getConnection()->getIP(); /*uint16_t clientos = */ msg.get<uint16_t>(); uint16_t version = msg.get<uint16_t>(); if (version >= 971) { msg.SkipBytes(17); } else { msg.SkipBytes(12); } /* * Skipped bytes: * 4 bytes: protocolVersion (only 971+) * 12 bytes: dat, spr, pic signatures (4 bytes each) * 1 byte: 0 (only 971+) */ if (version <= 760) { disconnectClient(0x0A, "Only clients with protocol " CLIENT_VERSION_STR " allowed!"); return false; } if (!RSA_decrypt(msg)) { getConnection()->closeConnection(); return false; } uint32_t key[4]; key[0] = msg.get<uint32_t>(); key[1] = msg.get<uint32_t>(); key[2] = msg.get<uint32_t>(); key[3] = msg.get<uint32_t>(); enableXTEAEncryption(); setXTEAKey(key); std::string accountName = msg.GetString(); std::string password = msg.GetString(); if (version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX) { if (version >= 1076) disconnectClient(0x0B, "Only clients with protocol " CLIENT_VERSION_STR " allowed!"); else disconnectClient(0x0A, "Only clients with protocol " CLIENT_VERSION_STR " allowed!"); return false; } if (g_game.getGameState() == GAME_STATE_STARTUP) { disconnectClient(0x0B, "Gameworld is starting up. Please wait."); return false; } if (g_game.getGameState() == GAME_STATE_MAINTAIN) { disconnectClient(0x0B, "Gameworld is under maintenance. Please re-connect in a while."); return false; } BanInfo banInfo; if (IOBan::isIpBanned(clientip, banInfo)) { if (banInfo.reason.empty()) { banInfo.reason = "(none)"; } std::ostringstream ss; ss << "Your IP has been banned until " << formatDateShort(banInfo.expiresAt) << " by " << banInfo.bannedBy << ".\n\nReason specified:\n" << banInfo.reason; disconnectClient(0x0B, ss.str().c_str()); return false; } //IF THE PASSWORD FIELDS AND ACCOUNT FIELD ARE EMPTY THEN THE USER WAN'T TO USE CAST SYSTEM bool cast_login = false; if ((accountName.empty() && password.empty()) || (accountName.empty() && !password.empty())) { cast_login = true; } if (!cast_login && accountName.empty()) { disconnectClient(0x0B, "Invalid account name."); return false; } Account account; if (!cast_login && !IOLoginData::loginserverAuthentication(accountName, password, account)) { disconnectClient(0x0B, "Account name or password is not correct."); return false; } OutputMessage_ptr output = OutputMessagePool::getInstance()->getOutputMessage(this, false); if (output) { //Update premium days g_game.updatePremium(account); //Add MOTD output->AddByte(0x14); std::ostringstream ss; ss << g_game.getMotdNum() << "\n" << g_config.getString(ConfigManager::MOTD); output->AddString(ss.str()); //SessionKey if (!cast_login) { output->AddByte(0x28); output->AddString(accountName + "\n" + password); } //Add char list output->AddByte(0x64); if (cast_login) { int cz = 0; std::vector<std::string> names; std::vector<uint32_t> counts; cast_login = false; uint8_t size = 0; g_game.lockPlayers(); for (const auto& it : g_game.getPlayers()) { if (it.second->cast.isCasting && (it.second->cast.password == "" || it.second->cast.password == password)) { names.push_back(it.second->getName()); counts.push_back(it.second->getCastViewerCount()); it.second->getCastViewerCount(); cast_login = true; size++; } } g_game.unlockPlayers(); if (cast_login) { output->AddByte(size); // number of worlds for (auto it = counts.begin(); it != counts.end(); it++) { output->AddByte(cz); // world id std::ostringstream os; os << (*it); output->AddString(os.str() + std::string(" viewers")); output->AddString(g_config.getString(ConfigManager::IP)); output->add<uint16_t>(g_config.getNumber(ConfigManager::GAME_PORT)); output->AddByte(0); cz++; } output->AddByte((uint8_t)cz); int world = 0; for (auto it : names) { output->AddByte(world); output->AddString(it); world++; } } } if (!cast_login) { 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<uint16_t>(g_config.getNumber(ConfigManager::GAME_PORT)); output->AddByte(0); output->AddByte((uint8_t)account.charList.size()); for (const std::string& characterName : account.charList) { output->AddByte(0); output->AddString(characterName); } } //Add premium days if (g_config.getBoolean(ConfigManager::FREE_PREMIUM)) { output->add<uint16_t>(0xFFFF); //client displays free premium } else { output->add<uint16_t>(account.premiumDays); } OutputMessagePool::getInstance()->send(output); } getConnection()->closeConnection(); return true; }
void ProtocolLogin::onRecvFirstMessage(NetworkMessage& msg) { if (g_game.getGameState() == GAME_STATE_SHUTDOWN) { getConnection()->close(); return; } msg.skipBytes(2); // client OS uint16_t version = msg.get<uint16_t>(); if (version >= 971) { msg.skipBytes(17); } else { msg.skipBytes(12); } /* * Skipped bytes: * 4 bytes: protocolVersion * 12 bytes: dat, spr, pic signatures (4 bytes each) * 1 byte: 0 */ #define dispatchDisconnectClient(err) g_dispatcher.addTask(createTask(std::bind(&ProtocolLogin::disconnectClient, this, err, version))) if (version <= 760) { dispatchDisconnectClient("Only clients with protocol " CLIENT_VERSION_STR " allowed!"); return; } if (!Protocol::RSA_decrypt(msg)) { getConnection()->close(); return; } uint32_t key[4]; key[0] = msg.get<uint32_t>(); key[1] = msg.get<uint32_t>(); key[2] = msg.get<uint32_t>(); key[3] = msg.get<uint32_t>(); enableXTEAEncryption(); setXTEAKey(key); if (version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX) { dispatchDisconnectClient("Only clients with protocol " CLIENT_VERSION_STR " allowed!"); return; } if (g_game.getGameState() == GAME_STATE_STARTUP) { dispatchDisconnectClient("Gameworld is starting up. Please wait."); return; } if (g_game.getGameState() == GAME_STATE_MAINTAIN) { dispatchDisconnectClient("Gameworld is under maintenance.\nPlease re-connect in a while."); return; } BanInfo banInfo; if (IOBan::isIpBanned(getConnection()->getIP(), banInfo)) { if (banInfo.reason.empty()) { banInfo.reason = "(none)"; } std::ostringstream ss; ss << "Your IP has been banned until " << formatDateShort(banInfo.expiresAt) << " by " << banInfo.bannedBy << ".\n\nReason specified:\n" << banInfo.reason; dispatchDisconnectClient(ss.str()); return; } std::string accountName = msg.getString(); std::string password = msg.getString(); if (accountName.empty()) { if (!g_config.getBoolean(ConfigManager::ENABLE_LIVE_CASTING)) { dispatchDisconnectClient("Invalid account name."); } else { g_dispatcher.addTask(createTask(std::bind(&ProtocolLogin::getCastingStreamsList, this, password, version))); } return; } #undef dispatchDisconnectClient g_dispatcher.addTask(createTask(std::bind(&ProtocolLogin::getCharacterList, this, accountName, password, version))); }
std::string Item::getDescription(const ItemType& it, int32_t lookDistance, const Item* item /*= NULL*/, int32_t subType /*= -1*/, bool addArticle /*= true*/) { std::ostringstream s; s << getNameDescription(it, item, subType, addArticle); if (item) { subType = item->getSubType(); } if (it.isRune()) { if (!it.runeSpellName.empty()) { s << " (\"" << it.runeSpellName << "\")"; } if (it.runeLevel > 0 || it.runeMagLevel > 0) { int32_t tmpSubType = subType; if (item) { tmpSubType = item->getSubType(); } s << ". " << (it.stackable && tmpSubType > 1 ? "They" : "It") << " can only be used with"; if (it.runeLevel > 0) { s << " level " << it.runeLevel; } if (it.runeMagLevel > 0) { if (it.runeLevel > 0) { s << " and"; } s << " magic level " << it.runeMagLevel; } s << " or higher"; } } else if (it.weaponType != WEAPON_NONE) { if (it.weaponType == WEAPON_DIST && it.ammoType != AMMO_NONE) { s << " (Range:" << it.shootRange; if (it.attack != 0) { s << ", Atk " << std::showpos << it.attack << std::noshowpos; } if (it.hitChance != 0) { s << ", Hit% " << std::showpos << it.hitChance << std::noshowpos; } s << ")"; } else if (it.weaponType != WEAPON_AMMO) { bool begin = true; if (it.attack != 0) { begin = false; s << " (Atk:" << it.attack; if (it.abilities && it.abilities->elementType != COMBAT_NONE && it.abilities->elementDamage != 0) { s << " physical + " << it.abilities->elementDamage << " " << getCombatName(it.abilities->elementType); } } if (it.defense != 0 || it.extraDefense != 0) { if (begin) { begin = false; s << " ("; } else { s << ", "; } s << "Def:" << it.defense; if (it.extraDefense != 0 || (item && item->getExtraDefense() != 0)) { s << " " << std::showpos << it.extraDefense << std::noshowpos; } } if (it.abilities) { for (uint16_t i = SKILL_FIRST; i <= SKILL_LAST; i++) { if (!it.abilities->skills[i]) { continue; } if (begin) { begin = false; s << " ("; } else { s << ", "; } s << getSkillName(i) << " " << std::showpos << it.abilities->skills[i] << std::noshowpos; } if (it.abilities->stats[STAT_MAGICPOINTS]) { if (begin) { begin = false; s << " ("; } else { s << ", "; } s << "magic level " << std::showpos << it.abilities->stats[STAT_MAGICPOINTS] << std::noshowpos; } int32_t show = it.abilities->absorbPercent[COMBAT_FIRST]; for (uint32_t i = (COMBAT_FIRST + 1); i <= COMBAT_COUNT; ++i) { if (it.abilities->absorbPercent[i] == show) { continue; } show = 0; break; } if (!show) { bool tmp = true; for (uint32_t i = COMBAT_FIRST; i <= COMBAT_COUNT; i++) { if (!it.abilities->absorbPercent[i]) { continue; } if (tmp) { tmp = false; if (begin) { begin = false; s << " ("; } else { s << ", "; } s << "protection "; } else { s << ", "; } s << getCombatName(indexToCombatType(i)) << " " << std::showpos << it.abilities->absorbPercent[i] << std::noshowpos << "%"; } } else { if (begin) { begin = false; s << " ("; } else { s << ", "; } s << "protection all " << std::showpos << show << std::noshowpos << "%"; } if (it.abilities->speed) { if (begin) { begin = false; s << " ("; } else { s << ", "; } s << "speed " << std::showpos << (int32_t)(it.abilities->speed / 2) << std::noshowpos; } } if (!begin) { s << ")"; } } } else if (it.armor || (item && item->getArmor()) || it.showAttributes) { int32_t tmp = it.armor; if (item) { tmp = item->getArmor(); } bool begin = true; if (tmp != 0) { s << " (Arm:" << tmp; begin = false; } if (it.abilities) { for (uint16_t i = SKILL_FIRST; i <= SKILL_LAST; i++) { if (!it.abilities->skills[i]) { continue; } if (begin) { begin = false; s << " ("; } else { s << ", "; } s << getSkillName(i) << " " << std::showpos << it.abilities->skills[i] << std::noshowpos; } if (it.abilities->stats[STAT_MAGICPOINTS]) { if (begin) { begin = false; s << " ("; } else { s << ", "; } s << "magic level " << std::showpos << it.abilities->stats[STAT_MAGICPOINTS] << std::noshowpos; } int32_t show = it.abilities->absorbPercent[COMBAT_FIRST]; for (uint32_t i = (COMBAT_FIRST + 1); i <= COMBAT_COUNT; ++i) { if (it.abilities->absorbPercent[i] == show) { continue; } show = 0; break; } if (!show) { bool protectionBegin = true; for (uint32_t i = COMBAT_FIRST; i <= COMBAT_COUNT; i++) { if (!it.abilities->absorbPercent[i]) { continue; } if (protectionBegin) { protectionBegin = false; if (begin) { begin = false; s << " ("; } else { s << ", "; } s << "protection "; } else { s << ", "; } s << getCombatName(indexToCombatType(i)) << " " << std::showpos << it.abilities->absorbPercent[i] << std::noshowpos << "%"; } } else { if (begin) { begin = false; s << " ("; } else { s << ", "; } s << "protection all " << std::showpos << show << std::noshowpos << "%"; } if (it.abilities->speed) { if (begin) { begin = false; s << " ("; } else { s << ", "; } s << "speed " << std::showpos << (int32_t)(it.abilities->speed / 2) << std::noshowpos; } } if (!begin) { s << ")"; } } else if (it.isContainer()) { s << " (Vol:" << (int32_t)it.maxItems << ")"; } else { bool found = true; if (it.abilities) { if (it.abilities->speed > 0) { s << " (speed " << std::showpos << (it.abilities->speed / 2) << std::noshowpos << ")"; } else if (it.abilities && hasBitSet(CONDITION_DRUNK, it.abilities->conditionSuppressions)) { s << " (hard drinking)"; } else if (it.abilities->invisible) { s << " (invisibility)"; } else if (it.abilities->regeneration) { s << " (faster regeneration)"; } else if (it.abilities->manaShield) { s << " (mana shield)"; } else { found = false; } } else { found = false; } if (!found) { if (it.isKey()) { s << " (Key:" << (item ? (int32_t)item->getActionId() : 0) << ")"; } else if (it.isFluidContainer()) { if (subType > 0) { const std::string& itemName = items[subType].name; s << " of " << (itemName.length() ? itemName : "unknown"); } else { s << ". It is empty"; } } else if (it.isSplash()) { s << " of "; if (subType > 0 && items[subType].name.length()) { s << items[subType].name; } else { s << "unknown"; } } else if (it.allowDistRead && it.id != 7369 && it.id != 7370 && it.id != 7371) { s << "." << std::endl; if (lookDistance <= 4) { if (item && !item->getText().empty()) { if (item->getWriter().length()) { s << item->getWriter() << " wrote"; time_t date = item->getDate(); if (date > 0) { s << " on " << formatDateShort(date); } s << ": "; } else { s << "You read: "; } std::string outtext; if (utf8ToLatin1(item->getText().c_str(), outtext)) { s << outtext; } else { s << item->getText(); } } else { s << "Nothing is written on it"; } } else { s << "You are too far away to read it"; } } else if (it.levelDoor && item && item->getActionId() >= (int32_t)it.levelDoor) { s << " for level " << item->getActionId() - it.levelDoor; } } } if (it.showCharges) { s << " that has " << subType << " charge" << (subType != 1 ? "s" : "") << " left"; } if (it.showDuration) { if (item && item->hasAttribute(ATTR_ITEM_DURATION)) { int32_t duration = item->getDuration() / 1000; s << " that will expire in "; if (duration >= 86400) { uint16_t days = duration / 86400; uint16_t hours = (duration % 86400) / 3600; s << days << " day" << (days != 1 ? "s" : ""); if (hours > 0) { s << " and " << hours << " hour" << (hours != 1 ? "s" : ""); } } else if (duration >= 3600) { uint16_t hours = duration / 3600; uint16_t minutes = (duration % 3600) / 60; s << hours << " hour" << (hours != 1 ? "s" : ""); if (minutes > 0) { s << " and " << minutes << " minute" << (minutes != 1 ? "s" : ""); } } else if (duration >= 60) { uint16_t minutes = duration / 60; s << minutes << " minute" << (minutes != 1 ? "s" : ""); uint16_t seconds = duration % 60; if (seconds > 0) { s << " and " << seconds << " second" << (seconds != 1 ? "s" : ""); } } else { s << duration << " second" << (duration != 1 ? "s" : ""); } } else { s << " that is brand-new"; } } if (!it.allowDistRead || item->getText().empty() || (it.id >= 7369 && it.id <= 7371)) { s << "."; } if (it.wieldInfo != 0) { s << std::endl << "It can only be wielded properly by "; if (it.wieldInfo & WIELDINFO_PREMIUM) { s << "premium "; } if (it.wieldInfo & WIELDINFO_VOCREQ) { s << it.vocationString; } else { s << "players"; } if (it.wieldInfo & WIELDINFO_LEVEL) { s << " of level " << (int32_t)it.minReqLevel << " or higher"; } if (it.wieldInfo & WIELDINFO_MAGLV) { if (it.wieldInfo & WIELDINFO_LEVEL) { s << " and"; } else { s << " of"; } s << " magic level " << (int32_t)it.minReqMagicLevel << " or higher"; } s << "."; } if (lookDistance <= 1) { double weight = (item == NULL ? it.weight : item->getWeight()); if (weight > 0 && it.pickupable) { int32_t count = weight / it.weight; s << std::endl << getWeightDescription(it, weight, count); } } if (item && !item->getSpecialDescription().empty()) { s << std::endl << item->getSpecialDescription(); } else if (it.description.length() && lookDistance <= 1) { s << std::endl << it.description; } if (it.allowDistRead && it.id >= 7369 && it.id <= 7371 && !item->getText().empty()) { s << std::endl << item->getText(); } return s.str(); }
void ProtocolLogin::onRecvFirstMessage(NetworkMessage& msg) { if (g_game.getGameState() == GAME_STATE_SHUTDOWN) { disconnect(); return; } /*uint16_t clientos = */ msg.get<uint16_t>(); uint16_t version = msg.get<uint16_t>(); msg.skipBytes(12); /* * Skipped bytes: * 4 bytes: protocolVersion * 12 bytes: dat, spr, pic signatures (4 bytes each) * 1 byte: 0 */ if (version <= 760) { disconnectClient("Only clients with protocol " CLIENT_VERSION_STR " allowed!"); return; } if (!Protocol::RSA_decrypt(msg)) { disconnect(); return; } uint32_t key[4]; key[0] = msg.get<uint32_t>(); key[1] = msg.get<uint32_t>(); key[2] = msg.get<uint32_t>(); key[3] = msg.get<uint32_t>(); enableXTEAEncryption(); setXTEAKey(key); uint32_t accountName = msg.get<uint32_t>(); std::string password = msg.getString(); if (version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX) { disconnectClient("Only clients with protocol " CLIENT_VERSION_STR " allowed!"); return; } if (g_game.getGameState() == GAME_STATE_STARTUP) { disconnectClient("Gameworld is starting up. Please wait."); return; } if (g_game.getGameState() == GAME_STATE_MAINTAIN) { disconnectClient("Gameworld is under maintenance.\nPlease re-connect in a while."); return; } BanInfo banInfo; auto connection = getConnection(); if (!connection) { return; } if (IOBan::isIpBanned(connection->getIP(), banInfo)) { if (banInfo.reason.empty()) { banInfo.reason = "(none)"; } std::ostringstream ss; ss << "Your IP has been banned until " << formatDateShort(banInfo.expiresAt) << " by " << banInfo.bannedBy << ".\n\nReason specified:\n" << banInfo.reason; disconnectClient(ss.str()); return; } if (accountName == 0) { disconnectClient("Invalid account name."); return; } auto thisPtr = std::dynamic_pointer_cast<ProtocolLogin>(shared_from_this()); g_dispatcher.addTask(createTask(std::bind(&ProtocolLogin::getCharacterList, thisPtr, accountName, password))); }
std::string Item::getDescription(const ItemType& it, const int32_t& lookDistance, const Item* item /*= NULL*/, int32_t subType /*= -1*/, bool addArticle /*= true*/) { std::stringstream s; if (item) { subType = item->getSubType(); } s << getLongName(it, lookDistance, item, subType, addArticle); if (it.isRune()) { s << " (\"" << it.runeSpellName << "\")."; if (it.runeLevel > 0 || it.runeMagLevel > 0) { s << std::endl << "It can only be used with"; if (it.runeLevel > 0) { s << " level " << it.runeLevel; } if (it.runeMagLevel > 0) { if (it.runeLevel > 0) { s << " and"; } s << " magic level " << it.runeMagLevel; } s << " or higher."; } } else if (it.weaponType != WEAPON_NONE) { if (it.weaponType == WEAPON_DIST && it.amuType != AMMO_NONE) { s << " (Range:" << it.shootRange; if (it.attack != 0) { s << ", Atk" << std::showpos << it.attack << std::noshowpos; } if (it.hitChance > 0) //excludes both cases it.hitchance 0 and -1 { s << ", Hit%" << std::showpos << it.hitChance << std::noshowpos; } s << ")"; } else if (it.weaponType != WEAPON_AMMO && it.weaponType != WEAPON_WAND) // Arrows and Bolts doesn't show atk { s << " ("; if (it.attack != 0) { s << "Atk:" << (int32_t)it.attack; if (it.abilities.elementDamage != 0) { s << " " << "physical + "; switch (it.abilities.elementType) { case COMBAT_ICEDAMAGE: s << it.abilities.elementDamage << " Ice,"; break; case COMBAT_EARTHDAMAGE: s << it.abilities.elementDamage << " Earth,"; break; case COMBAT_FIREDAMAGE: s << it.abilities.elementDamage << " Fire,"; break; case COMBAT_ENERGYDAMAGE: s << it.abilities.elementDamage << " Energy,"; break; default: s << it.abilities.elementDamage << " Unknown,"; break; } } } if (it.defense != 0 || it.extraDef != 0) { if (it.attack != 0) { s << " "; } s << "Def:" << (int32_t)it.defense; if (it.extraDef != 0) { s << " " << std::showpos << (int32_t)it.extraDef << std::noshowpos; } } if (it.abilities.stats[STAT_MAGICPOINTS] != 0) { if (it.attack != 0 || it.defense != 0 || it.extraDef != 0) { s << ", "; } s << "magic level " << std::showpos << (int32_t)it.abilities.stats[STAT_MAGICPOINTS] << std::noshowpos; } s << ")"; } if (it.showCharges) { if (subType > 1) { s << " that has " << (int32_t)subType << " charges left"; } else { s << " that has 1 charge left"; } } s << "."; } else if (it.armor != 0 || it.abilities.skill.any() || it.abilities.absorb.any() || it.abilities.stats[STAT_MAGICPOINTS] != 0 || it.abilities.speed != 0 || it.defense != 0) { if (it.showCharges) { if (subType > 1) { s << " that has " << (int32_t)subType << " charges left"; } else { s << " that has 1 charge left"; } } else if (it.showDuration) { if (item && item->hasAttribute(ATTR_ITEM_DURATION)) { int32_t duration = item->getDuration() / 1000; s << " that has energy for "; if (duration >= 120) { s << duration / 60 << " minutes left."; } else if (duration > 60) { s << "1 minute left."; } else { s << "less than a minute left."; } } else { s << " that is brand-new."; } } s << " ("; bool prevDesc = false; if (it.armor != 0) { // as it is the first desc it isn't // really necessary to add it here //if(prevDesc) // s << ", "; s << "Arm:" << it.armor; prevDesc = true; } if (it.abilities.skill.any()) { if (prevDesc) { s << ", "; } it.abilities.skill.getDescription(s); prevDesc = true; } if (it.abilities.absorb.any()) { if (prevDesc) { s << ", "; } s << "protection"; it.abilities.absorb.getDescription(s); prevDesc = true; } if (it.abilities.stats[STAT_MAGICPOINTS] != 0) { if (prevDesc) { s << ", "; } s << "magic level " << std::showpos << (int32_t)it.abilities.stats[STAT_MAGICPOINTS] << std::noshowpos; prevDesc = true; } if (it.defense != 0) { if (prevDesc) { s << ", "; } s << "defense " << std::showpos << (int32_t)it.defense << std::noshowpos; prevDesc = true; } if (it.abilities.speed != 0) { if (prevDesc) { s << ", "; } s << "speed " << std::showpos << (int32_t)(it.abilities.speed / 2) << std::noshowpos; // last desc... same thing as the first //prevDesc = true; } s << ")."; } else if (it.isFluidContainer()) { if (subType > 0) { s << " of " << items[subType].name << "."; } else { s << ". It is empty."; } } else if (it.isSplash()) { s << " of "; if (subType > 0) { s << items[subType].name << "."; } else { s << items[1].name << "."; } } else if (it.isContainer()) { s << " (Vol:" << (int32_t)it.maxItems << ")."; } else if (it.isKey()) { if (item) { s << " (Key:" << (int32_t)item->getActionId() << ")."; } else { s << " (Key:0)."; } } else if (it.allowDistRead) { s << std::endl; if (item && item->getText() != "") { if (lookDistance <= 4) { if (item->getWriter().length()) { s << item->getWriter() << " wrote"; time_t wDate = item->getWrittenDate(); if (wDate > 0) { char date[16]; formatDateShort(wDate, date); s << " on " << date; } s << ": "; } else { s << "You read: "; } s << item->getText(); } else { s << "You are too far away to read it."; } } else { s << "Nothing is written on it."; } } else if (it.isLevelDoor() && item && item->getActionId() >= 1000) { s << " for level " << item->getActionId() - 1000; } else if (it.showCharges) { if (subType > 1) { s << " that has " << (int32_t)subType << " charges left."; } else { s << " that has 1 charge left."; } } else if (it.showDuration) { if (item && item->hasAttribute(ATTR_ITEM_DURATION)) { int32_t duration = item->getDuration() / 1000; s << " that has energy for "; if (duration >= 120) { s << duration / 60 << " minutes left."; } else if (duration > 60) { s << "1 minute left."; } else { s << "less than a minute left."; } } else { s << " that is brand-new."; } } else { s << "."; } if (it.wieldInfo != 0) { s << std::endl << "It can only be wielded properly by "; if (it.wieldInfo & WIELDINFO_PREMIUM) { s << "premium "; } if (it.wieldInfo & WIELDINFO_VOCREQ) { s << it.vocationString; } else { s << "players"; } if (it.wieldInfo & WIELDINFO_LEVEL) { s << " of level " << (int32_t)it.minReqLevel << " or higher"; } if (it.wieldInfo & WIELDINFO_MAGLV) { if (it.wieldInfo & WIELDINFO_LEVEL) { s << " and"; } else { s << " of"; } s << " magic level " << (int32_t)it.minReqMagicLevel << " or higher"; } s << "."; } if (lookDistance <= 1) { double weight = (!item ? it.weight : item->getWeight()); if (weight > 0) { s << std::endl << getWeightDescription(it, weight); } } if (item && item->getSpecialDescription() != "") { s << std::endl << item->getSpecialDescription().c_str(); } else if (it.description.length() && lookDistance <= 1) { s << std::endl << it.description; } else if(it.isFluidContainer() && subType > 0 && items[subType].description.length() && lookDistance <= 1) { s << std::endl << items[subType].description; } return s.str(); }
bool ProtocolLogin::parseFirstPacket(NetworkMessage& msg) { if (g_game.getGameState() == GAME_STATE_SHUTDOWN) { getConnection()->closeConnection(); return false; } uint32_t clientip = getConnection()->getIP(); /*uint16_t clientos = */ msg.GetU16(); uint16_t version = msg.GetU16(); msg.SkipBytes(12); /* * Skipped bytes: * 12 bytes: dat, spr, pic signatures (4 bytes each) */ #ifdef __PROTOCOL_77__ if (!RSA_decrypt(msg)) { getConnection()->closeConnection(); return false; } uint32_t key[4]; key[0] = msg.GetU32(); key[1] = msg.GetU32(); key[2] = msg.GetU32(); key[3] = msg.GetU32(); enableXTEAEncryption(); setXTEAKey(key); #endif uint32_t accountName = msg.GetU32(); std::string password = msg.GetString(); if (version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX) { disconnectClient(0x0A, "Only clients with protocol " CLIENT_VERSION_STR " allowed!"); return false; } if (g_game.getGameState() == GAME_STATE_STARTUP) { disconnectClient(0x0A, "Gameworld is starting up. Please wait."); return false; } if (g_game.getGameState() == GAME_STATE_MAINTAIN) { disconnectClient(0x0A, "Gameworld is under maintenance. Please re-connect in a while."); return false; } BanInfo banInfo; if (IOBan::getInstance()->isIpBanned(clientip, banInfo)) { if (banInfo.reason.empty()) { banInfo.reason = "(none)"; } std::ostringstream ss; ss << "Your IP has been banned until " << formatDateShort(banInfo.expiresAt) << " by " << banInfo.bannedBy << ".\n\nReason specified:\n" << banInfo.reason; disconnectClient(0x0A, ss.str().c_str()); return false; } uint32_t serverip = serverIPs[0].first; for (uint32_t i = 0; i < serverIPs.size(); i++) { if ((serverIPs[i].first & serverIPs[i].second) == (clientip & serverIPs[i].second)) { serverip = serverIPs[i].first; break; } } if (!accountName) { disconnectClient(0x0A, "Invalid account id."); return false; } Account account; if (!IOLoginData::getInstance()->loginserverAuthentication(accountName, password, account)) { disconnectClient(0x0A, "Account id or password is not correct."); return false; } OutputMessage_ptr output = OutputMessagePool::getInstance()->getOutputMessage(this, false); if (output) { //Update premium days g_game.updatePremium(account); //Add MOTD output->AddByte(0x14); std::ostringstream ss; ss << g_game.getMotdNum() << "\n" << g_config.getString(ConfigManager::MOTD); output->AddString(ss.str()); //Add char list output->AddByte(0x64); output->AddByte((uint8_t)account.charList.size()); for (const std::string& characterName : account.charList) { output->AddString(characterName); if (g_config.getBoolean(ConfigManager::ON_OR_OFF_CHARLIST)) { if (g_game.getPlayerByName(characterName)) { output->AddString("Online"); } else { output->AddString("Offline"); } } else { output->AddString(g_config.getString(ConfigManager::SERVER_NAME)); } output->AddU32(serverip); output->AddU16(g_config.getNumber(ConfigManager::GAME_PORT)); } //Add premium days if (g_config.getBoolean(ConfigManager::FREE_PREMIUM)) { output->AddU16(0xFFFF); //client displays free premium } else { output->AddU16(account.premiumDays); } OutputMessagePool::getInstance()->send(output); } getConnection()->closeConnection(); return true; }
bool ProtocolLogin::parseFirstPacket(NetworkMessage& msg) { if(server.game().getGameState() == GAME_STATE_SHUTDOWN) { getConnection()->close(); return false; } uint32_t clientIp = getConnection()->getIP(); /*uint16_t operatingSystem = msg.GetU16();*/msg.SkipBytes(2); uint16_t version = msg.GetU16(); msg.SkipBytes(12); if(!RSA_decrypt(msg)) { getConnection()->close(); return false; } uint32_t key[4] = {msg.GetU32(), msg.GetU32(), msg.GetU32(), msg.GetU32()}; enableXTEAEncryption(); setXTEAKey(key); std::string name = msg.GetString(), password = msg.GetString(); if(name.empty()) { if(!server.configManager().getBool(ConfigManager::ACCOUNT_MANAGER)) { disconnectClient(0x0A, "Invalid account name."); return false; } name = "1"; password = "******"; } if(version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX) { disconnectClient(0x0A, CLIENT_VERSION_STRING); return false; } if(server.game().getGameState() < GAME_STATE_NORMAL) { disconnectClient(0x0A, "Server is just starting up, please wait."); return false; } if(server.game().getGameState() == GAME_STATE_MAINTAIN) { disconnectClient(0x0A, "Server is under maintenance, please re-connect in a while."); return false; } if(ConnectionManager::getInstance()->isDisabled(clientIp, protocolId)) { disconnectClient(0x0A, "Too many connections attempts from your IP address, please try again later."); return false; } if(IOBan::getInstance()->isIpBanished(clientIp)) { disconnectClient(0x0A, "Your IP is banished!"); return false; } uint32_t id = 1; if(!IOLoginData::getInstance()->getAccountId(name, id)) { ConnectionManager::getInstance()->addAttempt(clientIp, protocolId, false); disconnectClient(0x0A, "Invalid account name."); return false; } AccountP account = IOLoginData::getInstance()->loadAccount(id); if (account == nullptr) { disconnectClient(0x0A, "Invalid account name."); return false; } if(!encryptTest(password, account->getPassword())) { ConnectionManager::getInstance()->addAttempt(clientIp, protocolId, false); disconnectClient(0x0A, "Invalid password."); return false; } Ban ban; ban.value = account->getId(); ban.type = BAN_ACCOUNT; if(IOBan::getInstance()->getData(ban) && !IOLoginData::getInstance()->hasFlag(account->getId(), PlayerFlag_CannotBeBanned)) { bool deletion = ban.expires < 0; std::string name_ = "Automatic "; if(!ban.adminId) name_ += (deletion ? "deletion" : "banishment"); else IOLoginData::getInstance()->getNameByGuid(ban.adminId, name_, true); char buffer[500 + ban.comment.length()]; sprintf(buffer, "Your account has been %s at:\n%s by: %s,\nfor the following reason:\n%s.\nThe action taken was:\n%s.\nThe comment given was:\n%s.\nYour %s%s.", (deletion ? "deleted" : "banished"), formatDateShort(ban.added).c_str(), name_.c_str(), getReason(ban.reason).c_str(), getAction(ban.action, false).c_str(), ban.comment.c_str(), (deletion ? "account won't be undeleted" : "banishment will be lifted at:\n"), (deletion ? "." : formatDateShort(ban.expires, true).c_str())); disconnectClient(0x0A, buffer); return false; } const Account::Characters& characters = account->getCharacters(); if(!server.configManager().getBool(ConfigManager::ACCOUNT_MANAGER) && characters.empty()) { disconnectClient(0x0A, std::string("This account does not contain any character yet.\nCreate a new character on the " + server.configManager().getString(ConfigManager::SERVER_NAME) + " website at " + server.configManager().getString(ConfigManager::URL) + ".").c_str()); return false; } ConnectionManager::getInstance()->addAttempt(clientIp, protocolId, true); if(OutputMessage_ptr output = OutputMessagePool::getInstance()->getOutputMessage(this, false)) { TRACK_MESSAGE(output); output->AddByte(0x14); char motd[1300]; sprintf(motd, "%d\n%s", server.game().getMotdId(), server.configManager().getString(ConfigManager::MOTD).c_str()); output->AddString(motd); uint32_t serverIp = serverIps[0].first; for(IpList::iterator it = serverIps.begin(); it != serverIps.end(); ++it) { if((it->first & it->second) != (clientIp & it->second)) continue; serverIp = it->first; break; } //Add char list output->AddByte(0x64); if(server.configManager().getBool(ConfigManager::ACCOUNT_MANAGER) && id != 1) { output->AddByte(characters.size() + 1); output->AddString("Account Manager"); output->AddString(server.configManager().getString(ConfigManager::SERVER_NAME)); output->AddU32(serverIp); output->AddU16(server.configManager().getNumber(ConfigManager::GAME_PORT)); } else output->AddByte((uint8_t)characters.size()); for (auto it = characters.cbegin(); it != characters.cend(); ++it) { auto& character = *it; #ifndef __LOGIN_SERVER__ output->AddString(character->getName()); output->AddString(character->getType()); output->AddU32(serverIp); output->AddU16(server.configManager().getNumber(ConfigManager::GAME_PORT)); #else if(version < it->second->getVersionMin() || version > it->second->getVersionMax()) continue; output->AddString(it->first); output->AddString(it->second->getName()); output->AddU32(it->second->getAddress()); output->AddU16(it->second->getPort()); #endif } Days premiumDays = account->getPremiumDays(); if (premiumDays.count() >= std::numeric_limits<uint16_t>::max()) { output->AddU16(std::numeric_limits<uint16_t>::max()); } else { output->AddU16(static_cast<uint16_t>(premiumDays.count())); } OutputMessagePool::getInstance()->send(output); } getConnection()->close(); return true; }