diff --git a/src/engine/shared/config_variables.h b/src/engine/shared/config_variables.h index 00fe9826c..14e1e44a0 100644 --- a/src/engine/shared/config_variables.h +++ b/src/engine/shared/config_variables.h @@ -488,7 +488,7 @@ MACRO_CONFIG_INT(SvSpecFrequency, sv_pause_frequency, 1, 0, 9999, CFGFLAG_SERVER MACRO_CONFIG_INT(SvInvite, sv_invite, 1, 0, 1, CFGFLAG_SERVER, "Whether players can invite other players to teams") MACRO_CONFIG_INT(SvInviteFrequency, sv_invite_frequency, 1, 0, 9999, CFGFLAG_SERVER, "The minimum allowed delay between invites") MACRO_CONFIG_INT(SvTeleOthersAuthLevel, sv_tele_others_auth_level, 1, 1, 3, CFGFLAG_SERVER, "The auth level you need to tele others") -MACRO_CONFIG_INT(SvRegionalRankings, sv_regional_rankings, 1, 0, 1, CFGFLAG_SERVER, "Display regional rankings in /rank and /top5") +MACRO_CONFIG_INT(SvRegionalRankings, sv_regional_rankings, 1, 0, 1, CFGFLAG_SERVER, "Display regional rankings in /rank, /top5 and /top5team") MACRO_CONFIG_INT(SvEmotionalTees, sv_emotional_tees, 1, -1, 1, CFGFLAG_SERVER, "Whether eye change of tees is enabled with emoticons = 1, not = 0, -1 not at all") MACRO_CONFIG_INT(SvEmoticonMsDelay, sv_emoticon_ms_delay, 3000, 20, 999999999, CFGFLAG_SERVER, "The time in ms a player has to wait before allowing the next over-head emoticons") diff --git a/src/game/server/scoreworker.cpp b/src/game/server/scoreworker.cpp index 5516ec65c..35d1ba323 100644 --- a/src/game/server/scoreworker.cpp +++ b/src/game/server/scoreworker.cpp @@ -99,6 +99,48 @@ bool CTeamrank::SamePlayers(const std::vector *pvSortedNames) return true; } +bool CTeamrank::GetSqlTop5Team(IDbConnection *pSqlServer, bool *pEnd, char *pError, int ErrorSize, char (*paMessages)[512], int *Line, int Count) +{ + char aTime[32]; + int StartLine = *Line; + for(*Line = StartLine; *Line < StartLine + Count; (*Line)++) + { + bool Last = false; + float Time = pSqlServer->GetFloat(2); + str_time_float(Time, TIME_HOURS_CENTISECS, aTime, sizeof(aTime)); + int Rank = pSqlServer->GetInt(3); + int TeamSize = pSqlServer->GetInt(4); + + char aNames[2300] = {0}; + for(int i = 0; i < TeamSize; i++) + { + char aName[MAX_NAME_LENGTH]; + pSqlServer->GetString(1, aName, sizeof(aName)); + str_append(aNames, aName); + if(i < TeamSize - 2) + str_append(aNames, ", "); + else if(i == TeamSize - 2) + str_append(aNames, " & "); + if(pSqlServer->Step(&Last, pError, ErrorSize)) + { + return true; + } + if(Last) + { + break; + } + } + str_format(paMessages[*Line], sizeof(paMessages[*Line]), "%d. %s Team Time: %s", + Rank, aNames, aTime); + if(Last) + { + (*Line)++; + break; + } + } + return false; +} + bool CScoreWorker::LoadBestTime(IDbConnection *pSqlServer, const ISqlData *pGameData, char *pError, int ErrorSize) { const auto *pData = dynamic_cast(pGameData); @@ -1071,34 +1113,40 @@ bool CScoreWorker::ShowTeamTop5(IDbConnection *pSqlServer, const ISqlData *pGame int LimitStart = maximum(absolute(pData->m_Offset) - 1, 0); const char *pOrder = pData->m_Offset >= 0 ? "ASC" : "DESC"; + const char *pAny = "%"; // check sort method char aBuf[1024]; str_format(aBuf, sizeof(aBuf), "SELECT Name, Time, Ranking, TeamSize " - "FROM (" // limit to 5 - " SELECT TeamSize, Ranking, Id " + "FROM (" + " SELECT TeamSize, Ranking, Id, Server " " FROM (" // teamrank score board - " SELECT RANK() OVER w AS Ranking, COUNT(*) AS Teamsize, Id " - " FROM %s_teamrace " + " SELECT RANK() OVER w AS Ranking, COUNT(*) AS Teamsize, Id, Server " + " FROM (" + " SELECT * FROM %s_teamrace as tr " + " INNER JOIN %s_race as rr ON tr.Map = rr.Map AND tr.Name = rr.Name AND tr.Time = rr.Time AND tr.Timestamp = rr.Timestamp" + " ) " " WHERE Map = ? " " GROUP BY ID " " WINDOW w AS (ORDER BY Min(Time))" " ) as l1 " + " WHERE Server LIKE ? " " ORDER BY Ranking %s " - " LIMIT %d, 5" + " LIMIT %d, ?" ") as l2 " "INNER JOIN %s_teamrace as r ON l2.Id = r.Id " "ORDER BY Ranking %s, r.Id, Name ASC", - pSqlServer->GetPrefix(), pOrder, LimitStart, pSqlServer->GetPrefix(), pOrder); + pSqlServer->GetPrefix(), pSqlServer->GetPrefix(), pOrder, LimitStart, pSqlServer->GetPrefix(), pOrder); if(pSqlServer->PrepareStatement(aBuf, pError, ErrorSize)) { return true; } pSqlServer->BindString(1, pData->m_aMap); + pSqlServer->BindString(2, pAny); + pSqlServer->BindInt(3, 5); - // show teamtop5 int Line = 0; str_copy(paMessages[Line++], "------- Team Top 5 -------", sizeof(paMessages[Line])); @@ -1109,44 +1157,45 @@ bool CScoreWorker::ShowTeamTop5(IDbConnection *pSqlServer, const ISqlData *pGame } if(!End) { - for(Line = 1; Line < 6; Line++) // print + if(CTeamrank::GetSqlTop5Team(pSqlServer, &End, pError, ErrorSize, paMessages, &Line, 5)) { - bool Last = false; - float Time = pSqlServer->GetFloat(2); - str_time_float(Time, TIME_HOURS_CENTISECS, aBuf, sizeof(aBuf)); - int Rank = pSqlServer->GetInt(3); - int TeamSize = pSqlServer->GetInt(4); - - char aNames[2300] = {0}; - for(int i = 0; i < TeamSize; i++) - { - char aName[MAX_NAME_LENGTH]; - pSqlServer->GetString(1, aName, sizeof(aName)); - str_append(aNames, aName); - if(i < TeamSize - 2) - str_append(aNames, ", "); - else if(i == TeamSize - 2) - str_append(aNames, " & "); - if(pSqlServer->Step(&Last, pError, ErrorSize)) - { - return true; - } - if(Last) - { - break; - } - } - str_format(paMessages[Line], sizeof(paMessages[Line]), "%d. %s Team Time: %s", - Rank, aNames, aBuf); - if(Last) - { - Line++; - break; - } + return true; + } + } + + if(!g_Config.m_SvRegionalRankings) + { + str_copy(paMessages[Line], "-------------------------------", sizeof(paMessages[Line])); + return false; + } + + char aServerLike[16]; + str_format(aServerLike, sizeof(aServerLike), "%%%s%%", pData->m_aServer); + + if(pSqlServer->PrepareStatement(aBuf, pError, ErrorSize)) + { + return true; + } + pSqlServer->BindString(1, pData->m_aMap); + pSqlServer->BindString(2, aServerLike); + pSqlServer->BindInt(3, 3); + + str_format(pResult->m_Data.m_aaMessages[Line], sizeof(pResult->m_Data.m_aaMessages[Line]), + "----- %s Team Top -----", pData->m_aServer); + Line++; + + if(pSqlServer->Step(&End, pError, ErrorSize)) + { + return true; + } + if(!End) + { + if(CTeamrank::GetSqlTop5Team(pSqlServer, &End, pError, ErrorSize, paMessages, &Line, 3)) + { + return true; } } - str_copy(paMessages[Line], "-------------------------------", sizeof(paMessages[Line])); return false; } diff --git a/src/game/server/scoreworker.h b/src/game/server/scoreworker.h index 9e38501e5..c54f11c77 100644 --- a/src/game/server/scoreworker.h +++ b/src/game/server/scoreworker.h @@ -281,6 +281,8 @@ struct CTeamrank bool NextSqlResult(IDbConnection *pSqlServer, bool *pEnd, char *pError, int ErrorSize); bool SamePlayers(const std::vector *pvSortedNames); + + static bool GetSqlTop5Team(IDbConnection *pSqlServer, bool *pEnd, char *pError, int ErrorSize, char (*paMessages)[512], int *StartLine, int Count); }; struct CScoreWorker diff --git a/src/test/score.cpp b/src/test/score.cpp index 2bb920ebc..aa7b4bba2 100644 --- a/src/test/score.cpp +++ b/src/test/score.cpp @@ -282,41 +282,46 @@ struct TeamScore : public Score { void SetUp() override { - CSqlTeamScoreData teamScoreData; - str_copy(teamScoreData.m_aMap, "Kobra 3", sizeof(teamScoreData.m_aMap)); - str_copy(teamScoreData.m_aGameUuid, "8d300ecf-5873-4297-bee5-95668fdff320", sizeof(teamScoreData.m_aGameUuid)); - teamScoreData.m_Size = 2; - str_copy(teamScoreData.m_aaNames[0], "nameless tee", sizeof(teamScoreData.m_aaNames[0])); - str_copy(teamScoreData.m_aaNames[1], "brainless tee", sizeof(teamScoreData.m_aaNames[1])); - teamScoreData.m_Time = 100.0; - str_copy(teamScoreData.m_aTimestamp, "2021-11-24 19:24:08", sizeof(teamScoreData.m_aTimestamp)); - ASSERT_FALSE(CScoreWorker::SaveTeamScore(m_pConn, &teamScoreData, Write::NORMAL, m_aError, sizeof(m_aError))) << m_aError; - - str_copy(m_PlayerRequest.m_aMap, "Kobra 3", sizeof(m_PlayerRequest.m_aMap)); - str_copy(m_PlayerRequest.m_aRequestingPlayer, "brainless tee", sizeof(m_PlayerRequest.m_aRequestingPlayer)); - m_PlayerRequest.m_Offset = 0; + InsertTeamRank(100.0); } void InsertTeamRank(float Time = 100.0) { + str_copy(g_Config.m_SvSqlServerName, "USA", sizeof(g_Config.m_SvSqlServerName)); CSqlTeamScoreData teamScoreData; + CSqlScoreData ScoreData(std::make_shared()); str_copy(teamScoreData.m_aMap, "Kobra 3", sizeof(teamScoreData.m_aMap)); + str_copy(ScoreData.m_aMap, "Kobra 3", sizeof(ScoreData.m_aMap)); str_copy(teamScoreData.m_aGameUuid, "8d300ecf-5873-4297-bee5-95668fdff320", sizeof(teamScoreData.m_aGameUuid)); + str_copy(ScoreData.m_aGameUuid, "8d300ecf-5873-4297-bee5-95668fdff320", sizeof(ScoreData.m_aGameUuid)); teamScoreData.m_Size = 2; str_copy(teamScoreData.m_aaNames[0], "nameless tee", sizeof(teamScoreData.m_aaNames[0])); str_copy(teamScoreData.m_aaNames[1], "brainless tee", sizeof(teamScoreData.m_aaNames[1])); teamScoreData.m_Time = Time; + ScoreData.m_Time = Time; str_copy(teamScoreData.m_aTimestamp, "2021-11-24 19:24:08", sizeof(teamScoreData.m_aTimestamp)); + str_copy(ScoreData.m_aTimestamp, "2021-11-24 19:24:08", sizeof(ScoreData.m_aTimestamp)); + for(int i = 0; i < NUM_CHECKPOINTS; i++) + ScoreData.m_aCurrentTimeCp[i] = 0; ASSERT_FALSE(CScoreWorker::SaveTeamScore(m_pConn, &teamScoreData, Write::NORMAL, m_aError, sizeof(m_aError))) << m_aError; str_copy(m_PlayerRequest.m_aMap, "Kobra 3", sizeof(m_PlayerRequest.m_aMap)); str_copy(m_PlayerRequest.m_aRequestingPlayer, "brainless tee", sizeof(m_PlayerRequest.m_aRequestingPlayer)); + str_copy(ScoreData.m_aRequestingPlayer, "brainless tee", sizeof(ScoreData.m_aRequestingPlayer)); + + str_copy(ScoreData.m_aName, "nameless tee", sizeof(ScoreData.m_aName)); + ScoreData.m_ClientId = 0; + ASSERT_FALSE(CScoreWorker::SaveScore(m_pConn, &ScoreData, Write::NORMAL, m_aError, sizeof(m_aError))) << m_aError; + str_copy(ScoreData.m_aName, "brainless tee", sizeof(ScoreData.m_aName)); + ScoreData.m_ClientId = 1; + ASSERT_FALSE(CScoreWorker::SaveScore(m_pConn, &ScoreData, Write::NORMAL, m_aError, sizeof(m_aError))) << m_aError; m_PlayerRequest.m_Offset = 0; } }; TEST_P(TeamScore, All) { + g_Config.m_SvRegionalRankings = false; ASSERT_FALSE(CScoreWorker::ShowTeamTop5(m_pConn, &m_PlayerRequest, m_aError, sizeof(m_aError))) << m_aError; ExpectLines(m_pPlayerResult, {"------- Team Top 5 -------", @@ -324,6 +329,18 @@ TEST_P(TeamScore, All) "-------------------------------"}); } +TEST_P(TeamScore, TeamTop5Regional) +{ + g_Config.m_SvRegionalRankings = true; + str_copy(m_PlayerRequest.m_aServer, "USA", sizeof(m_PlayerRequest.m_aServer)); + ASSERT_FALSE(CScoreWorker::ShowTeamTop5(m_pConn, &m_PlayerRequest, m_aError, sizeof(m_aError))) << m_aError; + ExpectLines(m_pPlayerResult, + {"------- Team Top 5 -------", + "1. brainless tee & nameless tee Team Time: 01:40.00", + "----- USA Team Top -----", + "1. brainless tee & nameless tee Team Time: 01:40.00"}); +} + TEST_P(TeamScore, PlayerExists) { str_copy(m_PlayerRequest.m_aName, "brainless tee", sizeof(m_PlayerRequest.m_aName));