Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion Client/core/CClientVariables.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,6 @@ void CClientVariables::LoadDefaults()
DEFAULT("debugfile", _S("")); // debug filename
DEFAULT("console_pos", CVector2D(0, 0)); // console position
DEFAULT("console_size", CVector2D(200, 200)); // console size
DEFAULT("serverbrowser_size", CVector2D(720.0f, 495.0f)); // serverbrowser size
DEFAULT("fps_limit", 100); // frame limiter
DEFAULT("vsync", true); // vsync
DEFAULT("chat_font", 2); // chatbox font type
Expand Down
29 changes: 29 additions & 0 deletions Client/core/CQueryReceiver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,35 @@ SQueryInfo CQueryReceiver::GetServerResponse()
if (!strHttpPort.empty())
info.httpPort = static_cast<ushort>(atoi(strHttpPort));

// Check if this reply includes rules
if (strncmp(szBuffer + i, "RULES", 5) == 0)
{
g_pCore->GetConsole()->Printf("Parsing rules for server: %s", info.serverName.c_str());

i += 5;
while (i < len)
{
// Check if it's the end of rules
if ((unsigned char)szBuffer[i] == 1)
{
i++;
break;
}

SString key, value;
if (!ReadString(key, szBuffer, i, len))
return info;
if (!ReadString(value, szBuffer, i, len))
return info;

info.rules[key] = value;

g_pCore->GetConsole()->Printf(" Rule: %s = %s", key.c_str(), value.c_str());
}

g_pCore->GetConsole()->Printf("Finished parsing rules");
}

// Get player nicks
while (i < len)
{
Expand Down
1 change: 1 addition & 0 deletions Client/core/CQueryReceiver.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ struct SQueryInfo
ushort pingTime;

std::vector<SString> playersPool;
std::unordered_map<SString, SString> rules;
};

class CQueryReceiver
Expand Down
2 changes: 2 additions & 0 deletions Client/core/ServerBrowser/CServerList.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -573,6 +573,8 @@ bool CServerListItem::ParseQuery()
m_iBuildNumber = info.buildNum;
m_usHttpPort = info.httpPort;

rules = info.rules;

if ((uiMasterServerSaysRestrictions & RESTRICTION_PLAYER_LIST) == false)
vecPlayers = info.playersPool;

Expand Down
1 change: 1 addition & 0 deletions Client/core/ServerBrowser/CServerList.h
Original file line number Diff line number Diff line change
Expand Up @@ -223,6 +223,7 @@ class CServerListItem
CQueryReceiver queryReceiver;

std::vector<SString> vecPlayers;
std::unordered_map<SString, SString> rules;

void Query();

Expand Down
131 changes: 129 additions & 2 deletions Server/mods/deathmatch/logic/ASE.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -187,8 +187,8 @@ void ASE::DoPulse()
break;
}
case 'r':
{ // Our own lighter query for ingame browser - Release version only
strReply = QueryLightCached();
{ // New query for ingame server browser
strReply = QueryNewBrowserCached();
break;
}
case 'x':
Expand Down Expand Up @@ -395,6 +395,133 @@ const std::string* ASE::QueryLightCached()
return &m_strLightCached;
}

// Protect against a flood of server queries.
// Send cached version unless player count has changed, or last re-cache is older than m_lNewMinInterval
const std::string* ASE::QueryNewBrowserCached()
{
if (m_uiCurrentPlayerCount != m_uiNewLastPlayerCount || m_llCurrentTime - m_llNewLastTime > m_lNewMinInterval || m_strNewCached == "")
{
m_strNewCached = QueryNewBrowser();
m_llNewLastTime = m_llCurrentTime;
m_uiNewLastPlayerCount = m_uiCurrentPlayerCount;
}
return &m_strNewCached;
}

std::string ASE::QueryNewBrowser()
{
std::stringstream reply;

int iJoinedPlayers = m_pPlayerManager->CountJoined();
int iMaxPlayers = m_pMainConfig->GetMaxPlayers();
SString strPlayerCount = SString("%d/%d", iJoinedPlayers, iMaxPlayers);
SString strBuildType = SString("%d", MTASA_VERSION_TYPE);
SString strBuildNumber = SString("%d", MTASA_VERSION_BUILD);
SFixedString<32> strPingStatusFixed;
SFixedString<32> strNetRouteFixed;
g_pNetServer->GetPingStatus(&strPingStatusFixed);
g_pNetServer->GetNetRoute(&strNetRouteFixed);
SString strPingStatus = (const char*)strPingStatusFixed;
SString strNetRoute = (const char*)strNetRouteFixed;
SString strUpTime("%d", (uint)(time(NULL) - m_tStartTime));
SString strHttpPort("%d", m_pMainConfig->GetHTTPPort());

uint uiExtraDataLength = (strPlayerCount.length() + 1 + strBuildType.length() + 1 + strBuildNumber.length() + 1 + strPingStatus.length() + 1 +
strNetRoute.length() + 1 + strUpTime.length() + 1 + strHttpPort.length() + 1);
uint uiMaxMapNameLength = 250 - uiExtraDataLength;
m_strMapName = m_strMapName.Left(uiMaxMapNameLength);

reply << "EYE2";
// game
reply << (unsigned char)4;
reply << "mta";
// port
reply << (unsigned char)(m_strPort.length() + 1);
reply << m_strPort;
// server name
reply << (unsigned char)(m_pMainConfig->GetServerName().length() + 1);
reply << m_pMainConfig->GetServerName();
// game type
reply << (unsigned char)(m_strGameType.length() + 1);
reply << m_strGameType;
// map name with backwardly compatible large player count, build type and build number
reply << (unsigned char)(m_strMapName.length() + 1 + uiExtraDataLength);
reply << m_strMapName;
reply << (unsigned char)0;
reply << strPlayerCount;
reply << (unsigned char)0;
reply << strBuildType;
reply << (unsigned char)0;
reply << strBuildNumber;
reply << (unsigned char)0;
reply << strPingStatus;
reply << (unsigned char)0;
reply << strNetRoute;
reply << (unsigned char)0;
reply << strUpTime;
reply << (unsigned char)0;
reply << strHttpPort;
// version
std::string temp = MTA_DM_ASE_VERSION;
reply << (unsigned char)(temp.length() + 1);
reply << temp;
// passworded
reply << (unsigned char)((m_pMainConfig->HasPassword()) ? 1 : 0);
// serial verification?
reply << (unsigned char)((m_pMainConfig->GetSerialVerificationEnabled()) ? 1 : 0);
// players count
reply << (unsigned char)std::min(iJoinedPlayers, 255);
// players max
reply << (unsigned char)std::min(iMaxPlayers, 255);

// rules - this informs this response contains them
// previous version of this query did not have rules
reply << "RULES";

// send a max of 20 rules
list<CASERule*>::iterator rIter = IterBegin();
int rulesCount = 0;
for (; rIter != IterEnd() && rulesCount < 20; rIter++)
{
reply << (unsigned char)(strlen((*rIter)->GetKey()) + 1);
reply << (*rIter)->GetKey();
reply << (unsigned char)(strlen((*rIter)->GetValue()) + 1);
reply << (*rIter)->GetValue();
rulesCount++;
}
reply << (unsigned char)1;

// players
CPlayer* pPlayer = NULL;

// Keep the packet under 1350 bytes to try to avoid fragmentation
int iBytesLeft = 1340 - (int)reply.tellp();
int iPlayersLeft = iJoinedPlayers;

list<CPlayer*>::const_iterator pIter = m_pPlayerManager->IterBegin();
for (; pIter != m_pPlayerManager->IterEnd(); pIter++)
{
pPlayer = *pIter;
if (pPlayer->IsJoined())
{
// nick
std::string strPlayerName = RemoveColorCodes(pPlayer->GetNick());
if (strPlayerName.length() == 0)
strPlayerName = pPlayer->GetNick();

// Check if we can fit more names
iBytesLeft -= strPlayerName.length() + 1;
if (iBytesLeft < iPlayersLeft--)
strPlayerName = "";

reply << (unsigned char)(strPlayerName.length() + 1);
reply << strPlayerName.c_str();
}
}

return reply.str();
}

std::string ASE::QueryLight()
{
std::stringstream reply;
Expand Down
8 changes: 8 additions & 0 deletions Server/mods/deathmatch/logic/ASE.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,8 @@ class ASE
const std::string* QueryFullCached();
std::string QueryFull();
const std::string* QueryLightCached();
std::string QueryNewBrowser();
const std::string* QueryNewBrowserCached();
const std::string* QueryXfireLightCached();
std::string QueryXfireLight();

Expand Down Expand Up @@ -120,6 +122,12 @@ class ASE
long m_lLightMinInterval;
std::string m_strLightCached;

// New query cache
unsigned int m_uiNewLastPlayerCount;
long long m_llNewLastTime;
long m_lNewMinInterval;
std::string m_strNewCached;

// XFire Light query cache
unsigned int m_uiXfireLightLastPlayerCount;
long long m_llXfireLightLastTime;
Expand Down