Compare commits

...

4 commits

Author SHA1 Message Date
Dennis Felsing 3489131d78
Merge pull request #8085 from dobrykafe/pr-timecp
Improve `/timecp` chat command
2024-03-11 07:34:54 +00:00
Dennis Felsing 621b201acf
Merge pull request #8086 from furo321/browser-login-filter
Add a `No login required` filter
2024-03-11 07:33:21 +00:00
furo 40f641b0a6 Add a No login required filter 2024-03-11 02:09:16 +01:00
dobrykafe 35c45cf869 improve /timecp chat command 2024-03-11 00:36:07 +01:00
14 changed files with 104 additions and 2 deletions

View file

@ -445,6 +445,8 @@ void CServerBrowser::Filter()
Filtered = true;
else if(g_Config.m_BrFilterUnfinishedMap && Info.m_HasRank == CServerInfo::RANK_RANKED)
Filtered = true;
else if(g_Config.m_BrFilterLogin && Info.m_RequiresLogin)
Filtered = true;
else
{
if(!Communities().empty())
@ -597,6 +599,7 @@ int CServerBrowser::SortHash() const
i |= g_Config.m_BrFilterUnfinishedMap << 13;
i |= g_Config.m_BrFilterCountry << 14;
i |= g_Config.m_BrFilterConnectingPlayers << 15;
i |= g_Config.m_BrFilterLogin << 16;
return i;
}

View file

@ -2315,6 +2315,7 @@ void CServer::UpdateRegisterServerInfo()
"},"
"\"version\":\"%s\","
"\"client_score_kind\":\"time\","
"\"requires_login\":false,"
"\"clients\":[",
MaxClients,
MaxPlayers,

View file

@ -117,6 +117,7 @@ public:
char m_aAddress[MAX_SERVER_ADDRESSES * NETADDR_MAXSTRSIZE];
CClient m_aClients[SERVERINFO_MAX_CLIENTS];
int m_NumFilteredPlayers;
bool m_RequiresLogin;
static int EstimateLatency(int Loc1, int Loc2);
static bool ParseLocation(int *pResult, const char *pString);

View file

@ -285,6 +285,7 @@ MACRO_CONFIG_INT(BrFilterGametypeStrict, br_filter_gametype_strict, 0, 0, 1, CFG
MACRO_CONFIG_INT(BrFilterConnectingPlayers, br_filter_connecting_players, 1, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Filter connecting players")
MACRO_CONFIG_STR(BrFilterServerAddress, br_filter_serveraddress, 128, "", CFGFLAG_SAVE | CFGFLAG_CLIENT, "Server address to filter")
MACRO_CONFIG_INT(BrFilterUnfinishedMap, br_filter_unfinished_map, 0, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Show only servers with unfinished maps")
MACRO_CONFIG_INT(BrFilterLogin, br_filter_login, 1, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Filter out servers that require login")
MACRO_CONFIG_INT(BrIndicateFinished, br_indicate_finished, 1, 0, 1, CFGFLAG_SAVE | CFGFLAG_CLIENT, "Show whether you have finished a DDNet map (transmits your player name to info.ddnet.org/info)")
MACRO_CONFIG_STR(BrLocation, br_location, 16, "auto", CFGFLAG_SAVE | CFGFLAG_CLIENT, "Override location for ping estimation, available: auto, af, as, as:cn, eu, na, oc, sa (Automatic, Africa, Asia, China, Europe, North America, Oceania/Australia, South America")

View file

@ -71,6 +71,8 @@ bool CServerInfo2::FromJsonRaw(CServerInfo2 *pOut, const json_value *pJson)
const json_value &MapName = ServerInfo["map"]["name"];
const json_value &Version = ServerInfo["version"];
const json_value &Clients = ServerInfo["clients"];
const json_value &RequiresLogin = ServerInfo["requires_login"];
Error = false;
Error = Error || MaxClients.type != json_integer;
Error = Error || MaxPlayers.type != json_integer;
@ -96,6 +98,11 @@ bool CServerInfo2::FromJsonRaw(CServerInfo2 *pOut, const json_value *pJson)
{
pOut->m_ClientScoreKind = CServerInfo::CLIENT_SCORE_KIND_TIME;
}
pOut->m_RequiresLogin = false;
if(RequiresLogin.type == json_boolean)
{
pOut->m_RequiresLogin = RequiresLogin;
}
pOut->m_Passworded = Passworded;
str_copy(pOut->m_aGameType, GameType);
str_copy(pOut->m_aName, Name);
@ -196,6 +203,7 @@ bool CServerInfo2::operator==(const CServerInfo2 &Other) const
Unequal = Unequal || str_comp(m_aName, Other.m_aName) != 0;
Unequal = Unequal || str_comp(m_aMapName, Other.m_aMapName) != 0;
Unequal = Unequal || str_comp(m_aVersion, Other.m_aVersion) != 0;
Unequal = Unequal || m_RequiresLogin != Other.m_RequiresLogin;
if(Unequal)
{
return false;
@ -225,6 +233,7 @@ CServerInfo2::operator CServerInfo() const
Result.m_MaxPlayers = m_MaxPlayers;
Result.m_NumPlayers = m_NumPlayers;
Result.m_ClientScoreKind = m_ClientScoreKind;
Result.m_RequiresLogin = m_RequiresLogin;
Result.m_Flags = m_Passworded ? SERVER_FLAG_PASSWORD : 0;
str_copy(Result.m_aGameType, m_aGameType);
str_copy(Result.m_aName, m_aName);

View file

@ -38,6 +38,7 @@ public:
char m_aName[64];
char m_aMapName[MAX_MAP_LENGTH];
char m_aVersion[32];
bool m_RequiresLogin;
bool operator==(const CServerInfo2 &Other) const;
bool operator!=(const CServerInfo2 &Other) const { return !(*this == Other); }

View file

@ -660,6 +660,10 @@ void CMenus::RenderServerbrowserFilters(CUIRect View)
if(DoButton_CheckBox(&g_Config.m_BrFilterPw, Localize("No password"), g_Config.m_BrFilterPw, &Button))
g_Config.m_BrFilterPw ^= 1;
View.HSplitTop(RowHeight, &Button, &View);
if(DoButton_CheckBox(&g_Config.m_BrFilterLogin, Localize("No login required"), g_Config.m_BrFilterLogin, &Button))
g_Config.m_BrFilterLogin ^= 1;
View.HSplitTop(RowHeight, &Button, &View);
if(DoButton_CheckBox(&g_Config.m_BrFilterGametypeStrict, Localize("Strict gametype filter"), g_Config.m_BrFilterGametypeStrict, &Button))
g_Config.m_BrFilterGametypeStrict ^= 1;
@ -798,6 +802,7 @@ void CMenus::ResetServerbrowserFilters()
g_Config.m_BrFilterGametypeStrict = 0;
g_Config.m_BrFilterConnectingPlayers = 1;
g_Config.m_BrFilterServerAddress[0] = '\0';
g_Config.m_BrFilterLogin = true;
if(g_Config.m_UiPage != PAGE_LAN)
{

View file

@ -1949,5 +1949,5 @@ void CGameContext::ConTimeCP(IConsole::IResult *pResult, void *pUserData)
return;
const char *pName = pResult->GetString(0);
pSelf->Score()->LoadPlayerData(pResult->m_ClientId, pName);
pSelf->Score()->LoadPlayerTimeCp(pResult->m_ClientId, pName);
}

View file

@ -1445,7 +1445,7 @@ void CCharacter::SetTimeCheckpoint(int TimeCheckpoint)
if(m_pPlayer->GetClientVersion() >= VERSION_DDRACE)
{
CPlayerData *pData = GameServer()->Score()->PlayerData(m_pPlayer->GetCid());
if(pData->m_BestTime && pData->m_aBestTimeCp[m_LastTimeCp] != 0.0f)
if(pData->m_aBestTimeCp[m_LastTimeCp] != 0.0f)
{
CNetMsg_Sv_DDRaceTime Msg;
Msg.m_Time = (int)(m_Time * 100.0f);

View file

@ -910,6 +910,7 @@ void CPlayer::ProcessScoreResult(CScorePlayerResult &Result)
GameServer()->CallVote(m_ClientId, Result.m_Data.m_MapVote.m_aMap, aCmd, "/map", aChatmsg);
break;
case CScorePlayerResult::PLAYER_INFO:
{
if(Result.m_Data.m_Info.m_Time.has_value())
{
GameServer()->Score()->PlayerData(m_ClientId)->Set(Result.m_Data.m_Info.m_Time.value(), Result.m_Data.m_Info.m_aTimeCp);
@ -933,5 +934,13 @@ void CPlayer::ProcessScoreResult(CScorePlayerResult &Result)
GameServer()->SendRecord(m_ClientId);
break;
}
case CScorePlayerResult::PLAYER_TIMECP:
GameServer()->Score()->PlayerData(m_ClientId)->SetBestTimeCp(Result.m_Data.m_Info.m_aTimeCp);
char aBuf[128], aTime[32];
str_time_float(Result.m_Data.m_Info.m_Time.value(), TIME_HOURS_CENTISECS, aTime, sizeof(aTime));
str_format(aBuf, sizeof(aBuf), "Showing the checkpoint times for '%s' with a race time of %s", Result.m_Data.m_Info.m_aRequestedPlayer, aTime);
GameServer()->SendChatTarget(m_ClientId, aBuf);
break;
}
}
}

View file

@ -126,6 +126,11 @@ void CScore::LoadPlayerData(int ClientId, const char *pName)
ExecPlayerThread(CScoreWorker::LoadPlayerData, "load player data", ClientId, pName, 0);
}
void CScore::LoadPlayerTimeCp(int ClientId, const char *pName)
{
ExecPlayerThread(CScoreWorker::LoadPlayerTimeCp, "load player timecp", ClientId, pName, 0);
}
void CScore::MapVote(int ClientId, const char *pMapName)
{
if(RateLimitPlayer(ClientId))

View file

@ -48,6 +48,7 @@ public:
void MapInfo(int ClientId, const char *pMapName);
void MapVote(int ClientId, const char *pMapName);
void LoadPlayerData(int ClientId, const char *pName = "");
void LoadPlayerTimeCp(int ClientId, const char *pName = "");
void SaveScore(int ClientId, float Time, const char *pTimestamp, const float aTimeCp[NUM_CHECKPOINTS], bool NotEligible);
void SaveTeamScore(int *pClientIds, unsigned int Size, float Time, const char *pTimestamp);

View file

@ -43,6 +43,13 @@ void CScorePlayerResult::SetVariant(Variant v)
m_Data.m_Info.m_Time.reset();
for(float &TimeCp : m_Data.m_Info.m_aTimeCp)
TimeCp = 0;
break;
case PLAYER_TIMECP:
m_Data.m_Info.m_aRequestedPlayer[0] = '\0';
m_Data.m_Info.m_Time.reset();
for(float &TimeCp : m_Data.m_Info.m_aTimeCp)
TimeCp = 0;
break;
}
}
@ -203,6 +210,56 @@ bool CScoreWorker::LoadPlayerData(IDbConnection *pSqlServer, const ISqlData *pGa
return false;
}
bool CScoreWorker::LoadPlayerTimeCp(IDbConnection *pSqlServer, const ISqlData *pGameData, char *pError, int ErrorSize)
{
const auto *pData = dynamic_cast<const CSqlPlayerRequest *>(pGameData);
auto *pResult = dynamic_cast<CScorePlayerResult *>(pGameData->m_pResult.get());
auto *paMessages = pResult->m_Data.m_aaMessages;
char aBuf[1024];
str_format(aBuf, sizeof(aBuf),
"SELECT"
" Time, cp1, cp2, cp3, cp4, cp5, cp6, cp7, cp8, cp9, cp10, cp11, cp12, cp13, "
" cp14, cp15, cp16, cp17, cp18, cp19, cp20, cp21, cp22, cp23, cp24, cp25, "
" (cp1 + cp2 + cp3 + cp4 + cp5 + cp6 + cp7 + cp8 + cp9 + cp10 + cp11 + cp12 + cp13 + cp14 + "
" cp15 + cp16 + cp17 + cp18 + cp19 + cp20 + cp21 + cp22 + cp23 + cp24 + cp25 > 0) AS hasCP "
"FROM %s_race "
"WHERE Map = ? AND Name = ? AND hasCP = true "
"ORDER BY Time ASC "
"LIMIT 1",
pSqlServer->GetPrefix());
if(pSqlServer->PrepareStatement(aBuf, pError, ErrorSize))
{
return true;
}
const char *pPlayer = pData->m_aName[0] != '\0' ? pData->m_aName : pData->m_aRequestingPlayer;
pSqlServer->BindString(1, pData->m_aMap);
pSqlServer->BindString(2, pPlayer);
bool End;
if(pSqlServer->Step(&End, pError, ErrorSize))
{
return true;
}
if(!End)
{
pResult->SetVariant(CScorePlayerResult::PLAYER_TIMECP);
pResult->m_Data.m_Info.m_Time = pSqlServer->GetFloat(1);
for(int i = 0; i < NUM_CHECKPOINTS; i++)
{
pResult->m_Data.m_Info.m_aTimeCp[i] = pSqlServer->GetFloat(i + 2);
}
str_copy(pResult->m_Data.m_Info.m_aRequestedPlayer, pPlayer, sizeof(pResult->m_Data.m_Info.m_aRequestedPlayer));
}
else
{
pResult->SetVariant(CScorePlayerResult::DIRECT);
str_format(paMessages[0], sizeof(paMessages[0]), "'%s' has no checkpoint times available", pPlayer);
}
return false;
}
bool CScoreWorker::MapVote(IDbConnection *pSqlServer, const ISqlData *pGameData, char *pError, int ErrorSize)
{
const auto *pData = dynamic_cast<const CSqlPlayerRequest *>(pGameData);

View file

@ -39,6 +39,7 @@ struct CScorePlayerResult : ISqlResult
BROADCAST,
MAP_VOTE,
PLAYER_INFO,
PLAYER_TIMECP,
} m_MessageKind;
union
{
@ -49,6 +50,7 @@ struct CScorePlayerResult : ISqlResult
std::optional<float> m_Time;
float m_aTimeCp[NUM_CHECKPOINTS];
int m_Birthday; // 0 indicates no birthday
char m_aRequestedPlayer[MAX_NAME_LENGTH];
} m_Info = {};
struct
{
@ -244,6 +246,12 @@ public:
m_aBestTimeCp[i] = aTimeCp[i];
}
void SetBestTimeCp(const float aTimeCp[NUM_CHECKPOINTS])
{
for(int i = 0; i < NUM_CHECKPOINTS; i++)
m_aBestTimeCp[i] = aTimeCp[i];
}
float m_BestTime;
float m_aBestTimeCp[NUM_CHECKPOINTS];
@ -284,6 +292,7 @@ struct CScoreWorker
static bool MapVote(IDbConnection *pSqlServer, const ISqlData *pGameData, char *pError, int ErrorSize);
static bool LoadPlayerData(IDbConnection *pSqlServer, const ISqlData *pGameData, char *pError, int ErrorSize);
static bool LoadPlayerTimeCp(IDbConnection *pSqlServer, const ISqlData *pGameData, char *pError, int ErrorSize);
static bool MapInfo(IDbConnection *pSqlServer, const ISqlData *pGameData, char *pError, int ErrorSize);
static bool ShowRank(IDbConnection *pSqlServer, const ISqlData *pGameData, char *pError, int ErrorSize);
static bool ShowTeamRank(IDbConnection *pSqlServer, const ISqlData *pGameData, char *pError, int ErrorSize);