Skip to content

Disruptive player counting reports #3785

@joelslamospersson

Description

@joelslamospersson

Priority

Low

Area

  • Datapack
  • Source
  • Map
  • Other

What happened?

The problem
Two different protocols report player counts differently:
XML status protocol (sendStatusString()) — IP-filtered

Protocolstatus.cpp lines 108-125 ( At the time of my editing )

pugi::xml_node players = tsqp.append_child("players");
uint32_t real = 0;
std::map<uint32_t, uint32_t> listIP;
for (const auto &[key, player] : g_game().getPlayers()) {
    if (player->getIP() != 0) {
        auto ip = listIP.find(player->getIP());
        if (ip != listIP.end()) {
            listIP[player->getIP()]++;
            if (listIP[player->getIP()] < 5) {  // Only counts first 4 per IP
                real++;
            }
        } else {
            listIP[player->getIP()] = 1;
            real++;
        }
    }
}
players.append_attribute("online") = std::to_string(real).c_str();  // IP-filtered count

This counts up to 4 players per IP.
Binary protocol (sendInfo()) — no IP filtering
protocolstatus.cpp lines-187-192

if (requestedInfo & REQUEST_PLAYERS_INFO) {
    output->addByte(0x20);
    output->add<uint32_t>(static_cast<uint32_t>(g_game().getPlayersOnline()));  // Actual count
    output->add<uint32_t>(g_configManager().getNumber(MAX_PLAYERS));
    output->add<uint32_t>(g_game().getPlayersRecord());
}

This uses g_game().getPlayersOnline(), which returns:
game.hpp lines 181-183

size_t getPlayersOnline() const {
    return players.size();  // Returns ALL players, no IP filtering
}

Impact
XML status (used by otservlist.net): shows IP-filtered count (max 4 per IP)
Binary protocol (used by some server browsers/clients): shows actual player count
Example:
10 players from IP x
XML: 4
Binary: 10

This inconsistency can cause ( Can ):
Different counts between protocols
Potential otservlist bans if the binary protocol is used for reporting by fault or by meaning
Confusion for server browsers ( Issue I've encountered )

Updated code:
protocolstatus.hpp,
under:
void sendInfo(uint16_t requestedInfo, const std::string &characterName) const;

Add:
static uint32_t getIPFilteredPlayerCount();

Under this function:
void ProtocolStatus::onRecvFirstMessage(NetworkMessage &msg) {

Add this new function:

uint32_t ProtocolStatus::getIPFilteredPlayerCount() {
	uint32_t real = 0;
	std::map<uint32_t, uint32_t> listIP;
	for (const auto &[key, player] : g_game().getPlayers()) {
		if (player->getIP() != 0) {
			auto ip = listIP.find(player->getIP());
			if (ip != listIP.end()) {
				listIP[player->getIP()]++;
				if (listIP[player->getIP()] < 5) {
					real++;
				}
			} else {
				listIP[player->getIP()] = 1;
				real++;
			}
		}
	}
	return real;
}

Remove:

uint32_t real = 0;
    std::map<uint32_t, uint32_t> listIP;
    for (const auto &[key, player] : g_game().getPlayers()) {
        if (player->getIP() != 0) {
            auto ip = listIP.find(player->getIP());
            if (ip != listIP.end()) {
                listIP[player->getIP()]++;
                if (listIP[player->getIP()] < 5) {
                    real++;
                }
            } else {
                listIP[player->getIP()] = 1;
                real++;
            }
        }
    }
    players.append_attribute("online") = std::to_string(real).c_str();

Add:
players.append_attribute("online") = std::to_string(getIPFilteredPlayerCount()).c_str();

Edit this:

if (requestedInfo & REQUEST_PLAYERS_INFO) {
		output->addByte(0x20);
                ->Remove this: output->add<uint32_t>(static_cast<uint32_t>(g_game().getPlayersOnline()));
		->Add this: output->add<uint32_t>(getIPFilteredPlayerCount());
		output->add<uint32_t>(g_configManager().getNumber(MAX_PLAYERS));
		output->add<uint32_t>(g_game().getPlayersRecord());
	}

Please review this code before using it yourself
https://otland.net/threads/otservlist-ban-c-code-to-count-online.276146/

What OS are you seeing the problem on?

Linux

Code of Conduct

  • I agree to follow this project's Code of Conduct

Metadata

Metadata

Assignees

No one assigned

    Labels

    Priority: LowMinor impactStatus: Pending TestThis PR or Issue requires more testingType: BugInconsistencies or issues which will cause an issue or problem for users or implementors.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions