Compare commits

...

6 commits

Author SHA1 Message Date
KebsCS a65cbcdff7
Merge 53be2625ef into 11fd82077a 2024-09-07 19:06:48 +02:00
Jupeyy 11fd82077a
Merge pull request #8913 from Robyt3/Video-Stop-ASAN-Fix
Fix heap-use-after-free in `CVideo::Stop`
2024-09-07 16:17:29 +00:00
Dennis Felsing 3d30ce4bf2
Merge pull request #8817 from Robyt3/Client-Start-Menu-Console
Add icon button to open console in bottom right of start menu
2024-09-07 17:19:15 +02:00
Robert Müller 9e0ba8a91f Fix heap-use-after-free in CVideo::Stop
The `delete ms_pCurrentVideo` deletes the current video instance (`this`) so the subsequent write to `m_Stopped` was invalid.

Closes #8899.
2024-09-07 16:57:27 +02:00
Robert Müller c89509bc4b Add icon button to open console in bottom right of start menu
Add a button with the "terminal" icon in the bottom right of the start menu to open the local console to ensure that the local console is usable also when no physical keyboard (with F-keys) is available.
2024-09-07 13:12:30 +02:00
KebsCS 53be2625ef
Add regional rankings to /top5team 2024-09-03 17:29:59 +02:00
8 changed files with 147 additions and 64 deletions

View file

@ -283,6 +283,7 @@ void CVideo::Pause(bool Pause)
void CVideo::Stop() void CVideo::Stop()
{ {
dbg_assert(!m_Stopped, "Already stopped"); dbg_assert(!m_Stopped, "Already stopped");
m_Stopped = true;
m_pGraphics->WaitForIdle(); m_pGraphics->WaitForIdle();
@ -341,8 +342,6 @@ void CVideo::Stop()
pSound->PauseAudioDevice(); pSound->PauseAudioDevice();
delete ms_pCurrentVideo; delete ms_pCurrentVideo;
pSound->UnpauseAudioDevice(); pSound->UnpauseAudioDevice();
m_Stopped = true;
} }
void CVideo::NextVideoFrameThread() void CVideo::NextVideoFrameThread()

View file

@ -489,7 +489,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(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(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(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(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") 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")

View file

@ -93,6 +93,7 @@ MAYBE_UNUSED static const char *FONT_ICON_EARTH_AMERICAS = "\xEF\x95\xBD";
MAYBE_UNUSED static const char *FONT_ICON_NETWORK_WIRED = "\xEF\x9B\xBF"; MAYBE_UNUSED static const char *FONT_ICON_NETWORK_WIRED = "\xEF\x9B\xBF";
MAYBE_UNUSED static const char *FONT_ICON_LIST_UL = "\xEF\x83\x8A"; MAYBE_UNUSED static const char *FONT_ICON_LIST_UL = "\xEF\x83\x8A";
MAYBE_UNUSED static const char *FONT_ICON_INFO = "\xEF\x84\xA9"; MAYBE_UNUSED static const char *FONT_ICON_INFO = "\xEF\x84\xA9";
MAYBE_UNUSED static const char *FONT_ICON_TERMINAL = "\xEF\x84\xA0";
MAYBE_UNUSED static const char *FONT_ICON_SLASH = "\xEF\x9C\x95"; MAYBE_UNUSED static const char *FONT_ICON_SLASH = "\xEF\x9C\x95";
MAYBE_UNUSED static const char *FONT_ICON_PLAY = "\xEF\x81\x8B"; MAYBE_UNUSED static const char *FONT_ICON_PLAY = "\xEF\x81\x8B";

View file

@ -160,8 +160,6 @@ class CGameConsole : public CComponent
static const ColorRGBA ms_SearchHighlightColor; static const ColorRGBA ms_SearchHighlightColor;
static const ColorRGBA ms_SearchSelectedColor; static const ColorRGBA ms_SearchSelectedColor;
void Toggle(int Type);
static void PossibleCommandsRenderCallback(int Index, const char *pStr, void *pUser); static void PossibleCommandsRenderCallback(int Index, const char *pStr, void *pUser);
static void ConToggleLocalConsole(IConsole::IResult *pResult, void *pUserData); static void ConToggleLocalConsole(IConsole::IResult *pResult, void *pUserData);
static void ConToggleRemoteConsole(IConsole::IResult *pResult, void *pUserData); static void ConToggleRemoteConsole(IConsole::IResult *pResult, void *pUserData);
@ -196,6 +194,7 @@ public:
virtual bool OnInput(const IInput::CEvent &Event) override; virtual bool OnInput(const IInput::CEvent &Event) override;
void Prompt(char (&aPrompt)[32]); void Prompt(char (&aPrompt)[32]);
void Toggle(int Type);
bool IsClosed() { return m_ConsoleState == CONSOLE_CLOSED; } bool IsClosed() { return m_ConsoleState == CONSOLE_CLOSED; }
}; };
#endif #endif

View file

@ -17,6 +17,8 @@
#include "menus.h" #include "menus.h"
using namespace FontIcons;
void CMenus::RenderStartMenu(CUIRect MainView) void CMenus::RenderStartMenu(CUIRect MainView)
{ {
GameClient()->m_MenuBackground.ChangePosition(CMenuBackground::POS_START); GameClient()->m_MenuBackground.ChangePosition(CMenuBackground::POS_START);
@ -186,13 +188,27 @@ void CMenus::RenderStartMenu(CUIRect MainView)
} }
// render version // render version
CUIRect VersionUpdate, CurVersion; CUIRect CurVersion, ConsoleButton;
MainView.HSplitBottom(20.0f, nullptr, &VersionUpdate); MainView.HSplitBottom(45.0f, nullptr, &CurVersion);
VersionUpdate.VSplitRight(50.0f, &CurVersion, nullptr); CurVersion.VSplitRight(40.0f, &CurVersion, nullptr);
VersionUpdate.VMargin(VMargin, &VersionUpdate); CurVersion.HSplitTop(20.0f, &ConsoleButton, &CurVersion);
CurVersion.HSplitTop(5.0f, nullptr, &CurVersion);
ConsoleButton.VSplitRight(40.0f, nullptr, &ConsoleButton);
Ui()->DoLabel(&CurVersion, GAME_RELEASE_VERSION, 14.0f, TEXTALIGN_MR); Ui()->DoLabel(&CurVersion, GAME_RELEASE_VERSION, 14.0f, TEXTALIGN_MR);
static CButtonContainer s_ConsoleButton;
TextRender()->SetFontPreset(EFontPreset::ICON_FONT);
TextRender()->SetRenderFlags(ETextRenderFlags::TEXT_RENDER_FLAG_ONLY_ADVANCE_WIDTH | ETextRenderFlags::TEXT_RENDER_FLAG_NO_X_BEARING | ETextRenderFlags::TEXT_RENDER_FLAG_NO_Y_BEARING | ETextRenderFlags::TEXT_RENDER_FLAG_NO_PIXEL_ALIGMENT | ETextRenderFlags::TEXT_RENDER_FLAG_NO_OVERSIZE);
if(DoButton_Menu(&s_ConsoleButton, FONT_ICON_TERMINAL, 0, &ConsoleButton, nullptr, IGraphics::CORNER_ALL, 5.0f, 0.0f, ColorRGBA(0.0f, 0.0f, 0.0f, 0.1f)))
{
GameClient()->m_GameConsole.Toggle(CGameConsole::CONSOLETYPE_LOCAL);
}
TextRender()->SetRenderFlags(0);
TextRender()->SetFontPreset(EFontPreset::DEFAULT_FONT);
CUIRect VersionUpdate;
MainView.HSplitBottom(20.0f, nullptr, &VersionUpdate);
VersionUpdate.VMargin(VMargin, &VersionUpdate);
#if defined(CONF_AUTOUPDATE) #if defined(CONF_AUTOUPDATE)
CUIRect UpdateButton; CUIRect UpdateButton;
VersionUpdate.VSplitRight(100.0f, &VersionUpdate, &UpdateButton); VersionUpdate.VSplitRight(100.0f, &VersionUpdate, &UpdateButton);

View file

@ -99,6 +99,48 @@ bool CTeamrank::SamePlayers(const std::vector<std::string> *pvSortedNames)
return true; 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) bool CScoreWorker::LoadBestTime(IDbConnection *pSqlServer, const ISqlData *pGameData, char *pError, int ErrorSize)
{ {
const auto *pData = dynamic_cast<const CSqlLoadBestTimeData *>(pGameData); const auto *pData = dynamic_cast<const CSqlLoadBestTimeData *>(pGameData);
@ -1071,34 +1113,40 @@ bool CScoreWorker::ShowTeamTop5(IDbConnection *pSqlServer, const ISqlData *pGame
int LimitStart = maximum(absolute(pData->m_Offset) - 1, 0); int LimitStart = maximum(absolute(pData->m_Offset) - 1, 0);
const char *pOrder = pData->m_Offset >= 0 ? "ASC" : "DESC"; const char *pOrder = pData->m_Offset >= 0 ? "ASC" : "DESC";
const char *pAny = "%";
// check sort method // check sort method
char aBuf[1024]; char aBuf[1024];
str_format(aBuf, sizeof(aBuf), str_format(aBuf, sizeof(aBuf),
"SELECT Name, Time, Ranking, TeamSize " "SELECT Name, Time, Ranking, TeamSize "
"FROM (" // limit to 5 "FROM ("
" SELECT TeamSize, Ranking, Id " " SELECT TeamSize, Ranking, Id, Server "
" FROM (" // teamrank score board " FROM (" // teamrank score board
" SELECT RANK() OVER w AS Ranking, COUNT(*) AS Teamsize, Id " " SELECT RANK() OVER w AS Ranking, COUNT(*) AS Teamsize, Id, Server "
" FROM %s_teamrace " " 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 = ? " " WHERE Map = ? "
" GROUP BY ID " " GROUP BY ID "
" WINDOW w AS (ORDER BY Min(Time))" " WINDOW w AS (ORDER BY Min(Time))"
" ) as l1 " " ) as l1 "
" WHERE Server LIKE ? "
" ORDER BY Ranking %s " " ORDER BY Ranking %s "
" LIMIT %d, 5" " LIMIT %d, ?"
") as l2 " ") as l2 "
"INNER JOIN %s_teamrace as r ON l2.Id = r.Id " "INNER JOIN %s_teamrace as r ON l2.Id = r.Id "
"ORDER BY Ranking %s, r.Id, Name ASC", "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)) if(pSqlServer->PrepareStatement(aBuf, pError, ErrorSize))
{ {
return true; return true;
} }
pSqlServer->BindString(1, pData->m_aMap); pSqlServer->BindString(1, pData->m_aMap);
pSqlServer->BindString(2, pAny);
pSqlServer->BindInt(3, 5);
// show teamtop5
int Line = 0; int Line = 0;
str_copy(paMessages[Line++], "------- Team Top 5 -------", sizeof(paMessages[Line])); str_copy(paMessages[Line++], "------- Team Top 5 -------", sizeof(paMessages[Line]));
@ -1109,44 +1157,45 @@ bool CScoreWorker::ShowTeamTop5(IDbConnection *pSqlServer, const ISqlData *pGame
} }
if(!End) if(!End)
{ {
for(Line = 1; Line < 6; Line++) // print if(CTeamrank::GetSqlTop5Team(pSqlServer, &End, pError, ErrorSize, paMessages, &Line, 5))
{ {
bool Last = false; return true;
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); if(!g_Config.m_SvRegionalRankings)
{
char aNames[2300] = {0}; str_copy(paMessages[Line], "-------------------------------", sizeof(paMessages[Line]));
for(int i = 0; i < TeamSize; i++) return false;
{ }
char aName[MAX_NAME_LENGTH];
pSqlServer->GetString(1, aName, sizeof(aName)); char aServerLike[16];
str_append(aNames, aName); str_format(aServerLike, sizeof(aServerLike), "%%%s%%", pData->m_aServer);
if(i < TeamSize - 2)
str_append(aNames, ", "); if(pSqlServer->PrepareStatement(aBuf, pError, ErrorSize))
else if(i == TeamSize - 2) {
str_append(aNames, " & "); return true;
if(pSqlServer->Step(&Last, pError, ErrorSize)) }
{ pSqlServer->BindString(1, pData->m_aMap);
return true; pSqlServer->BindString(2, aServerLike);
} pSqlServer->BindInt(3, 3);
if(Last)
{ str_format(pResult->m_Data.m_aaMessages[Line], sizeof(pResult->m_Data.m_aaMessages[Line]),
break; "----- %s Team Top -----", pData->m_aServer);
} Line++;
}
str_format(paMessages[Line], sizeof(paMessages[Line]), "%d. %s Team Time: %s", if(pSqlServer->Step(&End, pError, ErrorSize))
Rank, aNames, aBuf); {
if(Last) return true;
{ }
Line++; if(!End)
break; {
} if(CTeamrank::GetSqlTop5Team(pSqlServer, &End, pError, ErrorSize, paMessages, &Line, 3))
{
return true;
} }
} }
str_copy(paMessages[Line], "-------------------------------", sizeof(paMessages[Line]));
return false; return false;
} }

View file

@ -281,6 +281,8 @@ struct CTeamrank
bool NextSqlResult(IDbConnection *pSqlServer, bool *pEnd, char *pError, int ErrorSize); bool NextSqlResult(IDbConnection *pSqlServer, bool *pEnd, char *pError, int ErrorSize);
bool SamePlayers(const std::vector<std::string> *pvSortedNames); bool SamePlayers(const std::vector<std::string> *pvSortedNames);
static bool GetSqlTop5Team(IDbConnection *pSqlServer, bool *pEnd, char *pError, int ErrorSize, char (*paMessages)[512], int *StartLine, int Count);
}; };
struct CScoreWorker struct CScoreWorker

View file

@ -282,41 +282,46 @@ struct TeamScore : public Score
{ {
void SetUp() override void SetUp() override
{ {
CSqlTeamScoreData teamScoreData; InsertTeamRank(100.0);
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;
} }
void InsertTeamRank(float Time = 100.0) void InsertTeamRank(float Time = 100.0)
{ {
str_copy(g_Config.m_SvSqlServerName, "USA", sizeof(g_Config.m_SvSqlServerName));
CSqlTeamScoreData teamScoreData; CSqlTeamScoreData teamScoreData;
CSqlScoreData ScoreData(std::make_shared<CScorePlayerResult>());
str_copy(teamScoreData.m_aMap, "Kobra 3", sizeof(teamScoreData.m_aMap)); 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(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; teamScoreData.m_Size = 2;
str_copy(teamScoreData.m_aaNames[0], "nameless tee", sizeof(teamScoreData.m_aaNames[0])); 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])); str_copy(teamScoreData.m_aaNames[1], "brainless tee", sizeof(teamScoreData.m_aaNames[1]));
teamScoreData.m_Time = Time; 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(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; 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_aMap, "Kobra 3", sizeof(m_PlayerRequest.m_aMap));
str_copy(m_PlayerRequest.m_aRequestingPlayer, "brainless tee", sizeof(m_PlayerRequest.m_aRequestingPlayer)); 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; m_PlayerRequest.m_Offset = 0;
} }
}; };
TEST_P(TeamScore, All) TEST_P(TeamScore, All)
{ {
g_Config.m_SvRegionalRankings = false;
ASSERT_FALSE(CScoreWorker::ShowTeamTop5(m_pConn, &m_PlayerRequest, m_aError, sizeof(m_aError))) << m_aError; ASSERT_FALSE(CScoreWorker::ShowTeamTop5(m_pConn, &m_PlayerRequest, m_aError, sizeof(m_aError))) << m_aError;
ExpectLines(m_pPlayerResult, ExpectLines(m_pPlayerResult,
{"------- Team Top 5 -------", {"------- 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) TEST_P(TeamScore, PlayerExists)
{ {
str_copy(m_PlayerRequest.m_aName, "brainless tee", sizeof(m_PlayerRequest.m_aName)); str_copy(m_PlayerRequest.m_aName, "brainless tee", sizeof(m_PlayerRequest.m_aName));