• There is NO official Otland's Discord server and NO official Otland's server list. The Otland's Staff does not manage any Discord server or server list. Moderators or administrator of any Discord server or server lists have NO connection to the Otland's Staff. Do not get scammed!

TFS 1.X+ Nostalrius Multiworld system

Vantoria

www.ClassicOT.us
Joined
Jun 6, 2014
Messages
186
Reaction score
16
Location
USA
hi guys i was trying to adapt this Multiworld system by aurelion5670 · Pull Request #929 · opentibiabr/otservbr-global (https://github.com/opentibiabr/otservbr-global/pull/929/files) multiworld system in nostalrius engine i think the code did adapt sucessfully because it compile good i have setup everything correctly as i know but something is giving me error in console
Lua:
Aug 19 00:27:59 tester tfs[152622]: [Error - mysql_real_query] Query: TRUNCATE TABLE `players_online` WHERE `world_id` = 3306
Aug 19 00:27:59 tester tfs[152622]: Message: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'WHERE `world_id` = 3306' at line 1
Aug 19 00:27:59 tester tfs[152622]: [Error - mysql_real_query] Query: SELECT `id`, `world_id`, `highest_bidder`, `last_bid`, (SELECT `balance` FROM `players` WHERE `players`.`id` = `highest_bidder`) AS `balance` FROM `houses` WHERE `owner` = 0 AND `world_id` = 3306 AND `bid_end` != 0 AND `bid_end` < 1597796879
Aug 19 00:27:59 tester tfs[152622]: Message: Unknown column 'world_id' in 'field list'
Aug 19 00:27:59 tester tfs[152622]: [Error - mysql_store_result] Query: SELECT `id`, `world_id`, `highest_bidder`, `last_bid`, (SELECT `balance` FROM `players` WHERE `players`.`id` = `highest_bidder`) AS `balance` FROM `houses` WHERE `owner` = 0 AND `world_id` = 3306 AND `bid_end` != 0 AND `bid_end` < 1597796879
Aug 19 00:27:59 tester tfs[152622]: Message: Commands out of sync; you can't run this command now
this is my new edited startup.lua
Lua:
function onStartup()
    math.randomseed(os.mtime())
    
    db.asyncQuery('TRUNCATE TABLE `players_online` WHERE `world_id` = '..configManager.getNumber(configKeys.WORLD_ID)..'')
    db.asyncQuery("DELETE FROM `guild_wars` WHERE `status` = 0")
    db.asyncQuery("DELETE FROM `players` WHERE `deletion` != 0 AND `deletion` < " .. os.time())
    db.asyncQuery("DELETE FROM `ip_bans` WHERE `expires_at` != 0 AND `expires_at` <= " .. os.time())

    -- Move expired bans to ban history
    local resultId = db.storeQuery("SELECT * FROM `account_bans` WHERE `expires_at` != 0 AND `expires_at` <= " .. os.time())
    if resultId ~= false then
        repeat
            local accountId = result.getDataInt(resultId, "account_id")
            db.asyncQuery("INSERT INTO `account_ban_history` (`account_id`, `reason`, `banned_at`, `expired_at`, `banned_by`) VALUES (" .. accountId .. ", " .. db.escapeString(result.getDataString(resultId, "reason")) .. ", " .. result.getDataLong(resultId, "banned_at") .. ", " .. result.getDataLong(resultId, "expires_at") .. ", " .. result.getDataInt(resultId, "banned_by") .. ")")
            db.asyncQuery("DELETE FROM `account_bans` WHERE `account_id` = " .. accountId)
        until not result.next(resultId)
        result.free(resultId)
    end

    -- Check house auctions
    local resultId = db.storeQuery('SELECT `id`, `world_id`, `highest_bidder`, `last_bid`, (SELECT `balance` FROM `players` WHERE `players`.`id` = `highest_bidder`) AS `balance` FROM `houses` WHERE `owner` = 0 AND `world_id` = '..configManager.getNumber(configKeys.WORLD_ID)..' AND `bid_end` != 0 AND `bid_end` < ' .. os.time())
    if resultId ~= false then
        repeat
            local house = House(result.getDataInt(resultId, "id"))
            if house ~= nil then
                local highestBidder = result.getDataInt(resultId, "highest_bidder")
                local balance = result.getDataLong(resultId, "balance")
                local lastBid = result.getDataInt(resultId, "last_bid")
                if balance >= lastBid then
                    db.query("UPDATE `players` SET `balance` = " .. (balance - lastBid) .. " WHERE `id` = " .. highestBidder)
                    house:setOwnerGuid(highestBidder)
                end
                db.asyncQuery('UPDATE `houses` SET `last_bid` = 0, `bid_end` = 0, `highest_bidder` = 0, `bid` = 0 WHERE `world_id` = '..configManager.getNumber(configKeys.WORLD_ID)..' and `id` = ' .. house:getId())
            end
        until not result.next(resultId)
        result.free(resultId)
    end
    
    -- Remove murders that are more than 60 days old
    local resultId = db.storeQuery("SELECT * FROM `player_murders` WHERE `date` <= " .. os.time() - 60 * 24 * 60 * 60)
    if resultId ~= false then
        repeat
            local playerId = result.getDataInt(resultId, "player_id")
            local id = result.getDataLong(resultId, "id")
            
            db.asyncQuery("DELETE FROM `player_murders` WHERE `player_id` = " .. playerId .. " AND `id` = " .. id)
        until not result.next(resultId)
        result.free(resultId)
    end
end

and this one the old startup.lua
Lua:
function onStartup()
    math.randomseed(os.mtime())
    
    db.query("TRUNCATE TABLE `players_online`")
    db.asyncQuery("DELETE FROM `guild_wars` WHERE `status` = 0")
    db.asyncQuery("DELETE FROM `players` WHERE `deletion` != 0 AND `deletion` < " .. os.time())
    db.asyncQuery("DELETE FROM `ip_bans` WHERE `expires_at` != 0 AND `expires_at` <= " .. os.time())

    -- Move expired bans to ban history
    local resultId = db.storeQuery("SELECT * FROM `account_bans` WHERE `expires_at` != 0 AND `expires_at` <= " .. os.time())
    if resultId ~= false then
        repeat
            local accountId = result.getDataInt(resultId, "account_id")
            db.asyncQuery("INSERT INTO `account_ban_history` (`account_id`, `reason`, `banned_at`, `expired_at`, `banned_by`) VALUES (" .. accountId .. ", " .. db.escapeString(result.getDataString(resultId, "reason")) .. ", " .. result.getDataLong(resultId, "banned_at") .. ", " .. result.getDataLong(resultId, "expires_at") .. ", " .. result.getDataInt(resultId, "banned_by") .. ")")
            db.asyncQuery("DELETE FROM `account_bans` WHERE `account_id` = " .. accountId)
        until not result.next(resultId)
        result.free(resultId)
    end

    -- Check house auctions
    local resultId = db.storeQuery("SELECT `id`, `highest_bidder`, `last_bid`, (SELECT `balance` FROM `players` WHERE `players`.`id` = `highest_bidder`) AS `balance` FROM `houses` WHERE `owner` = 0 AND `bid_end` != 0 AND `bid_end` < " .. os.time())
    if resultId ~= false then
        repeat
            local house = House(result.getDataInt(resultId, "id"))
            if house ~= nil then
                local highestBidder = result.getDataInt(resultId, "highest_bidder")
                local balance = result.getDataLong(resultId, "balance")
                local lastBid = result.getDataInt(resultId, "last_bid")
                if balance >= lastBid then
                    db.query("UPDATE `players` SET `balance` = " .. (balance - lastBid) .. " WHERE `id` = " .. highestBidder)
                    house:setOwnerGuid(highestBidder)
                end
                db.asyncQuery("UPDATE `houses` SET `last_bid` = 0, `bid_end` = 0, `highest_bidder` = 0, `bid` = 0 WHERE `id` = " .. house:getId())
            end
        until not result.next(resultId)
        result.free(resultId)
    end
    
    -- Remove murders that are more than 60 days old
    local resultId = db.storeQuery("SELECT * FROM `player_murders` WHERE `date` <= " .. os.time() - 60 * 24 * 60 * 60)
    if resultId ~= false then
        repeat
            local playerId = result.getDataInt(resultId, "player_id")
            local id = result.getDataLong(resultId, "id")
            
            db.asyncQuery("DELETE FROM `player_murders` WHERE `player_id` = " .. playerId .. " AND `id` = " .. id)
        until not result.next(resultId)
        result.free(resultId)
    end
end
also i can't see characterlist with otcv8 when i see console it give me this error
Code:
ERROR: protected lua call failed: C++ call failed: InputMessage eof reached
stack traceback:
    [builtin#146]: at 0x011ef230
    [C]: in function 'getString'
    /modules/gamelib/protocollogin.lua:247: in function 'parseCharacterList'
    /modules/gamelib/protocollogin.lua:178: in function </modules/gamelib/protocollogin.lua:159>
 
Solution
it is not defined but if i do it then i cant compile
Lua:
#define MULTIWORLD_SYSTEM
in definitions.h
it give me this error with no sucess on compilation
Code:
/home/otsmanager/forgottenserver/src/protocollogin.cpp: In member function ‘void ProtocolLogin::getCharacterList(uint32_t, const string&)’:
/home/otsmanager/forgottenserver/src/protocollogin.cpp:100:77: error: request for member ‘c_str’ in ‘g_gameworld.GameWorldConfig::getWorldIp(((int)((uint16_t)worldId)))’, which is of non-class type ‘const char*’
  100 |      output->add<uint32_t>(inet_addr(g_gameworld.getWorldIp(worldId).c_str()));
      |                                                                      ^~~~~
C++:
/**
* Tibia GIMUD Server - a free and open-source...
Do you already modified the database?
i saw there was missing world_id in houses table but still getting this
Lua:
[Error - mysql_real_query] Query: TRUNCATE TABLE `players_online` WHERE `world_id` = 3306
Message: You have an error in your SQL syntax; check the manual that corresponds to your MariaDB server version for the right syntax to use near 'WHERE `world_id` = 3306' at line 1
do you know why im getting this error with otcv8? i can't see the characterlist
Code:
ERROR: protected lua call failed: C++ call failed: InputMessage eof reached
stack traceback:
    [builtin#146]: at 0x011ef230
    [C]: in function 'getString'
    /modules/gamelib/protocollogin.lua:247: in function 'parseCharacterList'
    /modules/gamelib/protocollogin.lua:178: in function </modules/gamelib/protocollogin.lua:159>
 
Last edited:
someone can help me please? i am willing to pay if it is necessary.
i have a problem with fetching the characterlist normal tibia client give me debug
Lua:
+---------------------------------------------------------------
Debug Assertion 7.72 Utils.cpp 340
Wed Aug 19 10:57:56 2020
Windows Version: 6.2 build 9200 on 2
Graphic Engine: 2
Last Packet Types: 100 020 010 010 000 000 000 000 000 000
Last Packet: 112 000 020 034 000 051 010 087 101 108 099 111 109 101 032 116
Player.cpp 383: exception occurred, reason:
Network.cpp 885: exception occurred (ErrorCode = 0), reason:
Control.cpp 1280: exception occurred (Type = 100), reason:
Communication.cpp 1162: exception occurred (Count = 2), reason:
Network.cpp 470: exception occurred (MaxLength = 30), reason:
Utils.cpp 340: assertion failed (Position = 45) (Size-Length = -1676), reason:
Position<=Size-Length
----------------------------------------------------------------
otcv8 give me this error in console it doesn't let me see char list
Code:
ERROR: protected lua call failed: C++ call failed: InputMessage eof reached
stack traceback:
    [builtin#146]: at 0x011ef230
    [C]: in function 'getString'
    /modules/gamelib/protocollogin.lua:247: in function 'parseCharacterList'
    /modules/gamelib/protocollogin.lua:178: in function </modules/gamelib/protocollogin.lua:159>
i dont know what is wrong i did added the multi world system carefully since it compile good without any error and no error in console when i turn on the server i dont know if the problem is in protocollogin.cpp i let it here --> PROTOCOLLOGIN.CPP
 
its related with your game sources not sending the properly information to the client. Dont need to modify client to accept multi-world support.

and about your startup, create a value to each worldId on config.lua and put that on lua files.

like worldId = 1 ... 2 ... 3 wathever
 
its related with your game sources not sending the properly information to the client. Dont need to modify client to accept multi-world support.

and about your startup, create a value to each worldId on config.lua and put that on lua files.
like worldId = 1 ... 2 ... 3 wathever
yes i know the problem is with protocollogin.cpp but dont know where and about the startup i put it like this and worked
Lua:
db.asyncQuery('DELETE FROM `players_online` WHERE `world_id` = '..configManager.getNumber(configKeys.WORLD_ID)..'')
in config.lua i have it like worldId = 0 the other folder worldId = 1
 
i am willing to pay, guys the sources compile fine but still getting debug when trying to fetch characterlist as i know you wont do too much work since i think the problem is on protocollogin.cpp or iologindata.cpp please

Lua:
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017  Alejandro Mujica <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include "otpch.h"

#include "protocollogin.h"

#include "outputmessage.h"
#include "tasks.h"

#include "configmanager.h"
#include "iologindata.h"
#include "ban.h"
#include "game.h"
#ifdef MULTIWORLD_SYSTEM
    #include "gameworldconfig.h"
#endif

extern ConfigManager g_config;
extern Game g_game;
#ifdef MULTIWORLD_SYSTEM
    extern GameWorldConfig g_gameworld;
#endif

void ProtocolLogin::sendUpdateRequest()
{
    auto output = OutputMessagePool::getOutputMessage();

    output->addByte(0x1E);
    send(output);

    disconnect();
}

void ProtocolLogin::disconnectClient(const std::string& message)
{
    auto output = OutputMessagePool::getOutputMessage();

    output->addByte(0x0A);
    output->addString(message);
    send(output);

    disconnect();
}

void ProtocolLogin::getCharacterList(uint32_t accountNumber, const std::string& password)
{
    Account account;
    if (!IOLoginData::loginserverAuthentication(accountNumber, password, account)) {
        disconnectClient("Account number or password is not correct.");
        return;
    }

    auto output = OutputMessagePool::getOutputMessage();

    //Update premium days
    Game::updatePremium(account);

    const std::string& motd = g_config.getString(ConfigManager::MOTD);
    if (!motd.empty()) {
        //Add MOTD
        output->addByte(0x14);

        std::ostringstream ss;
        ss << g_game.getMotdNum() << "\n" << motd;
        output->addString(ss.str());
    }
   
    #ifdef MULTIWORLD_SYSTEM
        //Add char list
        output->addByte(0x64);

        uint8_t characters = std::min<size_t>(std::numeric_limits<uint8_t>::max() - 1, account.characters.size());
        uint8_t limit = 254;
       
        output->addByte(characters);
       
        for (const auto& it : account.characters) {
            if(limit == 0 || !accountNumber)
                break;
            output->addString(it);
           
            uint16_t worldId = g_gameworld.getPlayerWorldId(it);
           
            output->addString(g_gameworld.getWorldName(worldId));
            output->add<uint32_t>(inet_addr(g_gameworld.getWorldIp(worldId).c_str()));
            output->add<uint16_t>(g_gameworld.getWorldPort(worldId));
            limit -= 1;
        }
    #else
        //Add char list
        output->addByte(0x64);

        output->addByte(1); // number of worlds

        output->addByte(0); // world id
        output->addString(g_config.getString(ConfigManager::SERVER_NAME));
        output->add<uint32_t>(inet_addr(g_config.getString(ConfigManager::IP).c_str()));

        output->add<uint16_t>(g_config.getNumber(ConfigManager::GAME_PORT));

        output->addByte(0);
        //
        uint8_t size = std::min<size_t>(std::numeric_limits<uint8_t>::max(), account.characters.size());
        output->addByte(size);
        for (uint8_t i = 0; i < size; i++) {
            output->addByte(0);
            output->addString(account.characters[i]);
        }
    #endif  
    //Add premium days
    if (g_config.getBoolean(ConfigManager::FREE_PREMIUM)) {
        output->add<uint16_t>(0xFFFF);
    } else {
        output->add<uint16_t>(account.premiumDays);
    }

    send(output);

    disconnect();
}

void ProtocolLogin::onRecvFirstMessage(NetworkMessage& msg)
{
    if (g_game.getGameState() == GAME_STATE_SHUTDOWN) {
        disconnect();
        return;
    }

    msg.skipBytes(2); // client OS

    /*uint16_t version =*/ msg.get<uint16_t>();
    msg.skipBytes(12);

    /*
     * Skipped bytes:
     * 4 bytes: protocolVersion
     * 12 bytes: dat, spr, pic signatures (4 bytes each)
     */

    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);

    /*if (version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX) {
        //sendUpdateRequest();
        disconnectClient("Use Tibia 7.72 to login!");
        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;
    }

    uint32_t accountNumber = msg.get<uint32_t>();
    if (!accountNumber) {
        disconnectClient("Invalid account number.");
        return;
    }

    std::string password = msg.getString();
    if (password.empty()) {
        disconnectClient("Invalid password.");
        return;
    }

    auto thisPtr = std::static_pointer_cast<ProtocolLogin>(shared_from_this());
    g_dispatcher.addTask(createTask(std::bind(&ProtocolLogin::getCharacterList, thisPtr, accountNumber, password)));
}
 
Last edited:
i am willing to pay, guys the sources compile fine but still getting debug when trying to fetch characterlist as i know you wont do too much work since i think the problem is on protocollogin.cpp or iologindata.cpp please

Lua:
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017  Alejandro Mujica <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include "otpch.h"

#include "protocollogin.h"

#include "outputmessage.h"
#include "tasks.h"

#include "configmanager.h"
#include "iologindata.h"
#include "ban.h"
#include "game.h"
#ifdef MULTIWORLD_SYSTEM
    #include "gameworldconfig.h"
#endif

extern ConfigManager g_config;
extern Game g_game;
#ifdef MULTIWORLD_SYSTEM
    extern GameWorldConfig g_gameworld;
#endif

void ProtocolLogin::sendUpdateRequest()
{
    auto output = OutputMessagePool::getOutputMessage();

    output->addByte(0x1E);
    send(output);

    disconnect();
}

void ProtocolLogin::disconnectClient(const std::string& message)
{
    auto output = OutputMessagePool::getOutputMessage();

    output->addByte(0x0A);
    output->addString(message);
    send(output);

    disconnect();
}

void ProtocolLogin::getCharacterList(uint32_t accountNumber, const std::string& password)
{
    Account account;
    if (!IOLoginData::loginserverAuthentication(accountNumber, password, account)) {
        disconnectClient("Account number or password is not correct.");
        return;
    }

    auto output = OutputMessagePool::getOutputMessage();

    //Update premium days
    Game::updatePremium(account);

    const std::string& motd = g_config.getString(ConfigManager::MOTD);
    if (!motd.empty()) {
        //Add MOTD
        output->addByte(0x14);

        std::ostringstream ss;
        ss << g_game.getMotdNum() << "\n" << motd;
        output->addString(ss.str());
    }
   
    #ifdef MULTIWORLD_SYSTEM
        //Add char list
        output->addByte(0x64);

        uint8_t characters = std::min<size_t>(std::numeric_limits<uint8_t>::max() - 1, account.characters.size());
        uint8_t limit = 254;
       
        output->addByte(characters);
       
        for (const auto& it : account.characters) {
            if(limit == 0 || !accountNumber)
                break;
            output->addString(it);
           
            uint16_t worldId = g_gameworld.getPlayerWorldId(it);
           
            output->addString(g_gameworld.getWorldName(worldId));
            output->add<uint32_t>(inet_addr(g_gameworld.getWorldIp(worldId).c_str()));
            output->add<uint16_t>(g_gameworld.getWorldPort(worldId));
            limit -= 1;
        }
    #else
        //Add char list
        output->addByte(0x64);

        output->addByte(1); // number of worlds

        output->addByte(0); // world id
        output->addString(g_config.getString(ConfigManager::SERVER_NAME));
        output->add<uint32_t>(inet_addr(g_config.getString(ConfigManager::IP).c_str()));

        output->add<uint16_t>(g_config.getNumber(ConfigManager::GAME_PORT));

        output->addByte(0);
        //
        uint8_t size = std::min<size_t>(std::numeric_limits<uint8_t>::max(), account.characters.size());
        output->addByte(size);
        for (uint8_t i = 0; i < size; i++) {
            output->addByte(0);
            output->addString(account.characters[i]);
        }
    #endif  
    //Add premium days
    if (g_config.getBoolean(ConfigManager::FREE_PREMIUM)) {
        output->add<uint16_t>(0xFFFF);
    } else {
        output->add<uint16_t>(account.premiumDays);
    }

    send(output);

    disconnect();
}

void ProtocolLogin::onRecvFirstMessage(NetworkMessage& msg)
{
    if (g_game.getGameState() == GAME_STATE_SHUTDOWN) {
        disconnect();
        return;
    }

    msg.skipBytes(2); // client OS

    /*uint16_t version =*/ msg.get<uint16_t>();
    msg.skipBytes(12);

    /*
     * Skipped bytes:
     * 4 bytes: protocolVersion
     * 12 bytes: dat, spr, pic signatures (4 bytes each)
     */

    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);

    /*if (version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX) {
        //sendUpdateRequest();
        disconnectClient("Use Tibia 7.72 to login!");
        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;
    }

    uint32_t accountNumber = msg.get<uint32_t>();
    if (!accountNumber) {
        disconnectClient("Invalid account number.");
        return;
    }

    std::string password = msg.getString();
    if (password.empty()) {
        disconnectClient("Invalid password.");
        return;
    }

    auto thisPtr = std::static_pointer_cast<ProtocolLogin>(shared_from_this());
    g_dispatcher.addTask(createTask(std::bind(&ProtocolLogin::getCharacterList, thisPtr, accountNumber, password)));
}
Try this, you mixed up code from a repository that targets a different client version (which has a different login protocol) than the client version Nostalrius targets.

C++:
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017  Alejandro Mujica <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include "otpch.h"

#include "protocollogin.h"

#include "outputmessage.h"
#include "tasks.h"

#include "configmanager.h"
#include "iologindata.h"
#include "ban.h"
#include "game.h"
#ifdef MULTIWORLD_SYSTEM
    #include "gameworldconfig.h"
#endif

extern ConfigManager g_config;
extern Game g_game;
#ifdef MULTIWORLD_SYSTEM
    extern GameWorldConfig g_gameworld;
#endif

void ProtocolLogin::sendUpdateRequest()
{
    auto output = OutputMessagePool::getOutputMessage();

    output->addByte(0x1E);
    send(output);

    disconnect();
}

void ProtocolLogin::disconnectClient(const std::string& message)
{
    auto output = OutputMessagePool::getOutputMessage();

    output->addByte(0x0A);
    output->addString(message);
    send(output);

    disconnect();
}

void ProtocolLogin::getCharacterList(uint32_t accountNumber, const std::string& password)
{
    Account account;
    if (!IOLoginData::loginserverAuthentication(accountNumber, password, account)) {
        disconnectClient("Account number or password is not correct.");
        return;
    }

    auto output = OutputMessagePool::getOutputMessage();

    //Update premium days
    Game::updatePremium(account);

    const std::string& motd = g_config.getString(ConfigManager::MOTD);
    if (!motd.empty()) {
        //Add MOTD
        output->addByte(0x14);

        std::ostringstream ss;
        ss << g_game.getMotdNum() << "\n" << motd;
        output->addString(ss.str());
    }
   
    output->addByte(0x64);
    
    uint8_t size = std::min<size_t>(std::numeric_limits<uint8_t>::max(), account.characters.size());
    output->addByte(size);

    #ifdef MULTIWORLD_SYSTEM
        //Add char list
        for (uint8_t i = 0; i < size; i++) {
            output->addString(account.characters[i].name);

            const uint16_t worldId = g_gameworld.getPlayerWorldId(account.characters[i].worldid);

            output->addString(g_gameworld.getWorldName(worldId));
            output->add<uint32_t>(inet_addr(g_gameworld.getWorldIp(worldId).c_str()));
            output->add<uint16_t>(g_gameworld.getWorldPort(worldId));
        }
    #else
        //Add char list
        for (uint8_t i = 0; i < size; i++) {
            output->addString(account.characters[i]);
            output->addString(g_config.getString(ConfigManager::SERVER_NAME));
            output->add<uint32_t>(inet_addr(g_config.getString(ConfigManager::IP).c_str()));
            output->add<uint16_t>(g_config.getNumber(ConfigManager::GAME_PORT));
        }
    #endif  
    
    //Add premium days
    if (g_config.getBoolean(ConfigManager::FREE_PREMIUM)) {
        output->add<uint16_t>(0xFFFF);
    } else {
        output->add<uint16_t>(account.premiumDays);
    }

    send(output);

    disconnect();
}

void ProtocolLogin::onRecvFirstMessage(NetworkMessage& msg)
{
    if (g_game.getGameState() == GAME_STATE_SHUTDOWN) {
        disconnect();
        return;
    }

    msg.skipBytes(2); // client OS

    /*uint16_t version =*/ msg.get<uint16_t>();
    msg.skipBytes(12);

    /*
     * Skipped bytes:
     * 4 bytes: protocolVersion
     * 12 bytes: dat, spr, pic signatures (4 bytes each)
     */

    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);

    /*if (version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX) {
        //sendUpdateRequest();
        disconnectClient("Use Tibia 7.72 to login!");
        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;
    }

    uint32_t accountNumber = msg.get<uint32_t>();
    if (!accountNumber) {
        disconnectClient("Invalid account number.");
        return;
    }

    std::string password = msg.getString();
    if (password.empty()) {
        disconnectClient("Invalid password.");
        return;
    }

    auto thisPtr = std::static_pointer_cast<ProtocolLogin>(shared_from_this());
    g_dispatcher.addTask(createTask(std::bind(&ProtocolLogin::getCharacterList, thisPtr, accountNumber, password)));
}
 
Try this, you mixed up code from a repository that targets a different client version (which has a different login protocol) than the client version Nostalrius targets.

C++:
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017  Alejandro Mujica <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include "otpch.h"

#include "protocollogin.h"

#include "outputmessage.h"
#include "tasks.h"

#include "configmanager.h"
#include "iologindata.h"
#include "ban.h"
#include "game.h"
#ifdef MULTIWORLD_SYSTEM
    #include "gameworldconfig.h"
#endif

extern ConfigManager g_config;
extern Game g_game;
#ifdef MULTIWORLD_SYSTEM
    extern GameWorldConfig g_gameworld;
#endif

void ProtocolLogin::sendUpdateRequest()
{
    auto output = OutputMessagePool::getOutputMessage();

    output->addByte(0x1E);
    send(output);

    disconnect();
}

void ProtocolLogin::disconnectClient(const std::string& message)
{
    auto output = OutputMessagePool::getOutputMessage();

    output->addByte(0x0A);
    output->addString(message);
    send(output);

    disconnect();
}

void ProtocolLogin::getCharacterList(uint32_t accountNumber, const std::string& password)
{
    Account account;
    if (!IOLoginData::loginserverAuthentication(accountNumber, password, account)) {
        disconnectClient("Account number or password is not correct.");
        return;
    }

    auto output = OutputMessagePool::getOutputMessage();

    //Update premium days
    Game::updatePremium(account);

    const std::string& motd = g_config.getString(ConfigManager::MOTD);
    if (!motd.empty()) {
        //Add MOTD
        output->addByte(0x14);

        std::ostringstream ss;
        ss << g_game.getMotdNum() << "\n" << motd;
        output->addString(ss.str());
    }

    output->addByte(0x64);
 
    uint8_t size = std::min<size_t>(std::numeric_limits<uint8_t>::max(), account.characters.size());
    output->addByte(size);

    #ifdef MULTIWORLD_SYSTEM
        //Add char list
        for (uint8_t i = 0; i < size; i++) {
            output->addString(account.characters[i].name);

            const uint16_t worldId = g_gameworld.getPlayerWorldId(account.characters[i].worldid);

            output->addString(g_gameworld.getWorldName(worldId));
            output->add<uint32_t>(inet_addr(g_gameworld.getWorldIp(worldId).c_str()));
            output->add<uint16_t>(g_gameworld.getWorldPort(worldId));
        }
    #else
        //Add char list
        for (uint8_t i = 0; i < size; i++) {
            output->addString(account.characters[i]);
            output->addString(g_config.getString(ConfigManager::SERVER_NAME));
            output->add<uint32_t>(inet_addr(g_config.getString(ConfigManager::IP).c_str()));
            output->add<uint16_t>(g_config.getNumber(ConfigManager::GAME_PORT));
        }
    #endif
 
    //Add premium days
    if (g_config.getBoolean(ConfigManager::FREE_PREMIUM)) {
        output->add<uint16_t>(0xFFFF);
    } else {
        output->add<uint16_t>(account.premiumDays);
    }

    send(output);

    disconnect();
}

void ProtocolLogin::onRecvFirstMessage(NetworkMessage& msg)
{
    if (g_game.getGameState() == GAME_STATE_SHUTDOWN) {
        disconnect();
        return;
    }

    msg.skipBytes(2); // client OS

    /*uint16_t version =*/ msg.get<uint16_t>();
    msg.skipBytes(12);

    /*
     * Skipped bytes:
     * 4 bytes: protocolVersion
     * 12 bytes: dat, spr, pic signatures (4 bytes each)
     */

    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);

    /*if (version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX) {
        //sendUpdateRequest();
        disconnectClient("Use Tibia 7.72 to login!");
        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;
    }

    uint32_t accountNumber = msg.get<uint32_t>();
    if (!accountNumber) {
        disconnectClient("Invalid account number.");
        return;
    }

    std::string password = msg.getString();
    if (password.empty()) {
        disconnectClient("Invalid password.");
        return;
    }

    auto thisPtr = std::static_pointer_cast<ProtocolLogin>(shared_from_this());
    g_dispatcher.addTask(createTask(std::bind(&ProtocolLogin::getCharacterList, thisPtr, accountNumber, password)));
}
thanks for reply and it did work with your fix i can see characterlist but it doesn't recognize the world's id i mean i have 2 players in one account one in world 0 and other in world 1 in database but send the players to the same worl, yesterday i was learning some code and i did figure out a semi solution i did edit a loginserver apart only for try and did worked i mixed this codes to make it work
used
HeavenIsLost/realotsloginserver (https://github.com/HeavenIsLost/realotsloginserver)
this too
and this
with this edited loginserver i can see characterlist displaying 2 world's as it supposed to be and i can login without any problem just an error in console
Lua:
Tester has logged in.
[Error - mysql_real_query] Query: INSERT INTO `players_online` VALUES (4)
Message: Column count doesn't match value count at row 1
i think i will fix that too if i did all this without knowleadge, i would like to do it without using a loginserver, as i mention before your fix compile good and i can see characterlist but server dont recognize the worlds it send all players to the same world
 
thanks for reply and it did work with your fix i can see characterlist but it doesn't recognize the world's id i mean i have 2 players in one account one in world 0 and other in world 1 in database but send the players to the same worl, yesterday i was learning some code and i did figure out a semi solution i did edit a loginserver apart only for try and did worked i mixed this codes to make it work
used
HeavenIsLost/realotsloginserver (https://github.com/HeavenIsLost/realotsloginserver)
this too
and this
with this edited loginserver i can see characterlist displaying 2 world's as it supposed to be and i can login without any problem just an error in console
Lua:
Tester has logged in.
[Error - mysql_real_query] Query: INSERT INTO `players_online` VALUES (4)
Message: Column count doesn't match value count at row 1
i think i will fix that too if i did all this without knowleadge, i would like to do it without using a loginserver, as i mention before your fix compile good and i can see characterlist but server dont recognize the worlds it send all players to the same world
Run the 2nd world on a different game port.
 
it is in different game port already like i said it works fine the multi world with milice tfs loginserver with my fix, and with your's it doesnt recognize the worlds
C++:
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017  Alejandro Mujica <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include "otpch.h"

#include "protocollogin.h"

#include "outputmessage.h"
#include "tasks.h"

#include "configmanager.h"
#include "iologindata.h"
#include "ban.h"
#include "game.h"
#ifdef MULTIWORLD_SYSTEM
    #include "gameworldconfig.h"
#endif

extern ConfigManager g_config;
extern Game g_game;
#ifdef MULTIWORLD_SYSTEM
    extern GameWorldConfig g_gameworld;
#endif

void ProtocolLogin::sendUpdateRequest()
{
    auto output = OutputMessagePool::getOutputMessage();

    output->addByte(0x1E);
    send(output);

    disconnect();
}

void ProtocolLogin::disconnectClient(const std::string& message)
{
    auto output = OutputMessagePool::getOutputMessage();

    output->addByte(0x0A);
    output->addString(message);
    send(output);

    disconnect();
}

void ProtocolLogin::getCharacterList(uint32_t accountNumber, const std::string& password)
{
    Account account;
    if (!IOLoginData::loginserverAuthentication(accountNumber, password, account)) {
        disconnectClient("Account number or password is not correct.");
        return;
    }

    auto output = OutputMessagePool::getOutputMessage();

    //Update premium days
    Game::updatePremium(account);

    const std::string& motd = g_config.getString(ConfigManager::MOTD);
    if (!motd.empty()) {
        //Add MOTD
        output->addByte(0x14);

        std::ostringstream ss;
        ss << g_game.getMotdNum() << "\n" << motd;
        output->addString(ss.str());
    }
   
    output->addByte(0x64);
    
    uint8_t size = std::min<size_t>(std::numeric_limits<uint8_t>::max(), account.characters.size());
    output->addByte(size);

    #ifdef MULTIWORLD_SYSTEM
        //Add char list
        for (uint8_t i = 0; i < size; i++) {
            output->addString(account.characters[i].name);

            const uint16_t worldId = account.characters[i].worldid;

            output->addString(g_gameworld.getWorldName(worldId));
            output->add<uint32_t>(inet_addr(g_gameworld.getWorldIp(worldId).c_str()));
            output->add<uint16_t>(g_gameworld.getWorldPort(worldId));
        }
    #else
        //Add char list
        for (uint8_t i = 0; i < size; i++) {
            output->addString(account.characters[i]);
            output->addString(g_config.getString(ConfigManager::SERVER_NAME));
            output->add<uint32_t>(inet_addr(g_config.getString(ConfigManager::IP).c_str()));
            output->add<uint16_t>(g_config.getNumber(ConfigManager::GAME_PORT));
        }
    #endif  
    
    //Add premium days
    if (g_config.getBoolean(ConfigManager::FREE_PREMIUM)) {
        output->add<uint16_t>(0xFFFF);
    } else {
        output->add<uint16_t>(account.premiumDays);
    }

    send(output);

    disconnect();
}

void ProtocolLogin::onRecvFirstMessage(NetworkMessage& msg)
{
    if (g_game.getGameState() == GAME_STATE_SHUTDOWN) {
        disconnect();
        return;
    }

    msg.skipBytes(2); // client OS

    /*uint16_t version =*/ msg.get<uint16_t>();
    msg.skipBytes(12);

    /*
     * Skipped bytes:
     * 4 bytes: protocolVersion
     * 12 bytes: dat, spr, pic signatures (4 bytes each)
     */

    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);

    /*if (version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX) {
        //sendUpdateRequest();
        disconnectClient("Use Tibia 7.72 to login!");
        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;
    }

    uint32_t accountNumber = msg.get<uint32_t>();
    if (!accountNumber) {
        disconnectClient("Invalid account number.");
        return;
    }

    std::string password = msg.getString();
    if (password.empty()) {
        disconnectClient("Invalid password.");
        return;
    }

    auto thisPtr = std::static_pointer_cast<ProtocolLogin>(shared_from_this());
    g_dispatcher.addTask(createTask(std::bind(&ProtocolLogin::getCharacterList, thisPtr, accountNumber, password)));
}

Just noticed I made a mistake regarding the world ID, this should work.
 
mate still the same problem :/
Is MULTIWORLD_SYSTEM even defined in definitions.h or in the preprocessor definitions? See what this prints after requesting the character list.

C++:
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017  Alejandro Mujica <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include "otpch.h"

#include "protocollogin.h"

#include "outputmessage.h"
#include "tasks.h"

#include "configmanager.h"
#include "iologindata.h"
#include "ban.h"
#include "game.h"
#ifdef MULTIWORLD_SYSTEM
    #include "gameworldconfig.h"
#endif

extern ConfigManager g_config;
extern Game g_game;
#ifdef MULTIWORLD_SYSTEM
    extern GameWorldConfig g_gameworld;
#endif

void ProtocolLogin::sendUpdateRequest()
{
    auto output = OutputMessagePool::getOutputMessage();

    output->addByte(0x1E);
    send(output);

    disconnect();
}

void ProtocolLogin::disconnectClient(const std::string& message)
{
    auto output = OutputMessagePool::getOutputMessage();

    output->addByte(0x0A);
    output->addString(message);
    send(output);

    disconnect();
}

void ProtocolLogin::getCharacterList(uint32_t accountNumber, const std::string& password)
{
    Account account;
    if (!IOLoginData::loginserverAuthentication(accountNumber, password, account)) {
        disconnectClient("Account number or password is not correct.");
        return;
    }

    auto output = OutputMessagePool::getOutputMessage();

    //Update premium days
    Game::updatePremium(account);

    const std::string& motd = g_config.getString(ConfigManager::MOTD);
    if (!motd.empty()) {
        //Add MOTD
        output->addByte(0x14);

        std::ostringstream ss;
        ss << g_game.getMotdNum() << "\n" << motd;
        output->addString(ss.str());
    }
   
    output->addByte(0x64);
    
    uint8_t size = std::min<size_t>(std::numeric_limits<uint8_t>::max(), account.characters.size());
    output->addByte(size);

    #ifdef MULTIWORLD_SYSTEM
        //Add char list
        printf("multiworld is defined");

        for (uint8_t i = 0; i < size; i++) {
            output->addString(account.characters[i].name);

            const uint16_t worldId = account.characters[i].worldid;

            output->addString(g_gameworld.getWorldName(worldId));
            output->add<uint32_t>(inet_addr(g_gameworld.getWorldIp(worldId).c_str()));
            output->add<uint16_t>(g_gameworld.getWorldPort(worldId));
        }
    #else
        printf("multiworld is NOT defined");

        //Add char list
        for (uint8_t i = 0; i < size; i++) {
            output->addString(account.characters[i]);
            output->addString(g_config.getString(ConfigManager::SERVER_NAME));
            output->add<uint32_t>(inet_addr(g_config.getString(ConfigManager::IP).c_str()));
            output->add<uint16_t>(g_config.getNumber(ConfigManager::GAME_PORT));
        }
    #endif  
    
    //Add premium days
    if (g_config.getBoolean(ConfigManager::FREE_PREMIUM)) {
        output->add<uint16_t>(0xFFFF);
    } else {
        output->add<uint16_t>(account.premiumDays);
    }

    send(output);

    disconnect();
}

void ProtocolLogin::onRecvFirstMessage(NetworkMessage& msg)
{
    if (g_game.getGameState() == GAME_STATE_SHUTDOWN) {
        disconnect();
        return;
    }

    msg.skipBytes(2); // client OS

    /*uint16_t version =*/ msg.get<uint16_t>();
    msg.skipBytes(12);

    /*
     * Skipped bytes:
     * 4 bytes: protocolVersion
     * 12 bytes: dat, spr, pic signatures (4 bytes each)
     */

    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);

    /*if (version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX) {
        //sendUpdateRequest();
        disconnectClient("Use Tibia 7.72 to login!");
        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;
    }

    uint32_t accountNumber = msg.get<uint32_t>();
    if (!accountNumber) {
        disconnectClient("Invalid account number.");
        return;
    }

    std::string password = msg.getString();
    if (password.empty()) {
        disconnectClient("Invalid password.");
        return;
    }

    auto thisPtr = std::static_pointer_cast<ProtocolLogin>(shared_from_this());
    g_dispatcher.addTask(createTask(std::bind(&ProtocolLogin::getCharacterList, thisPtr, accountNumber, password)));
}
 
Is MULTIWORLD_SYSTEM even defined in definitions.h or in the preprocessor definitions? See what this prints after requesting the character list.

C++:
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017  Alejandro Mujica <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include "otpch.h"

#include "protocollogin.h"

#include "outputmessage.h"
#include "tasks.h"

#include "configmanager.h"
#include "iologindata.h"
#include "ban.h"
#include "game.h"
#ifdef MULTIWORLD_SYSTEM
    #include "gameworldconfig.h"
#endif

extern ConfigManager g_config;
extern Game g_game;
#ifdef MULTIWORLD_SYSTEM
    extern GameWorldConfig g_gameworld;
#endif

void ProtocolLogin::sendUpdateRequest()
{
    auto output = OutputMessagePool::getOutputMessage();

    output->addByte(0x1E);
    send(output);

    disconnect();
}

void ProtocolLogin::disconnectClient(const std::string& message)
{
    auto output = OutputMessagePool::getOutputMessage();

    output->addByte(0x0A);
    output->addString(message);
    send(output);

    disconnect();
}

void ProtocolLogin::getCharacterList(uint32_t accountNumber, const std::string& password)
{
    Account account;
    if (!IOLoginData::loginserverAuthentication(accountNumber, password, account)) {
        disconnectClient("Account number or password is not correct.");
        return;
    }

    auto output = OutputMessagePool::getOutputMessage();

    //Update premium days
    Game::updatePremium(account);

    const std::string& motd = g_config.getString(ConfigManager::MOTD);
    if (!motd.empty()) {
        //Add MOTD
        output->addByte(0x14);

        std::ostringstream ss;
        ss << g_game.getMotdNum() << "\n" << motd;
        output->addString(ss.str());
    }
 
    output->addByte(0x64);
  
    uint8_t size = std::min<size_t>(std::numeric_limits<uint8_t>::max(), account.characters.size());
    output->addByte(size);

    #ifdef MULTIWORLD_SYSTEM
        //Add char list
        printf("multiworld is defined");

        for (uint8_t i = 0; i < size; i++) {
            output->addString(account.characters[i].name);

            const uint16_t worldId = account.characters[i].worldid;

            output->addString(g_gameworld.getWorldName(worldId));
            output->add<uint32_t>(inet_addr(g_gameworld.getWorldIp(worldId).c_str()));
            output->add<uint16_t>(g_gameworld.getWorldPort(worldId));
        }
    #else
        printf("multiworld is NOT defined");

        //Add char list
        for (uint8_t i = 0; i < size; i++) {
            output->addString(account.characters[i]);
            output->addString(g_config.getString(ConfigManager::SERVER_NAME));
            output->add<uint32_t>(inet_addr(g_config.getString(ConfigManager::IP).c_str()));
            output->add<uint16_t>(g_config.getNumber(ConfigManager::GAME_PORT));
        }
    #endif
  
    //Add premium days
    if (g_config.getBoolean(ConfigManager::FREE_PREMIUM)) {
        output->add<uint16_t>(0xFFFF);
    } else {
        output->add<uint16_t>(account.premiumDays);
    }

    send(output);

    disconnect();
}

void ProtocolLogin::onRecvFirstMessage(NetworkMessage& msg)
{
    if (g_game.getGameState() == GAME_STATE_SHUTDOWN) {
        disconnect();
        return;
    }

    msg.skipBytes(2); // client OS

    /*uint16_t version =*/ msg.get<uint16_t>();
    msg.skipBytes(12);

    /*
     * Skipped bytes:
     * 4 bytes: protocolVersion
     * 12 bytes: dat, spr, pic signatures (4 bytes each)
     */

    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);

    /*if (version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX) {
        //sendUpdateRequest();
        disconnectClient("Use Tibia 7.72 to login!");
        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;
    }

    uint32_t accountNumber = msg.get<uint32_t>();
    if (!accountNumber) {
        disconnectClient("Invalid account number.");
        return;
    }

    std::string password = msg.getString();
    if (password.empty()) {
        disconnectClient("Invalid password.");
        return;
    }

    auto thisPtr = std::static_pointer_cast<ProtocolLogin>(shared_from_this());
    g_dispatcher.addTask(createTask(std::bind(&ProtocolLogin::getCharacterList, thisPtr, accountNumber, password)));
}
it is not defined but if i do it then i cant compile
Lua:
#define MULTIWORLD_SYSTEM
in definitions.h
it give me this error with no sucess on compilation
Code:
/home/otsmanager/forgottenserver/src/protocollogin.cpp: In member function ‘void ProtocolLogin::getCharacterList(uint32_t, const string&)’:
/home/otsmanager/forgottenserver/src/protocollogin.cpp:100:77: error: request for member ‘c_str’ in ‘g_gameworld.GameWorldConfig::getWorldIp(((int)((uint16_t)worldId)))’, which is of non-class type ‘const char*’
  100 |      output->add<uint32_t>(inet_addr(g_gameworld.getWorldIp(worldId).c_str()));
      |                                                                      ^~~~~
 
it is not defined but if i do it then i cant compile
Lua:
#define MULTIWORLD_SYSTEM
in definitions.h
it give me this error with no sucess on compilation
Code:
/home/otsmanager/forgottenserver/src/protocollogin.cpp: In member function ‘void ProtocolLogin::getCharacterList(uint32_t, const string&)’:
/home/otsmanager/forgottenserver/src/protocollogin.cpp:100:77: error: request for member ‘c_str’ in ‘g_gameworld.GameWorldConfig::getWorldIp(((int)((uint16_t)worldId)))’, which is of non-class type ‘const char*’
  100 |      output->add<uint32_t>(inet_addr(g_gameworld.getWorldIp(worldId).c_str()));
      |                                                                      ^~~~~
C++:
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017  Alejandro Mujica <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include "otpch.h"

#include "protocollogin.h"

#include "outputmessage.h"
#include "tasks.h"

#include "configmanager.h"
#include "iologindata.h"
#include "ban.h"
#include "game.h"
#ifdef MULTIWORLD_SYSTEM
    #include "gameworldconfig.h"
#endif

extern ConfigManager g_config;
extern Game g_game;
#ifdef MULTIWORLD_SYSTEM
    extern GameWorldConfig g_gameworld;
#endif

void ProtocolLogin::sendUpdateRequest()
{
    auto output = OutputMessagePool::getOutputMessage();

    output->addByte(0x1E);
    send(output);

    disconnect();
}

void ProtocolLogin::disconnectClient(const std::string& message)
{
    auto output = OutputMessagePool::getOutputMessage();

    output->addByte(0x0A);
    output->addString(message);
    send(output);

    disconnect();
}

void ProtocolLogin::getCharacterList(uint32_t accountNumber, const std::string& password)
{
    Account account;
    if (!IOLoginData::loginserverAuthentication(accountNumber, password, account)) {
        disconnectClient("Account number or password is not correct.");
        return;
    }

    auto output = OutputMessagePool::getOutputMessage();

    //Update premium days
    Game::updatePremium(account);

    const std::string& motd = g_config.getString(ConfigManager::MOTD);
    if (!motd.empty()) {
        //Add MOTD
        output->addByte(0x14);

        std::ostringstream ss;
        ss << g_game.getMotdNum() << "\n" << motd;
        output->addString(ss.str());
    }
   
    output->addByte(0x64);
    
    uint8_t size = std::min<size_t>(std::numeric_limits<uint8_t>::max(), account.characters.size());
    output->addByte(size);

    #ifdef MULTIWORLD_SYSTEM
        //Add char list
        printf("multiworld is defined");

        for (uint8_t i = 0; i < size; i++) {
            output->addString(account.characters[i].name);

            const uint16_t worldId = account.characters[i].worldid;

            output->addString(g_gameworld.getWorldName(worldId));
            output->add<uint32_t>(inet_addr(g_gameworld.getWorldIp(worldId)));
            output->add<uint16_t>(g_gameworld.getWorldPort(worldId));
        }
    #else
        printf("multiworld is NOT defined");

        //Add char list
        for (uint8_t i = 0; i < size; i++) {
            output->addString(account.characters[i]);
            output->addString(g_config.getString(ConfigManager::SERVER_NAME));
            output->add<uint32_t>(inet_addr(g_config.getString(ConfigManager::IP).c_str()));
            output->add<uint16_t>(g_config.getNumber(ConfigManager::GAME_PORT));
        }
    #endif  
    
    //Add premium days
    if (g_config.getBoolean(ConfigManager::FREE_PREMIUM)) {
        output->add<uint16_t>(0xFFFF);
    } else {
        output->add<uint16_t>(account.premiumDays);
    }

    send(output);

    disconnect();
}

void ProtocolLogin::onRecvFirstMessage(NetworkMessage& msg)
{
    if (g_game.getGameState() == GAME_STATE_SHUTDOWN) {
        disconnect();
        return;
    }

    msg.skipBytes(2); // client OS

    /*uint16_t version =*/ msg.get<uint16_t>();
    msg.skipBytes(12);

    /*
     * Skipped bytes:
     * 4 bytes: protocolVersion
     * 12 bytes: dat, spr, pic signatures (4 bytes each)
     */

    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);

    /*if (version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX) {
        //sendUpdateRequest();
        disconnectClient("Use Tibia 7.72 to login!");
        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;
    }

    uint32_t accountNumber = msg.get<uint32_t>();
    if (!accountNumber) {
        disconnectClient("Invalid account number.");
        return;
    }

    std::string password = msg.getString();
    if (password.empty()) {
        disconnectClient("Invalid password.");
        return;
    }

    auto thisPtr = std::static_pointer_cast<ProtocolLogin>(shared_from_this());
    g_dispatcher.addTask(createTask(std::bind(&ProtocolLogin::getCharacterList, thisPtr, accountNumber, password)));
}
 
Solution
C++:
/**
* Tibia GIMUD Server - a free and open-source MMORPG server emulator
* Copyright (C) 2017  Alejandro Mujica <[email protected]>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program; if not, write to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/

#include "otpch.h"

#include "protocollogin.h"

#include "outputmessage.h"
#include "tasks.h"

#include "configmanager.h"
#include "iologindata.h"
#include "ban.h"
#include "game.h"
#ifdef MULTIWORLD_SYSTEM
    #include "gameworldconfig.h"
#endif

extern ConfigManager g_config;
extern Game g_game;
#ifdef MULTIWORLD_SYSTEM
    extern GameWorldConfig g_gameworld;
#endif

void ProtocolLogin::sendUpdateRequest()
{
    auto output = OutputMessagePool::getOutputMessage();

    output->addByte(0x1E);
    send(output);

    disconnect();
}

void ProtocolLogin::disconnectClient(const std::string& message)
{
    auto output = OutputMessagePool::getOutputMessage();

    output->addByte(0x0A);
    output->addString(message);
    send(output);

    disconnect();
}

void ProtocolLogin::getCharacterList(uint32_t accountNumber, const std::string& password)
{
    Account account;
    if (!IOLoginData::loginserverAuthentication(accountNumber, password, account)) {
        disconnectClient("Account number or password is not correct.");
        return;
    }

    auto output = OutputMessagePool::getOutputMessage();

    //Update premium days
    Game::updatePremium(account);

    const std::string& motd = g_config.getString(ConfigManager::MOTD);
    if (!motd.empty()) {
        //Add MOTD
        output->addByte(0x14);

        std::ostringstream ss;
        ss << g_game.getMotdNum() << "\n" << motd;
        output->addString(ss.str());
    }
 
    output->addByte(0x64);
  
    uint8_t size = std::min<size_t>(std::numeric_limits<uint8_t>::max(), account.characters.size());
    output->addByte(size);

    #ifdef MULTIWORLD_SYSTEM
        //Add char list
        printf("multiworld is defined");

        for (uint8_t i = 0; i < size; i++) {
            output->addString(account.characters[i].name);

            const uint16_t worldId = account.characters[i].worldid;

            output->addString(g_gameworld.getWorldName(worldId));
            output->add<uint32_t>(inet_addr(g_gameworld.getWorldIp(worldId)));
            output->add<uint16_t>(g_gameworld.getWorldPort(worldId));
        }
    #else
        printf("multiworld is NOT defined");

        //Add char list
        for (uint8_t i = 0; i < size; i++) {
            output->addString(account.characters[i]);
            output->addString(g_config.getString(ConfigManager::SERVER_NAME));
            output->add<uint32_t>(inet_addr(g_config.getString(ConfigManager::IP).c_str()));
            output->add<uint16_t>(g_config.getNumber(ConfigManager::GAME_PORT));
        }
    #endif
  
    //Add premium days
    if (g_config.getBoolean(ConfigManager::FREE_PREMIUM)) {
        output->add<uint16_t>(0xFFFF);
    } else {
        output->add<uint16_t>(account.premiumDays);
    }

    send(output);

    disconnect();
}

void ProtocolLogin::onRecvFirstMessage(NetworkMessage& msg)
{
    if (g_game.getGameState() == GAME_STATE_SHUTDOWN) {
        disconnect();
        return;
    }

    msg.skipBytes(2); // client OS

    /*uint16_t version =*/ msg.get<uint16_t>();
    msg.skipBytes(12);

    /*
     * Skipped bytes:
     * 4 bytes: protocolVersion
     * 12 bytes: dat, spr, pic signatures (4 bytes each)
     */

    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);

    /*if (version < CLIENT_VERSION_MIN || version > CLIENT_VERSION_MAX) {
        //sendUpdateRequest();
        disconnectClient("Use Tibia 7.72 to login!");
        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;
    }

    uint32_t accountNumber = msg.get<uint32_t>();
    if (!accountNumber) {
        disconnectClient("Invalid account number.");
        return;
    }

    std::string password = msg.getString();
    if (password.empty()) {
        disconnectClient("Invalid password.");
        return;
    }

    auto thisPtr = std::static_pointer_cast<ProtocolLogin>(shared_from_this());
    g_dispatcher.addTask(createTask(std::bind(&ProtocolLogin::getCharacterList, thisPtr, accountNumber, password)));
}

ok bro it seems working atleast in characterlist but now i get this error when press enter to log ingame so still not working but we are near to get it
Lua:
Connection failed. (ERROR 1214)
 
Last edited:
i will do for sure it took me too much time without knowleadge to atleast make it compilable, i will do a thread with the correct lines i did change to make it work =)
 
Back
Top