-
-
Notifications
You must be signed in to change notification settings - Fork 775
Description
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