• 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!

Count only 4 player otservlist status.cpp

CastorFlynn

Member
Joined
Aug 29, 2021
Messages
88
Reaction score
8
I'm trying to configure the source to respect the otservlist rules. Using this code from this post, and with 7 player online on the same IP for example it registers 5 as online in otservelist. What can be wrong?

I change status.cpp this:
C++:
sprintf(buffer, "%d", g_game.getPlayersOnline());
xmlSetProp(p, (const xmlChar*)"online", (const xmlChar*)buffer);
To:
C++:
uint32_t real = 0;
std::map<uint32_t, uint32_t> listIP;
for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it) {
   if (it->second->getIP() != 0) {
         if (listIP.find(it->second->getIP()) != listIP.end()) {
             listIP[it->second->getIP()]++;
             if (listIP[it->second->getIP()] < 5) {
               real++;
             }
         } else {
           listIP[it->second->getIP()] = 1;
             real++;
         }
       }
}
sprintf(buffer, "%d", real);
xmlSetProp(p, (const xmlChar*)"online", (const xmlChar*)buffer);
 
I believe the requirement is to not send more than 4 players; so just change 5 to 4.

C++:
sprintf(buffer, "%d", g_game.getPlayersOnline());
xmlSetProp(p, (const xmlChar*)"online", (const xmlChar*)buffer);
To:
C++:
uint32_t real = 0;
std::map<uint32_t, uint32_t> listIP;
for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it) {
   if (it->second->getIP() != 0) {
         if (listIP.find(it->second->getIP()) != listIP.end()) {
             listIP[it->second->getIP()]++;
             if (listIP[it->second->getIP()] < 4) {
               real++;
             }
         } else {
           listIP[it->second->getIP()] = 1;
             real++;
         }
       }
}
sprintf(buffer, "%d", real);
xmlSetProp(p, (const xmlChar*)"online", (const xmlChar*)buffer);
 
I believe the requirement is to not send more than 4 players; so just change 5 to 4.

C++:
sprintf(buffer, "%d", g_game.getPlayersOnline());
xmlSetProp(p, (const xmlChar*)"online", (const xmlChar*)buffer);
To:
C++:
uint32_t real = 0;
std::map<uint32_t, uint32_t> listIP;
for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it) {
   if (it->second->getIP() != 0) {
         if (listIP.find(it->second->getIP()) != listIP.end()) {
             listIP[it->second->getIP()]++;
             if (listIP[it->second->getIP()] < 4) {
               real++;
             }
         } else {
           listIP[it->second->getIP()] = 1;
             real++;
         }
       }
}
sprintf(buffer, "%d", real);
xmlSetProp(p, (const xmlChar*)"online", (const xmlChar*)buffer);
I try that, but still count 5 with 7 online.
 
If you use linux - try entering this before compiling to clean .o files to ensure it is registering changes.
Code:
sudo rm *.o
or
Code:
sudo make clean

Not sure why it wouldn't work since it seems like thats the checker.
 
If you use linux - try entering this before compiling to clean .o files to ensure it is registering changes.
Code:
sudo rm *.o
or
Code:
sudo make clean

Not sure why it wouldn't work since it seems like thats the checker.
I always compile using make clean, but thanks for the suggestions.
 
Can you please upload your status.cpp to pastebin; if that is not resolving the issue need to scan the entire file for possibly a duplication of the code thats overwriting what happens in the currently provided code.

Previous related issues point to some +1 in the script. Can you test changing the number to something like 2 or 3 and then testing if the number changes on OTServList; this way we can check if the code above is actually doing anything.

Alternative:
Can also use this - How to NOT count x-logged players? (https://otland.net/threads/how-to-not-count-x-logged-players.81370/)
Then in [creaturescripts/scripts create antimc.lua
<event type="login" name="AntiMC" event="script" value="antimc.lua"/>

Lua:
local config = {
max = 4, -- Maximum Clients Allowed Connected
text = "Sorry, we only allow up to 4 Multi-Clients.", -- PopupFYI Text
group_id = 1 -- This will only kick players with Group 1 (Player)
}

local accepted_ip_list = "127.0.0.1" -- IP's allowed to MC

local function AntiMC(p)
    if #getPlayersByIp(getPlayerIp(p.pid)) >= p.max then
        doPlayerPopupFYI(p.pid, config.text)
        addEvent(doRemoveCreature, 2500, p.pid)
    end
    return TRUE
end

function onLogin(cid)
    if getPlayerGroupId(cid) <= config.group_id then
        if isInArray(accepted_ip_list,getPlayerIp(cid)) == FALSE then
                addEvent(AntiMC, 1000, {pid = cid, max = config.max+1})
            end
        end
    return TRUE
end

On creaturescripts/scripts/login.lua
Code:
registerCreatureEvent(cid, "AntiMC") -- Anti Multi Client (Max: 4)

You can use the creaturescript until you figure out what is wrong with your sources; although it can also be a final solution.
 
Last edited:
status.cpp
C++:
#include "otpch.h"
#include <libxml/xmlmemory.h>
#include <libxml/parser.h>

#include "status.h"
#include "const.h"
#include "tools.h"

#include "connection.h"
#include "networkmessage.h"
#include "outputmessage.h"

#include "configmanager.h"
#include "game.h"
#include "resources.h"

extern ConfigManager g_config;
extern Game g_game;

std::map<uint32_t, int64_t> ProtocolStatus::ipConnectMap;
const uint64_t ProtocolStatus::start = OTSYS_TIME();

enum RequestedInfo_t : uint16_t {
    REQUEST_BASIC_SERVER_INFO = 1 << 0,
    REQUEST_OWNER_SERVER_INFO = 1 << 1,
    REQUEST_MISC_SERVER_INFO = 1 << 2,
    REQUEST_PLAYERS_INFO = 1 << 3,
    REQUEST_MAP_INFO = 1 << 4,
    REQUEST_EXT_PLAYERS_INFO = 1 << 5,
    REQUEST_PLAYER_STATUS_INFO = 1 << 6,
    REQUEST_SERVER_SOFTWARE_INFO = 1 << 7,
};

void ProtocolStatus::onRecvFirstMessage(NetworkMessage& msg)
{
    uint32_t ip = getIP();
    if (ip != 0x0100007F) {
        std::map<uint32_t, int64_t>::const_iterator it = ipConnectMap.find(ip);
        if (it != ipConnectMap.end() && (OTSYS_TIME() < (it->second + g_config.getNumber(ConfigManager::STATUSQUERY_TIMEOUT)))) {
            disconnect();
            return;
        }
    }

    ipConnectMap[ip] = OTSYS_TIME();

    uint8_t type = msg.get<char>();
    switch(type)
    {
        case 0xFF:
        {
            if(msg.getString(4) == "info")
            {
                Dispatcher::getInstance().addTask(createTask(std::bind(&ProtocolStatus::sendStatusString,
                                      std::static_pointer_cast<ProtocolStatus>(shared_from_this()))));
                return;
            }

            break;
        }

        case 0x01:
        {
            uint32_t requestedInfo = msg.get<uint16_t>(); // only a byte is necessary, though we could add new infos here
            std::string characterName;
            if (requestedInfo & REQUEST_PLAYER_STATUS_INFO)
                characterName = msg.getString();

            Dispatcher::getInstance().addTask(createTask(std::bind(&ProtocolStatus::sendInfo, std::dynamic_pointer_cast<ProtocolStatus>(shared_from_this()),
                requestedInfo, characterName)));
            return;
        }

        default:
            break;
    }

    disconnect();
}

void ProtocolStatus::sendStatusString()
{
    auto output = OutputMessagePool::getOutputMessage();

    setRawMessages(true);

    xmlDocPtr doc = xmlNewDoc((const xmlChar*)"1.0");
    doc->children = xmlNewDocNode(doc, NULL, (const xmlChar*)"tsqp", NULL);
    xmlNodePtr root = doc->children;

    char buffer[90];
    xmlSetProp(root, (const xmlChar*)"version", (const xmlChar*)"1.0");

    xmlNodePtr p = xmlNewNode(NULL,(const xmlChar*)"serverinfo");
    sprintf(buffer, "%u", (uint32_t)((OTSYS_TIME() - ProtocolStatus::start) / 1000));
    xmlSetProp(p, (const xmlChar*)"uptime", (const xmlChar*)buffer);
    xmlSetProp(p, (const xmlChar*)"ip", (const xmlChar*)g_config.getString(ConfigManager::IP).c_str());
    xmlSetProp(p, (const xmlChar*)"servername", (const xmlChar*)g_config.getString(ConfigManager::SERVER_NAME).c_str());
    sprintf(buffer, "%d", (int32_t)g_config.getNumber(ConfigManager::LOGIN_PORT));
    xmlSetProp(p, (const xmlChar*)"port", (const xmlChar*)buffer);
    xmlSetProp(p, (const xmlChar*)"location", (const xmlChar*)g_config.getString(ConfigManager::LOCATION).c_str());
    xmlSetProp(p, (const xmlChar*)"url", (const xmlChar*)g_config.getString(ConfigManager::URL).c_str());
    xmlSetProp(p, (const xmlChar*)"server", (const xmlChar*)SOFTWARE_NAME);
    xmlSetProp(p, (const xmlChar*)"version", (const xmlChar*)SOFTWARE_VERSION);
    xmlSetProp(p, (const xmlChar*)"client", (const xmlChar*)CLIENT_VERSION_STRING);
    xmlAddChild(root, p);

    p = xmlNewNode(NULL,(const xmlChar*)"owner");
    xmlSetProp(p, (const xmlChar*)"name", (const xmlChar*)g_config.getString(ConfigManager::OWNER_NAME).c_str());
    xmlSetProp(p, (const xmlChar*)"email", (const xmlChar*)g_config.getString(ConfigManager::OWNER_EMAIL).c_str());
    xmlAddChild(root, p);

    p = xmlNewNode(NULL,(const xmlChar*)"players");
    sprintf(buffer, "%d", g_game.getPlayersWithMcLimit());
    xmlSetProp(p, (const xmlChar*)"online", (const xmlChar*)buffer);
    sprintf(buffer, "%d", (int32_t)g_config.getNumber(ConfigManager::MAX_PLAYERS));
    xmlSetProp(p, (const xmlChar*)"max", (const xmlChar*)buffer);
    sprintf(buffer, "%d", g_game.getPlayersRecord());
    xmlSetProp(p, (const xmlChar*)"peak", (const xmlChar*)buffer);
    xmlAddChild(root, p);

    p = xmlNewNode(NULL,(const xmlChar*)"monsters");
    sprintf(buffer, "%d", g_game.getMonstersOnline());
    xmlSetProp(p, (const xmlChar*)"total", (const xmlChar*)buffer);
    xmlAddChild(root, p);

    p = xmlNewNode(NULL,(const xmlChar*)"npcs");
uint32_t real = 0;
std::map<uint32_t, uint32_t> listIP;
for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it) {
   if (it->second->getIP() != 0) {
         if (listIP.find(it->second->getIP()) != listIP.end()) {
             listIP[it->second->getIP()]++;
             if (listIP[it->second->getIP()] < 5) {
               real++;
             }
         } else {
           listIP[it->second->getIP()] = 1;
             real++;
         }
       }
}
sprintf(buffer, "%d", real);
xmlSetProp(p, (const xmlChar*)"online", (const xmlChar*)buffer);
    xmlAddChild(root, p);

    p = xmlNewNode(NULL,(const xmlChar*)"map");
    xmlSetProp(p, (const xmlChar*)"name", (const xmlChar*)g_config.getString(ConfigManager::MAP_NAME).c_str());
    xmlSetProp(p, (const xmlChar*)"author", (const xmlChar*)g_config.getString(ConfigManager::MAP_AUTHOR).c_str());

    uint32_t mapWidth, mapHeight;
    g_game.getMapDimensions(mapWidth, mapHeight);
    sprintf(buffer, "%u", mapWidth);
    xmlSetProp(p, (const xmlChar*)"width", (const xmlChar*)buffer);
    sprintf(buffer, "%u", mapHeight);

    xmlSetProp(p, (const xmlChar*)"height", (const xmlChar*)buffer);
    xmlAddChild(root, p);

    xmlNewTextChild(root, NULL, (const xmlChar*)"motd", (const xmlChar*)g_config.getString(ConfigManager::MOTD).c_str());

    xmlChar* s = NULL;
    int32_t len = 0;
    xmlDocDumpMemory(doc, (xmlChar**)&s, &len);

    std::string xml;
    if(s)
        xml = std::string((char*)s, len);

    xmlFree(s);
    xmlFreeDoc(doc);

    output->addBytes(xml.c_str(), xml.size());
    send(output);
    disconnect();
}

void ProtocolStatus::sendInfo(uint16_t requestedInfo, const std::string& characterName)
{
    auto output = OutputMessagePool::getOutputMessage();

    if(requestedInfo & REQUEST_BASIC_SERVER_INFO)
    {
        output->addByte(0x10);
        output->addString(g_config.getString(ConfigManager::SERVER_NAME).c_str());
        output->addString(g_config.getString(ConfigManager::IP).c_str());

        char buffer[10];
        sprintf(buffer, "%d", (int32_t)g_config.getNumber(ConfigManager::LOGIN_PORT));
        output->addString(buffer);
    }

    if (requestedInfo & REQUEST_OWNER_SERVER_INFO)
    {
        output->addByte(0x11);
        output->addString(g_config.getString(ConfigManager::OWNER_NAME).c_str());
        output->addString(g_config.getString(ConfigManager::OWNER_EMAIL).c_str());
    }

    if(requestedInfo & REQUEST_MISC_SERVER_INFO)
    {
        output->addByte(0x12);
        output->addString(g_config.getString(ConfigManager::MOTD).c_str());
        output->addString(g_config.getString(ConfigManager::LOCATION).c_str());
        output->addString(g_config.getString(ConfigManager::URL).c_str());

        output->add<uint64_t>((OTSYS_TIME() - ProtocolStatus::start) / 1000);
    }

    if(requestedInfo & REQUEST_PLAYERS_INFO)
    {
        output->addByte(0x20);
        output->add<uint32_t>(g_game.getPlayersOnline());
        output->add<uint32_t>((uint32_t)g_config.getNumber(ConfigManager::MAX_PLAYERS));
        output->add<uint32_t>(g_game.getPlayersRecord());
    }

    if(requestedInfo & REQUEST_MAP_INFO)
    {
        output->addByte(0x30);
        output->addString(g_config.getString(ConfigManager::MAP_NAME).c_str());
        output->addString(g_config.getString(ConfigManager::MAP_AUTHOR).c_str());

        uint32_t mapWidth, mapHeight;
        g_game.getMapDimensions(mapWidth, mapHeight);
        output->add<uint16_t>(mapWidth);
        output->add<uint16_t>(mapHeight);
    }

    if(requestedInfo & REQUEST_EXT_PLAYERS_INFO)
    {
        output->addByte(0x21);
        std::list<std::pair<std::string, uint32_t> > players;
        for(AutoList<Player>::iterator it = Player::autoList.begin(); it != Player::autoList.end(); ++it)
        {
            if(!it->second->isRemoved() && !it->second->isGhost())
                players.push_back(std::make_pair(it->second->getName(), it->second->getLevel()));
        }

        output->add<uint32_t>(players.size());
        for(std::list<std::pair<std::string, uint32_t> >::iterator it = players.begin(); it != players.end(); ++it)
        {
            output->addString(it->first);
            output->add<uint32_t>(it->second);
        }
    }

    if(requestedInfo & REQUEST_PLAYER_STATUS_INFO)
    {
        output->addByte(0x22);

        Player* p = NULL;
        if(g_game.getPlayerByNameWildcard(characterName, p) == RET_NOERROR && !p->isGhost())
            output->addByte(0x01);
        else
            output->addByte(0x00);
    }

    if(requestedInfo & REQUEST_SERVER_SOFTWARE_INFO)
    {
        output->addByte(0x23);
        output->addString(SOFTWARE_NAME);
        output->addString(SOFTWARE_VERSION);
        output->addString(CLIENT_VERSION_STRING);
    }

    send(output);
    disconnect();
}

The intention is just not to count the number of excess players, I don't intend to limit the players with antimc

I will try put a lower number on code.
 
Back
Top