-
Quem Está Navegando 0 membros estão online
Nenhum usuário registrado visualizando esta página.
-
Conteúdo Similar
-
Por llucas75
Oi galera tudo de boa?
Eu estou tentando colocar uma distro 0.4 no meu otserver(a do IgorPereira) mas ela só funciona se não tiver account manager.
Já coloquei no FALSE o account manager no config.lua, alguém sabe como remover ele do meu server?
(Eu exclui ele da database, mas ai só diz que ele não pode ser carregado).
-
Por Max willain
Fala galera tk
venho aqui tirar uma duvida sobre modern account
bom depois de criado eu posso apagar a account manager e Player sample ?bom quando o player cria uma conta ainda fica quando ele cria uma account pelo site quando ele vai longa fica aparecendo para ele longa na account manager ou na account sample eu posso apagar para evitar isto?
-
Por Digoshow
Gente estou com um problema aqui no meu Otserv, o problema é o seguinte, os player entra cria um char no Account Mananger, mais so que não consegue entrar no site, o meu config.lua ja esta em sha1, agora eu acho que eu devo arrumar algo no Gesior mais onde ou o que?
O outro problema é que o Account Manager que fica na lista da conta de um player não da pra logar, voce tentar logar o Account Manager que esta na lista de characters da sua conta, ele diz a frase ( Invalid Passowrd ) eu quero que de para logar.
E tem mais um problema que é o seguinte, chars criados agora no WebSite coloca la a opção da cidade pra nascer tudo certinho, nasce no templo da cidade, mais eu quero que o char nasce em outro lugar, o mesmo lugar que os characters criado pelo Account Manager nasce, alguem pode me ajudar?
Os feras que me ajudarem vou dar rep+, porque se me ajudarem merecem, REP+.
-
Por alun0n0v0
Galera Tudo bem, Estou com uma base para por online da KPDO, Porem deparei que não consigo logar na acc de adm do servidor e também não consigo criar o account manager, o servidor esta em sqlite e é Win, aguem sabe me dizer como posso corrigir esses 2 erros,é os unicos problemas que me empedem de Por o servidor online, se aguem puder me ajudar agradeço muito ❤️❤️❤️
-
Por Codex NG
Not completely tested and not all features are working but I am releasing this so that it is considered to be fixed and merged with the official branch.
Sql
INSERT INTO `players` (`id`, `name`, `group_id`, `account_id`, `level`, `vocation`, `health`, `healthmax`, `experience`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `lookaddons`, `maglevel`, `mana`, `manamax`, `manaspent`, `soul`, `town_id`, `posx`, `posy`, `posz`, `conditions`, `cap`, `sex`, `lastlogin`, `lastip`, `save`, `skull`, `skulltime`, `lastlogout`, `blessings`, `onlinetime`, `deletion`, `balance`, `offlinetraining_time`, `offlinetraining_skill`, `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`) VALUES (1, 'Account Manager', 1, 1, 1, 1, 150, 150, 0, 0, 0, 0, 0, 110, 0, 0, 0, 0, 0, 0, 1, 0, 0, 0, '', 40000, 1, 1535311649, 16777343, 1, 0, 0, 1535311709, 0, 2958, 0, 0, 43200, -1, 2520, 10, 0, 10, 0, 10, 0, 10, 0, 10, 0, 10, 0, 10, 0);
INSERT INTO `accounts` (`id`, `name`, `password`, `secret`, `type`, `premdays`, `lastday`, `vippoints`, `email`, `creation`) VALUES (1, '1', '356a192b7913b04c54574d18c28d46e6395428ab', NULL, 1, 365, 1535263046, '', '', 0);
configmanager.cpp
// account manager boolean[ACCOUNT_MANAGER] = getGlobalBoolean(L, "accountManager", true); integer[AM_LEVEL] = getGlobalNumber(L, "startLevel", 1); integer[AM_EXPERIENCE] = getGlobalNumber(L, "experience", 0); integer[AM_MAGLEVEL] = getGlobalNumber(L, "level", 0); integer[AM_FIST] = getGlobalNumber(L, "fist", 10); integer[AM_CLUB] = getGlobalNumber(L, "club", 10); integer[AM_SWORD] = getGlobalNumber(L, "sword", 10); integer[AM_AXE] = getGlobalNumber(L, "axe", 10); integer[AM_SHIELD] = getGlobalNumber(L, "shield", 10); integer[AM_DIST] = getGlobalNumber(L, "distance", 10); integer[AM_FISH] = getGlobalNumber(L, "fish", 10); integer[AM_SOUL] = getGlobalNumber(L, "soul", 100); integer[AM_BALANCE] = getGlobalNumber(L, "balance", 0); integer[AM_OFFLINE_TRAIN] = getGlobalNumber(L, "offlineTrainingTime", 0); integer[AM_STAMINA] = getGlobalNumber(L, "stamina", 0); integer[AM_LOOK_ADDONS] = getGlobalNumber(L, "lookAddons", 0); integer[AM_MOUNT_ID] = getGlobalNumber(L, "mountId", 0); integer[AM_TOWN_ID] = getGlobalNumber(L, "startTownId", 1); integer[AM_SPAWNPOS_X] = getGlobalNumber(L, "temple_x", 0); integer[AM_SPAWNPOS_Y] = getGlobalNumber(L, "temple_y", 0); integer[AM_SPAWNPOS_Z] = getGlobalNumber(L, "temple_z", 0); integer[AM_MAX_HP] = getGlobalNumber(L, "baseHP", 150); integer[AM_MAX_MP] = getGlobalNumber(L, "baseMP", 0); integer[AM_MAX_CAP] = getGlobalNumber(L, "baseCAP", 400); integer[AM_MALE] = getGlobalNumber(L, "maleOutfit", 128); integer[AM_FEMALE] = getGlobalNumber(L, "femaleOutfit", 136); boolean[AM_CHOOSEVOC] = getGlobalBoolean(L, "chooseVocation", false); boolean[AM_GENERATE_ACCOUNT_NUMBER] = getGlobalBoolean(L, "generateAccountNumber", false); // xml or lua boolean[USE_XML] = getGlobalBoolean(L, "useXml", false); configmanager.h
booleans
// account manager ACCOUNT_MANAGER, NAMELOCK_MANAGER, AM_CHOOSEVOC, AM_GENERATE_ACCOUNT_NUMBER, // -- // lua or xml USE_XML,
integers
// account manager AM_LEVEL, AM_EXPERIENCE, AM_MAGLEVEL, AM_FIST, AM_CLUB, AM_SWORD, AM_AXE, AM_SHIELD, AM_DIST, AM_FISH, AM_SOUL, AM_BALANCE, AM_OFFLINE_TRAIN, AM_STAMINA, AM_LOOK_ADDONS, AM_MOUNT_ID, AM_TOWN_ID, AM_SPAWNPOS_X, AM_SPAWNPOS_Y, AM_SPAWNPOS_Z, AM_MAX_HP, AM_MAX_MP, AM_MAX_CAP, AM_MALE, AM_FEMALE, // --
creature.h
// account manager virtual bool isAccountManager() const { return false; } // --
game.cpp
find this inside of Game:playerSay
uint32_t muteTime = player->isMuted(); if (muteTime > 0) { std::ostringstream ss; ss << "You are still muted for " << muteTime << " seconds."; player->sendTextMessage(MESSAGE_STATUS_SMALL, ss.str()); return; } and place this right underneath
// account manager if(player->isAccountManager()) { player->removeMessageBuffer(); internalCreatureSay(player, TALKTYPE_SAY, text, false); return; } // --
find this in Game::internalCreatureSay
if (text.empty()) { return false; } and place this above it
// account manager Player* player = creature->getPlayer(); if(player && player->isAccountManager()) { player->manageAccount(text); return true; } // --
add this to house.cpp
// account manager void House::updateDoorDescription(std::string _name/* = ""*/) { std::string tmp = "house"; /* no isGuild method (atm) if(isGuild()) tmp = "hall"; */ char houseDescription[200]; const int32_t housePrice = g_config.getNumber(ConfigManager::HOUSE_PRICE); if(owner) { /* if(isGuild()) IOGuild::getInstance()->getGuildById(_name, owner); */ if(_name.empty()) IOLoginData::getInstance()->getNameByGuid(owner, _name); sprintf(houseDescription, "It belongs to %s '%s'. %s owns this %s.", tmp.c_str(), houseName.c_str(), _name.c_str(), tmp.c_str()); } else sprintf(houseDescription, "It belongs to %s '%s'. Nobody owns this %s. It costs %lu gold coins.", tmp.c_str(), houseName.c_str(), tmp.c_str(), ( housePrice != -1 ? (houseTiles.size() * housePrice) : 0 ) ); for (const auto& it : doorSet) { it->setSpecialDescription(houseDescription); } } // --
house.h
find this void updateDoorDescription() const; and place this right underneath it
void updateDoorDescription(std::string _name = "");
iologindata.cpp
find this #include "game.h" and add this below it
// account manager #include "vocation.h" // --
find this extern Game g_game; and add this below it
// account manager extern Vocation g_vocations; // --
inside of this IOLoginData::loginserverAuthentication find this
result = db.storeQuery(query.str()); if (result) { do { if (result->getNumber<uint64_t>("deletion") == 0) { account.characters.push_back(result->getString("name")); } } while (result->next()); std::sort(account.characters.begin(), account.characters.end()); } return true; and replace it with this
result = db.storeQuery(query.str()); // account manager if(!result){ // give the account the account manager to use if they have no account account.characters.push_back("Account Manager"); return true; } // -- if (result) { // allow them to access the account manager if there are players on the account if (account.id != 1){ account.characters.push_back("Account Manager"); } do { if (result->getNumber<uint64_t>("deletion") == 0) { account.characters.push_back(result->getString("name")); } } while (result->next()); std::sort(account.characters.begin(), account.characters.end()); } return true;
add this
// account manager bool IOLoginData::getAccountId(const std::string& name, uint32_t& number) { if(!name.length()) return false; Database& db = Database::getInstance(); std::ostringstream query; query << "SELECT `id` FROM `accounts` WHERE `name` LIKE " << db.escapeString(name) << " LIMIT 1;"; DBResult_ptr result; if(!(result = db.storeQuery(query.str()))) return false; number = result->getNumber<uint32_t>("id"); return true; } // -- find this in IOLoginData::updateOnlineStatus
if (g_config.getBoolean(ConfigManager::ALLOW_CLONES)) { return; } and add this
// account manager if(g_config.getBoolean(ConfigManager::ACCOUNT_MANAGER)){ return; } // --
add this
// account manager bool IOLoginData::getNameByGuid(uint32_t guid, std::string& name) { std::ostringstream query; query << "SELECT `name` FROM `players` WHERE `id` = " << guid << " AND `deleted` = 0 LIMIT 1;"; DBResult_ptr result = Database::getInstance().storeQuery(query.str()); if (!result) { return false; } name = result->getString("name"); nameCacheMap[guid] = name; return true; } // -- Now add all these
// account manager bool IOLoginData::accountIdExists(uint32_t accountId) { Database& db = Database::getInstance(); std::ostringstream query; query << "SELECT `id` FROM `accounts` WHERE `id` = " << accountId << " LIMIT 1"; DBResult_ptr result = db.storeQuery(query.str()); if(!result) return false; return true; } bool IOLoginData::accountNameExists(const std::string& name) { Database& db = Database::getInstance(); std::ostringstream query; query << "SELECT `id` FROM `accounts` WHERE `name` LIKE " << db.escapeString(name) << " LIMIT 1"; DBResult_ptr result = db.storeQuery(query.str()); if(!result) return false; return true; } bool IOLoginData::getPassword(uint32_t accountId, std::string& password, std::string name/* = ""*/) { Database& db = Database::getInstance(); std::ostringstream query; query << "SELECT `password` FROM `accounts` WHERE `id` = " << accountId << " LIMIT 1"; DBResult_ptr result = db.storeQuery(query.str()); if(!result) return false; if(name.empty() || name == "Account Manager") { password = result->getString("password"); return true; } std::string tmpPassword = result->getString("password"); query.str(""); query << "SELECT `name` FROM `players` WHERE `account_id` = " << accountId; result = db.storeQuery(query.str()); if(!result) return false; do { if(result->getString("name") != name) continue; password = tmpPassword; return true; } while(result->next()); return false; } // accountId should be id because the server references the index and not the actual account data bool IOLoginData::setPassword(uint32_t accountId, std::string newPassword) { std::string ePassword = transformToSHA1(newPassword); Database& db = Database::getInstance(); std::ostringstream query; query << "UPDATE `accounts` SET `password` = " << db.escapeString(ePassword) << " WHERE `id` = " << accountId << ";"; return db.executeQuery(query.str()); } // not using recovery key atm but still good to have bool IOLoginData::validRecoveryKey(uint32_t accountId, std::string recoveryKey) { std::string nRecoveryKey = transformToSHA1(recoveryKey); Database& db = Database::getInstance(); std::ostringstream query; query << "SELECT `id` FROM `accounts` WHERE `id` = " << accountId << " AND `recoverykey` "; query << "LIKE " << db.escapeString(nRecoveryKey) << " LIMIT 1"; DBResult_ptr result = db.storeQuery(query.str()); if(!result) return false; return true; } bool IOLoginData::setRecoveryKey(uint32_t accountId, std::string newRecoveryKey) { std::string nRecoveryKey = transformToSHA1(newRecoveryKey); Database& db = Database::getInstance(); std::ostringstream query; std::cout << "account id " << accountId << std::endl; query << "UPDATE `accounts` SET `recoverykey` = " << db.escapeString(nRecoveryKey) << " WHERE `name` = " << accountId << ";"; return db.executeQuery(query.str()); } uint64_t IOLoginData::createAccount(std::string name, std::string password) { std::string ePassword = transformToSHA1(password); Database& db = Database::getInstance(); std::ostringstream query; query << "INSERT INTO `accounts` (`id`, `name`, `password`) VALUES (NULL, " << db.escapeString(name) << ", " << db.escapeString(ePassword) << ")"; if(!db.executeQuery(query.str())) return 0; return db.getLastInsertId(); } // not tested yet bool IOLoginData::changeName(uint32_t guid, std::string newName, std::string oldName) { Database& db = Database::getInstance(); std::ostringstream query; query << "INSERT INTO `player_namelocks` (`player_id`, `name`, `new_name`, `date`) VALUES ("<< guid << ", " << db.escapeString(oldName) << ", " << db.escapeString(newName) << ", " << time(NULL) << ")"; DBResult_ptr result = db.storeQuery(query.str()); if (!result) { return false; } query.str(""); query << "UPDATE `players` SET `name` = " << db.escapeString(newName) << " WHERE `id` = " << guid << " LIMIT 1"; result = db.storeQuery(query.str()); if (!result) { return false; } GuidCacheMap::iterator it = guidCacheMap.find(oldName); if(it != guidCacheMap.end()) { guidCacheMap.erase(it); guidCacheMap[newName] = guid; } nameCacheMap[guid] = newName; return true; } bool IOLoginData::createCharacter(uint32_t accountId, std::string characterName, uint32_t vocationId /*int32_t vocationId */, uint16_t sex) { if(playerExists(characterName)){ return false; } // a little bulky but whatever lol uint32_t healthMax = g_config.getNumber(ConfigManager::AM_MAX_HP); uint32_t manaMax = g_config.getNumber(ConfigManager::AM_MAX_MP); uint32_t capMax = g_config.getNumber(ConfigManager::AM_MAX_CAP); uint16_t lookType = (sex % 2) ? g_config.getNumber(ConfigManager::AM_MALE) : g_config.getNumber(ConfigManager::AM_FEMALE); uint16_t lookAddons = g_config.getNumber(ConfigManager::AM_LOOK_ADDONS); uint16_t magLevel = g_config.getNumber(ConfigManager::AM_MAGLEVEL); uint16_t townId = g_config.getNumber(ConfigManager::AM_TOWN_ID); uint16_t spawnX = g_config.getNumber(ConfigManager::AM_SPAWNPOS_X); uint16_t spawnY = g_config.getNumber(ConfigManager::AM_SPAWNPOS_Y); uint16_t spawnZ = g_config.getNumber(ConfigManager::AM_SPAWNPOS_Z); uint32_t level = g_config.getNumber(ConfigManager::AM_LEVEL); uint64_t exp = g_config.getNumber(ConfigManager::AM_EXPERIENCE); uint32_t fist = g_config.getNumber(ConfigManager::AM_FIST); uint32_t club = g_config.getNumber(ConfigManager::AM_CLUB); uint32_t sword = g_config.getNumber(ConfigManager::AM_SWORD); uint32_t axe = g_config.getNumber(ConfigManager::AM_AXE); uint32_t shield = g_config.getNumber(ConfigManager::AM_SHIELD); uint32_t dist = g_config.getNumber(ConfigManager::AM_DIST); uint32_t fish = g_config.getNumber(ConfigManager::AM_FISH); uint32_t soul = g_config.getNumber(ConfigManager::AM_SOUL); uint64_t balance = g_config.getNumber(ConfigManager::AM_BALANCE); int32_t offlineTrainingTime = g_config.getNumber(ConfigManager::AM_OFFLINE_TRAIN); uint16_t stamina = g_config.getNumber(ConfigManager::AM_STAMINA); if(level > 1){ exp += Player::getExpForLevel(level); healthMax *= level; manaMax *= level; capMax *= level; } Database& db = Database::getInstance(); std::string name = db.escapeString(characterName); std::ostringstream query, initialQuery, lastQuery, selectChar; // since character creation wants to use the account name when it setups up the player as the account id // we'll ask the database to get the id of the account since that is how the players are listed in the character list selectChar << "SELECT `id` FROM `accounts` WHERE `name` = " << accountId << ";"; DBResult_ptr result = db.storeQuery(selectChar.str()); if (!result){ return false; } accountId = result->getNumber<uint32_t>("id"); // this is to counteract the foreign key issue initialQuery << "SET FOREIGN_KEY_CHECKS=0;"; lastQuery << "SET FOREIGN_KEY_CHECKS=1;"; db.executeQuery(initialQuery.str()); query << "INSERT INTO `players` (`name`, `group_id`, `account_id`, `level`, `vocation`, `health`, `healthmax`, `experience`, `lookbody`, `lookfeet`, `lookhead`, `looklegs`, `looktype`, `lookaddons`, `maglevel`, `mana`, `manamax`, `manaspent`, `soul`, `town_id`, `posx`, `posy`, `posz`, `conditions`, `cap`, `sex`, `lastlogin`, `lastip`, `save`, `skull`, `skulltime`, `lastlogout`, `blessings`, `onlinetime`, `deletion`, `balance`, `offlinetraining_time`, `offlinetraining_skill`, `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`) VALUES (" << name << ", 1, " << accountId << ", " << level << ", " << vocationId << ", " << healthMax << ", " << healthMax << ", " << exp << ", 0, 0, 0, 0, " << lookType << ", " << lookAddons << ", " << magLevel << ", " << manaMax << ", " << manaMax << ", 0, " << soul << ", " << townId << ", " << spawnX << ", " << spawnY << ", " << spawnZ << ", 0x0, " << capMax << ", " << sex << ", 0, 0, 1, 0, 0, 0, 0, 0, 0, " << balance << ", " << offlineTrainingTime << ", -1, " << stamina << ", " << fist << ", 0, " << club << ", 0, " << sword << ", 0, " << axe << ", 0, " << dist << ", 0, " << shield << ", 0, " << fish << ", 0);"; if(db.executeQuery(query.str())){ db.executeQuery(lastQuery.str()); return true; } db.executeQuery(lastQuery.str()); return false; } // not tested DeleteCharacter_t IOLoginData::deleteCharacter(uint32_t accountId, const std::string characterName) { if(g_game.getPlayerByName(characterName)) return DELETE_ONLINE; Database& db = Database::getInstance(); std::ostringstream query; query << "SELECT `id` FROM `players` WHERE `name` LIKE " << db.escapeString(characterName) << " AND `account_id` = " << accountId << " AND `deleted` = 0 LIMIT 1"; DBResult_ptr result = db.storeQuery(query.str()); if(!result) return DELETE_INTERNAL; uint32_t id = result->getNumber<uint32_t>("id"); House* house = g_game.map.houses.getHouseByPlayerId(id); if(house) return DELETE_HOUSE; /* if(IOGuild::getInstance()->getGuildLevel(id) == 3) return DELETE_LEADER; */ query.str(""); query << "UPDATE `players` SET `deleted` = 1 WHERE `id` = " << id << ";"; if(!db.executeQuery(query.str())) return DELETE_INTERNAL; query.str(""); query << "DELETE FROM `guild_invites` WHERE `player_id` = " << id; db.executeQuery(query.str()); query.str(""); query << "DELETE FROM `player_viplist` WHERE `vip_id` = " << id; db.executeQuery(query.str()); /* for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it) { VIPListSet::iterator it_ = it->second->VIPList.find(id); if(it_ != it->second->VIPList.end()) it->second->VIPList.erase(it_); } */ return DELETE_SUCCESS; } bool IOLoginData::playerExists(uint32_t guid, bool multiworld /*= false*/, bool checkCache /*= true*/) { if(checkCache) { NameCacheMap::iterator it = nameCacheMap.find(guid); if(it != nameCacheMap.end()) return true; } Database& db = Database::getInstance(); std::ostringstream query; query << "SELECT `name` FROM `players` WHERE `id` = " << guid << " AND `deleted` = 0"; query << " LIMIT 1"; DBResult_ptr result = db.storeQuery(query.str()); if(!result) return false; const std::string name = result->getString("name"); nameCacheMap[guid] = name; return true; } bool IOLoginData::playerExists(std::string& name, bool multiworld /*= false*/, bool checkCache /*= true*/) { if(checkCache) { GuidCacheMap::iterator it = guidCacheMap.find(name); if(it != guidCacheMap.end()) { name = it->first; return true; } } Database& db = Database::getInstance(); std::ostringstream query; query << "SELECT `id`, `name` FROM `players` WHERE `name` LIKE " << db.escapeString(name); /*<< " AND `deleted` = 0"; */ query << " LIMIT 1"; DBResult_ptr result = db.storeQuery(query.str()); if(!result) return false; name = result->getString("name"); guidCacheMap[name] = result->getNumber<int32_t>("id"); return true; } // --
iologindata.h
find this #include "database.h" and place this right underneath
// account manager enum DeleteCharacter_t { DELETE_INTERNAL, DELETE_LEADER, DELETE_HOUSE, DELETE_ONLINE, DELETE_SUCCESS }; // --
find this
class IOLoginData { public: and add this under it
// account manager virtual ~IOLoginData() {} static IOLoginData* getInstance() { static IOLoginData instance; return &instance; } // -- find this static AccountType_t getAccountType(uint32_t accountId); and place this right below it
// account manager bool accountIdExists(uint32_t accountId); bool accountNameExists(const std::string& name); bool getAccountId(const std::string& name, uint32_t& number); bool getNameByGuid(uint32_t guid, std::string& name); bool playerExists(uint32_t guid, bool multiworld = false, bool checkCache = true); bool playerExists(std::string& name, bool multiworld = false, bool checkCache = true); bool changeName(uint32_t guid, std::string newName, std::string oldName); bool createCharacter(uint32_t accountId, std::string characterName, uint32_t vocationId /* int32_t vocationId */, uint16_t sex); DeleteCharacter_t deleteCharacter(uint32_t accountId, const std::string characterName); bool getPassword(uint32_t accountId, std::string& password, std::string name = ""); bool setPassword(uint32_t accountId, std::string newPassword); bool validRecoveryKey(uint32_t accountId, std::string recoveryKey); bool setRecoveryKey(uint32_t accountId, std::string newRecoveryKey); uint64_t createAccount(std::string name, std::string password); // -- find this static void removePremiumDays(uint32_t accountId, int32_t removeDays); and place this right below it
// account manager protected: struct StringCompareCase { bool operator()(const std::string& l, const std::string& r) const { return strcasecmp(l.c_str(), r.c_str()) < 0; } }; typedef std::map<std::string, uint32_t, StringCompareCase> GuidCacheMap; GuidCacheMap guidCacheMap; typedef std::map<uint32_t, std::string> NameCacheMap; NameCacheMap nameCacheMap; // --
luascript.cpp
find this registerEnum(ZONE_NORMAL) and place this underneath
// account manager registerEnum(MANAGER_NONE) registerEnum(MANAGER_NEW) registerEnum(MANAGER_ACCOUNT) registerEnum(MANAGER_NAMELOCK) // --
find this registerMethod("Player", "getLastLogout", LuaScriptInterface::luaPlayerGetLastLogout);
and place this right underneath
// account manager registerMethod("Player", "getAccountManager", LuaScriptInterface::luaGetPlayerAccountManager); // --
find this
int LuaScriptInterface::luaPlayerGetLastLogout(lua_State* L) { // player:getLastLogout() Player* player = getUserdata<Player>(L, 1); if (player) { lua_pushnumber(L, player->getLastLogout()); } else { lua_pushnil(L); } return 1; } and place this under it
int32_t LuaScriptInterface::luaGetPlayerAccountManager(lua_State* L) { // player:getAccountManager() Player* player = getUserdata<Player>(L, 1); if (player) { lua_pushnumber(L, player->accountManager); } else { lua_pushnil(L); } return 1; } luascript.h
find this static int luaPlayerGetLastLogout(lua_State* L); and place this under it
// account manager static int luaGetPlayerAccountManager(lua_State* L); // -- map.cpp
look for bool Map:placeCreature(const Position& centerPos, Creature* creature, bool extendedPos/* = false*/, bool forceLogin/* = false*/)
look for this
Tile* tile = getTile(centerPos.x, centerPos.y, centerPos.z); if (tile) { placeInPZ = tile->hasFlag(TILESTATE_PROTECTIONZONE); ReturnValue ret = tile->queryAdd(0, *creature, 1, FLAG_IGNOREBLOCKITEM); foundTile = forceLogin || ret == RETURNVALUE_NOERROR || ret == RETURNVALUE_PLAYERISNOTINVITED; } else { placeInPZ = false; foundTile = false; } and replace it with this
Tile* tile = getTile(centerPos.x, centerPos.y, centerPos.z); if (tile) { placeInPZ = tile->hasFlag(TILESTATE_PROTECTIONZONE); // account manager uint32_t flags = FLAG_IGNOREBLOCKITEM; if(creature->isAccountManager()) flags |= FLAG_IGNOREBLOCKCREATURE; // -- ReturnValue ret = tile->queryAdd(0, *creature, 1, flags); foundTile = forceLogin || ret == RETURNVALUE_NOERROR || ret == RETURNVALUE_PLAYERISNOTINVITED; } else { placeInPZ = false; foundTile = false; }
player.cpp
find this #include <bitset>
and place this under it
// account manager #include "ban.h" // --
look for this
Player::Player(ProtocolGame_ptr p) : Creature(), lastPing(OTSYS_TIME()), lastPong(lastPing), inbox(new Inbox(ITEM_INBOX)), client(std::move(p)) { inbox->incrementReferenceCounter(); } and replace it with this
Player::Player(ProtocolGame_ptr p) : Creature(), lastPing(OTSYS_TIME()), lastPong(lastPing), inbox(new Inbox(ITEM_INBOX)), client(std::move(p)) { // account manager for(int8_t i = 0; i <= states; i++) { talkState[i] = false; } accountManager = MANAGER_NONE; // -- inbox->incrementReferenceCounter(); }
add this
// account manager void Player::manageAccount(const std::string &text) { std::stringstream msg; msg << "Account Manager: "; bool noSwap = true; switch(accountManager) { case MANAGER_NAMELOCK: { if(!talkState[1]) { managerString = text; trimString(managerString); if(managerString.length() < 4) msg << "Your name you want is too short, please select a longer name."; else if(managerString.length() > 20) msg << "The name you want is too long, please select a shorter name."; else if(!isValidName(managerString)) msg << "That name seems to contain invalid symbols, please choose another name."; else if(IOLoginData::getInstance()->playerExists(managerString, true)) msg << "A player with that name already exists, please choose another name."; else { std::string tmp = asLowerCaseString(managerString); if(tmp.substr(0, 4) != "god " && tmp.substr(0, 3) != "cm " && tmp.substr(0, 3) != "gm ") { talkState[1] = true; talkState[2] = true; msg << managerString << ", are you sure?"; } else msg << "Your character is not a staff member, please tell me another name!"; } } else if(checkText(text, "no") && talkState[2]) { talkState[1] = talkState[2] = false; msg << "What else would you like to name your character?"; } else if(checkText(text, "yes") && talkState[2]) { if(!IOLoginData::getInstance()->playerExists(managerString, true)) { uint32_t tmp = IOLoginData::getInstance()->getGuidByName(managerString2); if(tmp != 0 && IOLoginData::getInstance()->changeName(tmp, managerString, managerString2) && IOBan::isPlayerNamelocked(tmp)) { if(House* house = g_game.map.houses.getHouseByPlayerId(tmp)) house->updateDoorDescription(managerString); talkState[1] = true; talkState[2] = false; msg << "Your character has been successfully renamed, you should now be able to login at it without any problems."; } else { talkState[1] = talkState[2] = false; msg << "Failed to change your name, please try again."; } } else { talkState[1] = talkState[2] = false; msg << "A player with that name already exists, please choose another name."; } } else msg << "Sorry, but I can't understand you, please try to repeat that!"; break; } case MANAGER_ACCOUNT: { // pr(" manage account case ", managerNumber); Account account = IOLoginData::getInstance()->loadAccount(managerNumber); if(checkText(text, "cancel") || (checkText(text, "account") && !talkState[1])) { talkState[1] = true; for(int8_t i = 2; i <= 12; i++) talkState[i] = false; msg << "Do you want to change your 'password', add a 'character', or 'delete' a character?"; } else if(checkText(text, "delete") && talkState[1]) { talkState[1] = false; talkState[2] = true; msg << "Which character would you like to delete?"; } else if(talkState[2]) { std::string tmp = text; trimString(tmp); if(!isValidName(tmp, false)) msg << "That name contains invalid characters, try to say your name again, you might have typed it wrong."; else { talkState[2] = false; talkState[3] = true; managerString = tmp; msg << "Do you really want to delete the character named " << managerString << "?"; } } else if(checkText(text, "yes") && talkState[3]) { switch(IOLoginData::getInstance()->deleteCharacter(managerNumber, managerString)) { case DELETE_INTERNAL: msg << "An error occured while deleting your character. Either the character does not belong to you or it doesn't exist."; break; case DELETE_SUCCESS: msg << "Your character has been deleted."; break; case DELETE_HOUSE: msg << "Your character owns a house. To make sure you really want to lose your house by deleting your character, you have to login and leave the house or pass it to someone else first."; break; case DELETE_LEADER: msg << "Your character is the leader of a guild. You need to disband or pass the leadership someone else to delete your character."; break; case DELETE_ONLINE: msg << "A character with that name is currently online, to delete a character it has to be offline."; break; } talkState[1] = true; for(int8_t i = 2; i <= 12; i++) talkState[i] = false; } else if(checkText(text, "no") && talkState[3]) { talkState[1] = true; talkState[3] = false; msg << "Tell me what character you want to delete."; } else if(checkText(text, "password") && talkState[1]) { talkState[1] = false; talkState[4] = true; msg << "Tell me your new password please."; } else if(talkState[4]) { std::string tmp = text; trimString(tmp); if(tmp.length() < 6) msg << "That password is too short, at least 6 digits are required. Please select a longer password."; else if(!isValidPassword(tmp)) msg << "Your password contains invalid characters... please tell me another one."; else { talkState[4] = false; talkState[5] = true; managerString = tmp; msg << "Should '" << managerString << "' be your new password?"; } } else if(checkText(text, "yes") && talkState[5]) { talkState[1] = true; for(int8_t i = 2; i <= 12; i++) talkState[i] = false; IOLoginData::getInstance()->setPassword(managerNumber, managerString); msg << "Your password has been changed."; } else if(checkText(text, "no") && talkState[5]) { talkState[1] = true; for(int8_t i = 2; i <= 12; i++) talkState[i] = false; msg << "Then not."; } else if(checkText(text, "character") && talkState[1]) { if(account.characters.size() <= 15) { talkState[1] = false; talkState[6] = true; msg << "What would you like as your character name?"; } else { talkState[1] = true; for(int8_t i = 2; i <= 12; i++) talkState[i] = false; msg << "Your account reach the limit of 15 players, you can 'delete' a character if you want to create a new one."; } } else if(talkState[6]) { managerString = text; trimString(managerString); if(managerString.length() < 4) msg << "Your name you want is too short, please select a longer name."; else if(managerString.length() > 20) msg << "The name you want is too long, please select a shorter name."; else if(!isValidName(managerString)) msg << "That name seems to contain invalid symbols, please choose another name."; else if(IOLoginData::getInstance()->playerExists(managerString, true)) msg << "A player with that name already exists, please choose another name."; else { std::string tmp = asLowerCaseString(managerString); if(tmp.substr(0, 4) != "god " && tmp.substr(0, 3) != "cm " && tmp.substr(0, 3) != "gm ") { talkState[6] = false; talkState[7] = true; msg << managerString << ", are you sure?"; } else msg << "Your character is not a staff member, please tell me another name!"; } } else if(checkText(text, "no") && talkState[7]) { talkState[6] = true; talkState[7] = false; msg << "What else would you like to name your character?"; } else if(checkText(text, "yes") && talkState[7]) { talkState[7] = false; talkState[8] = true; msg << "Should your character be a 'male' or a 'female'."; } else if(talkState[8] && (checkText(text, "female") || checkText(text, "male"))) { talkState[8] = false; talkState[9] = true; if(checkText(text, "female")) { msg << "A female, are you sure?"; managerSex = PLAYERSEX_FEMALE; } else { msg << "A male, are you sure?"; managerSex = PLAYERSEX_MALE; } } else if(checkText(text, "no") && talkState[9]) { talkState[8] = true; talkState[9] = false; msg << "Tell me... would you like to be a 'male' or a 'female'?"; } else if(checkText(text, "yes") && talkState[9]) { if(g_config.getBoolean(ConfigManager::AM_CHOOSEVOC)) { talkState[9] = false; talkState[11] = true; bool firstPart = true; g_vocations.getVocationMap(firstPart, msg); } else if(!IOLoginData::getInstance()->playerExists(managerString, true)) { talkState[1] = true; for(int8_t i = 2; i <= 12; i++) talkState[i] = false; if(IOLoginData::getInstance()->createCharacter(managerNumber, managerString, managerNumber2, (uint16_t)managerSex)) msg << "Your character has been created."; else msg << "Your character couldn't be created, please try again."; } else { talkState[6] = true; talkState[9] = false; msg << "A player with that name already exists, please choose another name."; } } else if(talkState[11]) { g_vocations.getVocationConfirmation(text, talkState[11], talkState[12], managerNumber2, msg); if(msg.str().length() == 17) msg << "I don't understand what vocation you would like to be... could you please repeat it?"; } else if(checkText(text, "yes") && talkState[12]) { if(!IOLoginData::getInstance()->playerExists(managerString, true)) { talkState[1] = true; for(int8_t i = 2; i <= 12; i++) talkState[i] = false; if(IOLoginData::getInstance()->createCharacter(managerNumber, managerString, managerNumber2, (uint16_t)managerSex)) msg << "Your character has been created."; else msg << "Your character couldn't be created, please try again."; } else { talkState[6] = true; talkState[9] = false; msg << "A player with that name already exists, please choose another name."; } } else if(checkText(text, "no") && talkState[12]) { talkState[11] = true; talkState[12] = false; msg << "No? Then what would you like to be?"; } else if(checkText(text, "recovery key") && talkState[1]) { talkState[1] = false; talkState[10] = true; msg << "Would you like a recovery key?"; } else if(checkText(text, "yes") && talkState[10]) { // std::cout << "recovery key " << account.recoveryKey << " empty? " << account.recoveryKey.empty() <<std::endl; /* if(!account.recoveryKey.empty()) msg << "Sorry, you already have a recovery key, for security reasons I may not give you a new one."; else { managerString = generateRecoveryKey(4, 4); IOLoginData::getInstance()->setRecoveryKey(managerNumber, managerString); msg << "Your recovery key is: " << managerString << "."; } */ talkState[1] = true; for(int8_t i = 2; i <= 12; i++) talkState[i] = false; } else if(checkText(text, "no") && talkState[10]) { msg << "Then not."; talkState[1] = true; for(int8_t i = 2; i <= 12; i++) talkState[i] = false; } else msg << "Please read the latest message that I have specified, I don't understand the current requested action."; break; } case MANAGER_NEW: { if(checkText(text, "account") && !talkState[1]) { msg << "What would you like your password to be?"; talkState[1] = true; talkState[2] = true; } else if(talkState[2]) { std::string tmp = text; trimString(tmp); if(tmp.length() < 6) msg << "That password is too short, at least 6 digits are required. Please select a longer password."; else if(!isValidPassword(tmp)) msg << "Your password contains invalid characters... please tell me another one."; else { talkState[3] = true; talkState[2] = false; managerString = tmp; msg << managerString << " is it? 'yes' or 'no'?"; } } else if(checkText(text, "yes") && talkState[3]) { if(g_config.getBoolean(ConfigManager::AM_GENERATE_ACCOUNT_NUMBER)) { do sprintf(managerChar, "%d%d%d%d%d%d%d", random_range(2, 9), random_range(2, 9), random_range(2, 9), random_range(2, 9), random_range(2, 9), random_range(2, 9), random_range(2, 9)); while(IOLoginData::getInstance()->accountNameExists(managerChar)); uint32_t id = (uint32_t)IOLoginData::getInstance()->createAccount(managerChar, managerString); if(id) { accountManager = MANAGER_ACCOUNT; managerNumber = id; noSwap = talkState[1] = false; msg << "Your account has been created, you may manage it now, but remember your account name: '" << managerChar << "' and password: '" << managerString << "'! If the account name is too hard to remember, please note it somewhere."; } else msg << "Your account could not be created, please try again."; for(int8_t i = 2; i <= 5; i++) talkState[i] = false; } else { msg << "What would you like your account name to be?"; talkState[3] = false; talkState[4] = true; } } else if(checkText(text, "no") && talkState[3]) { talkState[2] = true; talkState[3] = false; msg << "What would you like your password to be then?"; } else if(talkState[4]) { std::string tmp = text; trimString(tmp); if(tmp.length() < 3) msg << "That account name is too short, at least 3 digits are required. Please select a longer account name."; else if(tmp.length() > 25) msg << "That account name is too long, not more than 25 digits are required. Please select a shorter account name."; else if(!isValidAccountName(tmp)) msg << "Your account name contains invalid characters, please choose another one."; else if(asLowerCaseString(tmp) == asLowerCaseString(managerString)) msg << "Your account name cannot be same as password, please choose another one."; else { sprintf(managerChar, "%s", tmp.c_str()); msg << managerChar << ", are you sure?"; talkState[4] = false; talkState[5] = true; } } else if(checkText(text, "yes") && talkState[5]) { if(!IOLoginData::getInstance()->accountNameExists(managerChar)) { uint32_t id = (uint32_t)IOLoginData::getInstance()->createAccount(managerChar, managerString); if(id) { accountManager = MANAGER_ACCOUNT; managerNumber = id; noSwap = talkState[1] = false; msg << "Your account has been created, you may manage it now, but remember your account name: '" << managerChar << "' and password: '" << managerString << "'!"; } else msg << "Your account could not be created, please try again."; for(int8_t i = 2; i <= 5; i++) talkState[i] = false; } else { msg << "An account with that name already exists, please try another account name."; talkState[4] = true; talkState[5] = false; } } else if(checkText(text, "no") && talkState[5]) { talkState[5] = false; talkState[4] = true; msg << "What else would you like as your account name?"; } else if(checkText(text, "recover") && !talkState[6]) { talkState[6] = true; talkState[7] = true; msg << "What was your account name?"; } else if(talkState[7]) { managerString = text; if(IOLoginData::getInstance()->getAccountId(managerString, (uint32_t&)managerNumber)) { talkState[7] = false; talkState[8] = true; msg << "What was your recovery key?"; } else { msg << "Sorry, but account with such name doesn't exists."; talkState[6] = talkState[7] = false; } } else if(talkState[8]) { managerString2 = text; if(IOLoginData::getInstance()->validRecoveryKey(managerNumber, managerString2) && managerString2 != "0") { sprintf(managerChar, "%s%d", g_config.getString(ConfigManager::SERVER_NAME).c_str(), random_range(100, 999)); IOLoginData::getInstance()->setPassword(managerNumber, managerChar); msg << "Correct! Your new password is: " << managerChar << "."; } else msg << "Sorry, but this key doesn't match to account you gave me."; talkState[7] = talkState[8] = false; } else msg << "Sorry, but I can't understand you, please try to repeat that."; break; } default: return; break; } sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, msg.str().c_str()); if(!noSwap) sendTextMessage(MESSAGE_STATUS_CONSOLE_ORANGE, "Hint: Type 'account' to manage your account and if you want to start over then type 'cancel'."); } // -- player.h
find class Guild; and add this below it
// account manager enum AccountManager_t { MANAGER_NONE, MANAGER_NEW, MANAGER_ACCOUNT, MANAGER_NAMELOCK }; // -- next find this void addList() override; and add this below
// account manager void manageAccount(const std::string& text); bool isAccountManager() const {return (accountManager != MANAGER_NONE);} template <typename T> inline void pr(std::string s, T const& v) { std::cout << s << v << std::endl; }; // -- find this
void disconnect() { if (client) { client->disconnect(); } } place this under it
// account manager bool isVirtual() const { return (getID() == 0); } // -- find this int32_t idleTime = 0;
and place this below it
// account manager int32_t managerNumber; uint32_t managerNumber2; std::string managerString, managerString2; int8_t states = 13; bool talkState[13]; // -- find this OperatingSystem_t operatingSystem = CLIENTOS_NONE;
and place this below it
// account manager AccountManager_t accountManager = MANAGER_NONE; PlayerSex_t managerSex; char managerChar[100]; // -- protocolgame.cpp
find this void ProtocolGame::login(const std::string& name, uint32_t accountId, OperatingSystem_t operatingSystem)
find this
void ProtocolGame::login(const std::string& name, uint32_t accountId, OperatingSystem_t operatingSystem) { //dispatcher thread Player* foundPlayer = g_game.getPlayerByName(name); if (!foundPlayer || g_config.getBoolean(ConfigManager::ALLOW_CLONES)) { player = new Player(getThis()); player->setName(name); player->incrementReferenceCounter(); player->setID(); if (!IOLoginData::preloadPlayer(player, name)) { disconnectClient("Your character could not be loaded."); return; } if (IOBan::isPlayerNamelocked(player->getGUID())) { disconnectClient("Your character has been namelocked."); return; } and replace it with this
void ProtocolGame::login(const std::string& name, uint32_t accountId, OperatingSystem_t operatingSystem) { //dispatcher thread Player* foundPlayer = g_game.getPlayerByName(name); if(!foundPlayer || name == "Account Manager" || g_config.getBoolean(ConfigManager::ALLOW_CLONES) ) { player = new Player(getThis()); player->setName(name); player->incrementReferenceCounter(); player->setID(); if (!IOLoginData::preloadPlayer(player, name)) { disconnectClient("Your character could not be loaded."); return; } if (IOBan::isPlayerNamelocked(player->getGUID()) && accountId != 1) { if(g_config.getBoolean(ConfigManager::NAMELOCK_MANAGER)) { player->name = "Account Manager"; player->accountManager = MANAGER_NAMELOCK; player->managerNumber = accountId; player->managerString2 = name; } else { disconnectClient("Your character has been namelocked."); return; } }else if(player->getName() == "Account Manager" && g_config.getBoolean(ConfigManager::ACCOUNT_MANAGER)) { if(accountId != 1) { player->accountManager = MANAGER_ACCOUNT; player->managerNumber = accountId; } else { player->accountManager = MANAGER_NEW; } } in that same method underneath this
if (g_game.getGameState() == GAME_STATE_CLOSING && !player->hasFlag(PlayerFlag_CanAlwaysLogin)) { disconnectClient("The game is just going down.\nPlease try again later."); return; } if (g_game.getGameState() == GAME_STATE_CLOSED && !player->hasFlag(PlayerFlag_CanAlwaysLogin)) { disconnectClient("Server is currently closed.\nPlease try again later."); return; } place this
// account manager if (g_config.getBoolean(ConfigManager::ONE_PLAYER_ON_ACCOUNT) && !player->isAccountManager() && player->getAccountType() < ACCOUNT_TYPE_GAMEMASTER && g_game.getPlayerByAccount(player->getAccount())) { bool found = false; std::vector<Player*> tmp; tmp.push_back(g_game.getPlayerByAccount(accountId)); for(std::vector<Player*>::iterator it = tmp.begin(); it != tmp.end(); ++it) { if((*it)->getName() != name) continue; found = true; break; } if(tmp.size() > 0 && !found) { disconnectClient("You may only login with one character\nof your account at the same time."); return; } } // -- find this void ProtocolGame::onRecvFirstMessage(NetworkMessage& msg)
inside of there you are going to look for this
std::string& token = sessionArgs[2]; uint32_t tokenTime = 0; try { tokenTime = std::stoul(sessionArgs[3]); } catch (const std::invalid_argument&) { disconnectClient("Malformed token packet."); return; } catch (const std::out_of_range&) { disconnectClient("Token time is too long."); return; } if (accountName.empty()) { disconnectClient("You must enter your account name."); return; } replace it with this
// account manager if (accountName.empty()) { accountName = "1"; } if (password.empty()) { password = "1"; } // -- within that same method you will look for this
uint32_t accountId = IOLoginData::gameworldAuthentication(accountName, password, characterName, token, tokenTime); if (accountId == 0) { disconnectClient("Account name or password is not correct."); return; } g_dispatcher.addTask(createTask(std::bind(&ProtocolGame::login, getThis(), characterName, accountId, operatingSystem))); } and replace it with this
uint32_t accountId = atoi(accountName.c_str()); g_dispatcher.addTask(createTask(std::bind(&ProtocolGame::login, getThis(), characterName, accountId, operatingSystem))); }
this whole method you are going to replace void ProtocolGame::parsePacket(NetworkMessage& msg)
void ProtocolGame::parsePacket(NetworkMessage& msg) { if (!acceptPackets || g_game.getGameState() == GAME_STATE_SHUTDOWN || msg.getLength() <= 0) { return; } uint8_t recvbyte = msg.getByte(); if (!player) { if (recvbyte == 0x0F) { disconnect(); } return; } //a dead player can not performs actions if (player->isRemoved() || player->getHealth() <= 0) { if (recvbyte == 0x0F) { disconnect(); return; } if (recvbyte != 0x14) { return; } } // account manager if(player->isAccountManager()) { switch(recvbyte) { case 0x14: g_dispatcher.addTask(createTask(std::bind(&ProtocolGame::logout, getThis(), true, false))); break; break; case 0x96: parseSay(msg); break; default: sendCancelWalk(); break; } } else { // -- switch (recvbyte) { case 0x14: g_dispatcher.addTask(createTask(std::bind(&ProtocolGame::logout, getThis(), true, false))); break; case 0x1D: addGameTask(&Game::playerReceivePingBack, player->getID()); break; case 0x1E: addGameTask(&Game::playerReceivePing, player->getID()); break; case 0x32: parseExtendedOpcode(msg); break; //otclient extended opcode case 0x64: parseAutoWalk(msg); break; case 0x65: addGameTask(&Game::playerMove, player->getID(), DIRECTION_NORTH); break; case 0x66: addGameTask(&Game::playerMove, player->getID(), DIRECTION_EAST); break; case 0x67: addGameTask(&Game::playerMove, player->getID(), DIRECTION_SOUTH); break; case 0x68: addGameTask(&Game::playerMove, player->getID(), DIRECTION_WEST); break; case 0x69: addGameTask(&Game::playerStopAutoWalk, player->getID()); break; case 0x6A: addGameTask(&Game::playerMove, player->getID(), DIRECTION_NORTHEAST); break; case 0x6B: addGameTask(&Game::playerMove, player->getID(), DIRECTION_SOUTHEAST); break; case 0x6C: addGameTask(&Game::playerMove, player->getID(), DIRECTION_SOUTHWEST); break; case 0x6D: addGameTask(&Game::playerMove, player->getID(), DIRECTION_NORTHWEST); break; case 0x6F: addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerTurn, player->getID(), DIRECTION_NORTH); break; case 0x70: addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerTurn, player->getID(), DIRECTION_EAST); break; case 0x71: addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerTurn, player->getID(), DIRECTION_SOUTH); break; case 0x72: addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerTurn, player->getID(), DIRECTION_WEST); break; case 0x77: parseEquipObject(msg); break; case 0x78: parseThrow(msg); break; case 0x79: parseLookInShop(msg); break; case 0x7A: parsePlayerPurchase(msg); break; case 0x7B: parsePlayerSale(msg); break; case 0x7C: addGameTask(&Game::playerCloseShop, player->getID()); break; case 0x7D: parseRequestTrade(msg); break; case 0x7E: parseLookInTrade(msg); break; case 0x7F: addGameTask(&Game::playerAcceptTrade, player->getID()); break; case 0x80: addGameTask(&Game::playerCloseTrade, player->getID()); break; case 0x82: parseUseItem(msg); break; case 0x83: parseUseItemEx(msg); break; case 0x84: parseUseWithCreature(msg); break; case 0x85: parseRotateItem(msg); break; case 0x87: parseCloseContainer(msg); break; case 0x88: parseUpArrowContainer(msg); break; case 0x89: parseTextWindow(msg); break; case 0x8A: parseHouseWindow(msg); break; case 0x8C: parseLookAt(msg); break; case 0x8D: parseLookInBattleList(msg); break; case 0x8E: /* join aggression */ break; case 0x96: parseSay(msg); break; case 0x97: addGameTask(&Game::playerRequestChannels, player->getID()); break; case 0x98: parseOpenChannel(msg); break; case 0x99: parseCloseChannel(msg); break; case 0x9A: parseOpenPrivateChannel(msg); break; case 0x9E: addGameTask(&Game::playerCloseNpcChannel, player->getID()); break; case 0xA0: parseFightModes(msg); break; case 0xA1: parseAttack(msg); break; case 0xA2: parseFollow(msg); break; case 0xA3: parseInviteToParty(msg); break; case 0xA4: parseJoinParty(msg); break; case 0xA5: parseRevokePartyInvite(msg); break; case 0xA6: parsePassPartyLeadership(msg); break; case 0xA7: addGameTask(&Game::playerLeaveParty, player->getID()); break; case 0xA8: parseEnableSharedPartyExperience(msg); break; case 0xAA: addGameTask(&Game::playerCreatePrivateChannel, player->getID()); break; case 0xAB: parseChannelInvite(msg); break; case 0xAC: parseChannelExclude(msg); break; case 0xBE: addGameTask(&Game::playerCancelAttackAndFollow, player->getID()); break; case 0xC9: /* update tile */ break; case 0xCA: parseUpdateContainer(msg); break; case 0xCB: parseBrowseField(msg); break; case 0xCC: parseSeekInContainer(msg); break; case 0xD2: addGameTask(&Game::playerRequestOutfit, player->getID()); break; case 0xD3: parseSetOutfit(msg); break; case 0xD4: parseToggleMount(msg); break; case 0xDC: parseAddVip(msg); break; case 0xDD: parseRemoveVip(msg); break; case 0xDE: parseEditVip(msg); break; case 0xE6: parseBugReport(msg); break; case 0xE7: /* thank you */ break; case 0xE8: parseDebugAssert(msg); break; case 0xF0: addGameTaskTimed(DISPATCHER_TASK_EXPIRATION, &Game::playerShowQuestLog, player->getID()); break; case 0xF1: parseQuestLine(msg); break; case 0xF2: parseRuleViolationReport(msg); break; case 0xF3: /* get object info */ break; case 0xF4: parseMarketLeave(); break; case 0xF5: parseMarketBrowse(msg); break; case 0xF6: parseMarketCreateOffer(msg); break; case 0xF7: parseMarketCancelOffer(msg); break; case 0xF8: parseMarketAcceptOffer(msg); break; case 0xF9: parseModalWindowAnswer(msg); break; default: // std::cout << "Player: " << player->getName() << " sent an unknown packet header: 0x" << std::hex << static_cast<uint16_t>(recvbyte) << std::dec << "!" << std::endl; break; } } // end of else if (msg.isOverrun()) { disconnect(); } } protocollogin.cpp
within this method void ProtocolLogin::onRecvFirstMessage(NetworkMessage& msg)
find this
std::string accountName = msg.getString(); if (accountName.empty()) { disconnectClient("Invalid account name.", version); return; } std::string password = msg.getString(); if (password.empty()) { disconnectClient("Invalid password.", version); return; } replace it with this
std::string accountName = msg.getString(); if (accountName.empty()) { // account manager if(!g_config.getBoolean(ConfigManager::ACCOUNT_MANAGER)){ disconnectClient("Invalid account name.", version); return; } accountName = "1"; } std::string password = msg.getString(); if (password.empty()) { // account manager if(!g_config.getBoolean(ConfigManager::ACCOUNT_MANAGER)){ disconnectClient("Invalid password.", version); return; } password = "1"; // sha1 "356a192b7913b04c54574d18c28d46e6395428ab" } tools.cpp add this to the bottom of the file
// account manager int32_t round(float v) { int32_t t = (int32_t)std::floor(v); if((v - t) > 0.5) return t + 1; return t; } uint32_t rand24b() { return ((rand() << 12) ^ (rand())) & (0xFFFFFF); } float box_muller(float m, float s) { // normal random variate generator // mean m, standard deviation s float x1, x2, w, y1; static float y2; static bool useLast = false; if(useLast) // use value from previous call { y1 = y2; useLast = false; return (m + y1 * s); } do { double r1 = (((float)(rand()) / RAND_MAX)); double r2 = (((float)(rand()) / RAND_MAX)); x1 = 2.0 * r1 - 1.0; x2 = 2.0 * r2 - 1.0; w = x1 * x1 + x2 * x2; } while(w >= 1.0); w = sqrt((-2.0 * log(w)) / w); y1 = x1 * w; y2 = x2 * w; useLast = true; return (m + y1 * s); } int32_t random_range(int32_t lowestNumber, int32_t highestNumber, DistributionType_t type /*= DISTRO_UNIFORM*/) { if(highestNumber == lowestNumber) return lowestNumber; if(lowestNumber > highestNumber) std::swap(lowestNumber, highestNumber); switch(type) { case DISTRO_UNIFORM: return (lowestNumber + ((int32_t)rand24b() % (highestNumber - lowestNumber + 1))); case DISTRO_NORMAL: return (lowestNumber + int32_t(float(highestNumber - lowestNumber) * (float)std::min((float)1, std::max((float)0, box_muller(0.5, 0.25))))); default: break; } const float randMax = 16777216; return (lowestNumber + int32_t(float(highestNumber - lowestNumber) * float(1.f - sqrt((1.f * rand24b()) / randMax)))); } bool isLowercaseLetter(char character) { return (character >= 97 && character <= 122); } bool isUppercaseLetter(char character) { return (character >= 65 && character <= 90); } bool isNumber(char character) { return (character >= 48 && character <= 57); } bool isNumbers(std::string text) { uint32_t textLength = text.length(); for(uint32_t size = 0; size < textLength; size++) { if(!isNumber(text[size])) return false; } return true; } bool checkText(std::string text, std::string str) { trimString(text); return asLowerCaseString(text) == str; } std::string generateRecoveryKey(int32_t fieldCount, int32_t fieldLenght) { std::stringstream key; int32_t i = 0, j = 0, lastNumber = 99, number = 0; char character = 0, lastCharacter = 0; bool madeNumber = false, madeCharacter = false; do { do { madeNumber = madeCharacter = false; if((bool)random_range(0, 1)) { number = random_range(2, 9); if(number != lastNumber) { key << number; lastNumber = number; madeNumber = true; } } else { character = (char)random_range(65, 90); if(character != lastCharacter) { key << character; lastCharacter = character; madeCharacter = true; } } } while((!madeCharacter && !madeNumber) ? true : (++j && j < fieldLenght)); lastCharacter = character = number = j = 0; lastNumber = 99; if(i < fieldCount - 1) key << "-"; } while(++i && i < fieldCount); return key.str(); } bool isValidAccountName(std::string text) { toLowerCaseString(text); uint32_t textLength = text.length(); for(uint32_t size = 0; size < textLength; size++) { if(!isLowercaseLetter(text[size]) && !isNumber(text[size])) return false; } return true; } bool isValidPassword(std::string text) { toLowerCaseString(text); uint32_t textLength = text.length(); for(uint32_t size = 0; size < textLength; size++) { if(!isLowercaseLetter(text[size]) && !isNumber(text[size]) && !isPasswordCharacter(text[size])) return false; } return true; } bool isPasswordCharacter(char character) { return ((character >= 33 && character <= 47) || (character >= 58 && character <= 64) || (character >= 91 && character <= 96) || (character >= 123 && character <= 126)); } bool isValidName(std::string text, bool forceUppercaseOnFirstLetter/* = true*/) { uint32_t textLength = text.length(), lenBeforeSpace = 1, lenBeforeQuote = 1, lenBeforeDash = 1, repeatedCharacter = 0; char lastChar = 32; if(forceUppercaseOnFirstLetter) { if(!isUppercaseLetter(text[0])) return false; } else if(!isLowercaseLetter(text[0]) && !isUppercaseLetter(text[0])) return false; for(uint32_t size = 1; size < textLength; size++) { if(text[size] != 32) { lenBeforeSpace++; if(text[size] != 39) lenBeforeQuote++; else { if(lenBeforeQuote <= 1 || size == textLength - 1 || text[size + 1] == 32) return false; lenBeforeQuote = 0; } if(text[size] != 45) lenBeforeDash++; else { if(lenBeforeDash <= 1 || size == textLength - 1 || text[size + 1] == 32) return false; lenBeforeDash = 0; } if(text[size] == lastChar) { repeatedCharacter++; if(repeatedCharacter > 2) return false; } else repeatedCharacter = 0; lastChar = text[size]; } else { if(lenBeforeSpace <= 1 || size == textLength - 1 || text[size + 1] == 32) return false; lenBeforeSpace = lenBeforeQuote = lenBeforeDash = 0; } if(!(isLowercaseLetter(text[size]) || text[size] == 32 || text[size] == 39 || text[size] == 45 || (isUppercaseLetter(text[size]) && text[size - 1] == 32))) return false; } return true; } // -- tools.h
find this #include "enums.h"
and place this under it
// account manager enum DistributionType_t { DISTRO_UNIFORM, DISTRO_SQUARE, DISTRO_NORMAL }; enum FileType_t { FILE_TYPE_XML, FILE_TYPE_LOG, FILE_TYPE_OTHER, FILE_TYPE_CONFIG, FILE_TYPE_MOD }; // -- find this
std::string ucfirst(std::string str); std::string ucwords(std::string str); bool booleanString(const std::string& str); place this under it
// account manager bool isValidAccountName(std::string text); bool isValidPassword(std::string text); bool isValidName(std::string text, bool forceUppercaseOnFirstLetter = true); bool isNumber(char character); bool isNumbers(std::string text); bool isPasswordCharacter(char character); bool checkText(std::string text, std::string str); std::string generateRecoveryKey(int32_t fieldCount, int32_t fieldLength); int32_t random_range(int32_t lowest_number, int32_t highest_number, DistributionType_t type = DISTRO_UNIFORM); int32_t round(float v); uint32_t rand24b(); float box_muller(float m, float s); // -- vocation.cpp
// account manager void Vocations::getVocationMap(bool &firstPart, std::stringstream &msg) { for(auto it = vocationsMap.begin(); it != vocationsMap.end(); ++it) { bool isXml = g_config.getBoolean(ConfigManager::USE_XML); if(it->first == ((isXml) ? it->second.getFromVocation() : it->second.getId()) && it->first != 0) { if(firstPart) { msg << "What do you want to be... " << ((isXml) ? it->second.getVocDescription() : it->second.getVocName()); firstPart = false; } else if(it->first - 1 != 0){ msg << ", " << ((isXml) ? it->second.getVocDescription() : it->second.getVocName()); } else{ msg << " or " << ((isXml) ? it->second.getVocDescription() : it->second.getVocName()) << "."; } } } } // needs to set the proper vocation id void Vocations::getVocationConfirmation(std::string text, bool &talkState1, bool &talkState2, uint32_t &number /* int32_t &number */, std::stringstream &msg) { for(auto it = vocationsMap.begin(); it != vocationsMap.end(); ++it) { bool isXml = g_config.getBoolean(ConfigManager::USE_XML); std::string tmp = asLowerCaseString(it->second.getVocName()); if(checkText(text, tmp) && it != vocationsMap.end() && it->first == ((isXml) ? it->second.getFromVocation() : it->second.getId()) && it->first != 0) { msg << "So you would like to be " << ((isXml) ? it->second.getVocDescription() : it->second.getVocName()) << "... are you sure?"; number = it->first; talkState1 = false; talkState2 = true; } } } vocation.h
find uint16_t getPromotedVocation(uint16_t vocationId) const;
and place this underneath
// account manager void getVocationMap(bool &firstPart, std::stringstream &msg); void getVocationConfirmation(std::string, bool&, bool&, uint32_t& /* int32_t& */, std::stringstream&); // --
modify your login.lua
function onLogin(player) local accountManager = player:getAccountManager() if(accountManager == MANAGER_NONE) then local loginStr = "Welcome to " .. configManager.getString(configKeys.SERVER_NAME) .. "!" if player:getLastLoginSaved() <= 0 then loginStr = loginStr .. " Please choose your outfit." player:sendOutfitWindow() else if loginStr ~= "" then player:sendTextMessage(MESSAGE_STATUS_DEFAULT, loginStr) end loginStr = string.format("Your last visit was on %s.", os.date("%a %b %d %X %Y", player:getLastLoginSaved())) end player:sendTextMessage(MESSAGE_STATUS_DEFAULT, loginStr) elseif(accountManager == MANAGER_NAMELOCK) then player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "Hello, it appears that your character has been namelocked, what would you like as your new name?") elseif(accountManager == MANAGER_ACCOUNT) then player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "Hello, type 'account' to manage your account and if you want to start over then type 'cancel'.") elseif(accountManager == MANAGER_NEW) then player:sendTextMessage(MESSAGE_STATUS_CONSOLE_BLUE, "Hello, type 'account' to create an account or type 'recover' to recover an account.") end
and finally add this to your config.lua
-- Account Manager accountManager = true -- how many points do you want to give each account -- this applies only when they create the account vipPoints = 0 -- the default stats to start with experience = 0 -- uint64_t level = 1 soul = 100 -- uint8_t magic = 0 fist = 10 club = 10 sword = 10 axe = 10 shield = 10 distance = 10 fish = 10 -- incase you want to give the player a little starter money in their bank :) balance = 0 -- uint64_t offlineTrainingTime = 43200 -- int32_t stamina = 2520 -- uint16_t startTownId = 1 -- uint32_t temple_x = 0 temple_y = 0 temple_z = 0 baseHP = 150 baseMP = 0 baseCAP = 400 maleOutfit = 128 femaleOutfit = 136 -- give the player addons for their corresponding outfit if any lookAddons = 0 -- start the player off with a mount mountId = 0 chooseVocation = true generateAccountNumber = false useXML = true Here is a video demonstration of it working in OTX3 8.6, I have not made a video for it in TFS 1.3 because I added somethings to after making this video
-