mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-10 10:08:18 +00:00
Merge #5372
5372: Get best Time Checkpoints back if map has one, add /timecp, remove sv_checkpoint_save r=heinrich5991 a=def- Even if you made a better finish without time cps before. Can happen now that we add Time CPs to existing maps: https://docs.google.com/spreadsheets/d/1yMMBLSbS2cOSYsbIMkDZpMLaV6k930mXj5yVZF0Uuaw/edit#gid=0 As suggested by snail <!-- What is the motivation for the changes of this pull request --> ## Checklist - [ ] Tested the change ingame - [ ] Provided screenshots if it is a visual change - [ ] Tested in combination with possibly related configuration options - [x] Written a unit test if it works standalone, system.c especially - [ ] Considered possible null pointers and out of bounds array indexing - [ ] Changed no physics that affect existing maps - [ ] Tested the change with [ASan+UBSan or valgrind's memcheck](https://github.com/ddnet/ddnet/#using-addresssanitizer--undefinedbehavioursanitizer-or-valgrinds-memcheck) (optional) Co-authored-by: Dennis Felsing <dennis@felsin9.de>
This commit is contained in:
commit
d9a6175e30
|
@ -234,7 +234,6 @@ MACRO_CONFIG_INT(SvFastDownload, sv_fast_download, 1, 0, 1, CFGFLAG_SERVER, "Ena
|
||||||
|
|
||||||
MACRO_CONFIG_INT(SvShotgunBulletSound, sv_shotgun_bullet_sound, 0, 0, 1, CFGFLAG_SERVER, "Crazy shotgun bullet sound on/off")
|
MACRO_CONFIG_INT(SvShotgunBulletSound, sv_shotgun_bullet_sound, 0, 0, 1, CFGFLAG_SERVER, "Crazy shotgun bullet sound on/off")
|
||||||
|
|
||||||
MACRO_CONFIG_INT(SvCheckpointSave, sv_checkpoint_save, 1, 0, 1, CFGFLAG_SERVER, "Whether to save checkpoint times to the score file")
|
|
||||||
MACRO_CONFIG_STR(SvScoreFolder, sv_score_folder, 32, "records", CFGFLAG_SERVER, "Folder to save score files to")
|
MACRO_CONFIG_STR(SvScoreFolder, sv_score_folder, 32, "records", CFGFLAG_SERVER, "Folder to save score files to")
|
||||||
|
|
||||||
MACRO_CONFIG_STR(SvRegionName, sv_region_name, 5, "UNK", CFGFLAG_SERVER, "Server region. Used for regional bans")
|
MACRO_CONFIG_STR(SvRegionName, sv_region_name, 5, "UNK", CFGFLAG_SERVER, "Server region. Used for regional bans")
|
||||||
|
|
|
@ -43,6 +43,7 @@ CHAT_COMMAND("top5", "?i[rank to start with]", CFGFLAG_CHAT | CFGFLAG_SERVER, Co
|
||||||
CHAT_COMMAND("times", "?s[player name] ?i[number of times to skip]", CFGFLAG_CHAT | CFGFLAG_SERVER, ConTimes, this, "/times ?s?i shows last 5 times of the server or of a player beginning with name s starting with time i (i = 1 by default, -1 for first)")
|
CHAT_COMMAND("times", "?s[player name] ?i[number of times to skip]", CFGFLAG_CHAT | CFGFLAG_SERVER, ConTimes, this, "/times ?s?i shows last 5 times of the server or of a player beginning with name s starting with time i (i = 1 by default, -1 for first)")
|
||||||
CHAT_COMMAND("points", "?r[player name]", CFGFLAG_CHAT | CFGFLAG_SERVER, ConPoints, this, "Shows the global points of a player beginning with name r (your rank by default)")
|
CHAT_COMMAND("points", "?r[player name]", CFGFLAG_CHAT | CFGFLAG_SERVER, ConPoints, this, "Shows the global points of a player beginning with name r (your rank by default)")
|
||||||
CHAT_COMMAND("top5points", "?i[number]", CFGFLAG_CHAT | CFGFLAG_SERVER, ConTopPoints, this, "Shows five points of the global point ladder beginning with rank i (1 by default)")
|
CHAT_COMMAND("top5points", "?i[number]", CFGFLAG_CHAT | CFGFLAG_SERVER, ConTopPoints, this, "Shows five points of the global point ladder beginning with rank i (1 by default)")
|
||||||
|
CHAT_COMMAND("timecp", "?r[player name]", CFGFLAG_CHAT | CFGFLAG_SERVER, ConTimeCP, this, "Set your checkpoints based on another player")
|
||||||
|
|
||||||
CHAT_COMMAND("team", "?i[id]", CFGFLAG_CHAT | CFGFLAG_SERVER, ConJoinTeam, this, "Lets you join team i (shows your team if left blank)")
|
CHAT_COMMAND("team", "?i[id]", CFGFLAG_CHAT | CFGFLAG_SERVER, ConJoinTeam, this, "Lets you join team i (shows your team if left blank)")
|
||||||
CHAT_COMMAND("lock", "?i['0'|'1']", CFGFLAG_CHAT | CFGFLAG_SERVER, ConLockTeam, this, "Toggle team lock so no one else can join and so the team restarts when a player dies. /lock 0 to unlock, /lock 1 to lock.")
|
CHAT_COMMAND("lock", "?i['0'|'1']", CFGFLAG_CHAT | CFGFLAG_SERVER, ConLockTeam, this, "Toggle team lock so no one else can join and so the team restarts when a player dies. /lock 0 to unlock, /lock 1 to lock.")
|
||||||
|
|
|
@ -1576,3 +1576,24 @@ void CGameContext::ConTopPoints(IConsole::IResult *pResult, void *pUserData)
|
||||||
else
|
else
|
||||||
pSelf->Score()->ShowTopPoints(pResult->m_ClientID);
|
pSelf->Score()->ShowTopPoints(pResult->m_ClientID);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CGameContext::ConTimeCP(IConsole::IResult *pResult, void *pUserData)
|
||||||
|
{
|
||||||
|
CGameContext *pSelf = (CGameContext *)pUserData;
|
||||||
|
if(!CheckClientID(pResult->m_ClientID))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(g_Config.m_SvHideScore)
|
||||||
|
{
|
||||||
|
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "chatresp",
|
||||||
|
"Showing the checkpoint times is not allowed on this server.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CPlayer *pPlayer = pSelf->m_apPlayers[pResult->m_ClientID];
|
||||||
|
if(!pPlayer)
|
||||||
|
return;
|
||||||
|
|
||||||
|
const char *pName = pResult->GetString(0);
|
||||||
|
pSelf->Score()->LoadPlayerData(pResult->m_ClientID, pName);
|
||||||
|
}
|
||||||
|
|
|
@ -362,6 +362,7 @@ private:
|
||||||
static void ConTimes(IConsole::IResult *pResult, void *pUserData);
|
static void ConTimes(IConsole::IResult *pResult, void *pUserData);
|
||||||
static void ConPoints(IConsole::IResult *pResult, void *pUserData);
|
static void ConPoints(IConsole::IResult *pResult, void *pUserData);
|
||||||
static void ConTopPoints(IConsole::IResult *pResult, void *pUserData);
|
static void ConTopPoints(IConsole::IResult *pResult, void *pUserData);
|
||||||
|
static void ConTimeCP(IConsole::IResult *pResult, void *pUserData);
|
||||||
|
|
||||||
static void ConUTF8(IConsole::IResult *pResult, void *pUserData);
|
static void ConUTF8(IConsole::IResult *pResult, void *pUserData);
|
||||||
static void ConDND(IConsole::IResult *pResult, void *pUserData);
|
static void ConDND(IConsole::IResult *pResult, void *pUserData);
|
||||||
|
|
|
@ -113,9 +113,9 @@ CScore::CScore(CGameContext *pGameServer, CDbConnectionPool *pPool) :
|
||||||
m_pPool->Execute(CScoreWorker::Init, std::move(Tmp), "load best time");
|
m_pPool->Execute(CScoreWorker::Init, std::move(Tmp), "load best time");
|
||||||
}
|
}
|
||||||
|
|
||||||
void CScore::LoadPlayerData(int ClientID)
|
void CScore::LoadPlayerData(int ClientID, const char *pName)
|
||||||
{
|
{
|
||||||
ExecPlayerThread(CScoreWorker::LoadPlayerData, "load player data", ClientID, "", 0);
|
ExecPlayerThread(CScoreWorker::LoadPlayerData, "load player data", ClientID, pName, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CScore::MapVote(int ClientID, const char *MapName)
|
void CScore::MapVote(int ClientID, const char *MapName)
|
||||||
|
|
|
@ -44,7 +44,7 @@ public:
|
||||||
|
|
||||||
void MapInfo(int ClientID, const char *pMapName);
|
void MapInfo(int ClientID, const char *pMapName);
|
||||||
void MapVote(int ClientID, const char *pMapName);
|
void MapVote(int ClientID, const char *pMapName);
|
||||||
void LoadPlayerData(int ClientID);
|
void LoadPlayerData(int ClientID, const char *pName = "");
|
||||||
void SaveScore(int ClientID, float Time, const char *pTimestamp, float aCpTime[NUM_CHECKPOINTS], bool NotEligible);
|
void SaveScore(int ClientID, float Time, const char *pTimestamp, float aCpTime[NUM_CHECKPOINTS], bool NotEligible);
|
||||||
|
|
||||||
void SaveTeamScore(int *pClientIDs, unsigned int Size, float Time, const char *pTimestamp);
|
void SaveTeamScore(int *pClientIDs, unsigned int Size, float Time, const char *pTimestamp);
|
||||||
|
|
|
@ -131,20 +131,27 @@ bool CScoreWorker::LoadPlayerData(IDbConnection *pSqlServer, const ISqlData *pGa
|
||||||
char aBuf[512];
|
char aBuf[512];
|
||||||
// get best race time
|
// get best race time
|
||||||
str_format(aBuf, sizeof(aBuf),
|
str_format(aBuf, sizeof(aBuf),
|
||||||
"SELECT Time, cp1, cp2, cp3, cp4, cp5, cp6, cp7, cp8, cp9, cp10, "
|
"SELECT"
|
||||||
" cp11, cp12, cp13, cp14, cp15, cp16, cp17, cp18, cp19, cp20, "
|
" (SELECT Time FROM %s_race WHERE Map = ? AND Name = ? ORDER BY Time ASC LIMIT 1) AS Time, "
|
||||||
" 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, "
|
||||||
|
" (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 "
|
"FROM %s_race "
|
||||||
"WHERE Map = ? AND Name = ? "
|
"WHERE Map = ? AND Name = ? "
|
||||||
"ORDER BY Time ASC "
|
"ORDER BY hasCP DESC, Time ASC "
|
||||||
"LIMIT 1",
|
"LIMIT 1",
|
||||||
pSqlServer->GetPrefix());
|
pSqlServer->GetPrefix(), pSqlServer->GetPrefix());
|
||||||
if(pSqlServer->PrepareStatement(aBuf, pError, ErrorSize))
|
if(pSqlServer->PrepareStatement(aBuf, pError, ErrorSize))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *pPlayer = pData->m_aName[0] != '\0' ? pData->m_aName : pData->m_aRequestingPlayer;
|
||||||
pSqlServer->BindString(1, pData->m_aMap);
|
pSqlServer->BindString(1, pData->m_aMap);
|
||||||
pSqlServer->BindString(2, pData->m_aRequestingPlayer);
|
pSqlServer->BindString(2, pData->m_aRequestingPlayer);
|
||||||
|
pSqlServer->BindString(3, pData->m_aMap);
|
||||||
|
pSqlServer->BindString(4, pPlayer);
|
||||||
|
|
||||||
bool End;
|
bool End;
|
||||||
if(pSqlServer->Step(&End, pError, ErrorSize))
|
if(pSqlServer->Step(&End, pError, ErrorSize))
|
||||||
|
@ -159,12 +166,9 @@ bool CScoreWorker::LoadPlayerData(IDbConnection *pSqlServer, const ISqlData *pGa
|
||||||
pResult->m_Data.m_Info.m_Score = -Time;
|
pResult->m_Data.m_Info.m_Score = -Time;
|
||||||
pResult->m_Data.m_Info.m_HasFinishScore = true;
|
pResult->m_Data.m_Info.m_HasFinishScore = true;
|
||||||
|
|
||||||
if(g_Config.m_SvCheckpointSave)
|
for(int i = 0; i < NUM_CHECKPOINTS; i++)
|
||||||
{
|
{
|
||||||
for(int i = 0; i < NUM_CHECKPOINTS; i++)
|
pResult->m_Data.m_Info.m_CpTime[i] = pSqlServer->GetFloat(i + 2);
|
||||||
{
|
|
||||||
pResult->m_Data.m_Info.m_CpTime[i] = pSqlServer->GetFloat(i + 2);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -90,7 +90,7 @@ struct Score : public testing::TestWithParam<IDbConnection *>
|
||||||
ASSERT_EQ(NumInserted, 1);
|
ASSERT_EQ(NumInserted, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InsertRank()
|
void InsertRank(float Time = 100.0, bool WithTimeCheckPoints = false)
|
||||||
{
|
{
|
||||||
str_copy(g_Config.m_SvSqlServerName, "USA", sizeof(g_Config.m_SvSqlServerName));
|
str_copy(g_Config.m_SvSqlServerName, "USA", sizeof(g_Config.m_SvSqlServerName));
|
||||||
CSqlScoreData ScoreData(std::make_shared<CScorePlayerResult>());
|
CSqlScoreData ScoreData(std::make_shared<CScorePlayerResult>());
|
||||||
|
@ -98,10 +98,10 @@ struct Score : public testing::TestWithParam<IDbConnection *>
|
||||||
str_copy(ScoreData.m_aGameUuid, "8d300ecf-5873-4297-bee5-95668fdff320", sizeof(ScoreData.m_aGameUuid));
|
str_copy(ScoreData.m_aGameUuid, "8d300ecf-5873-4297-bee5-95668fdff320", sizeof(ScoreData.m_aGameUuid));
|
||||||
str_copy(ScoreData.m_aName, "nameless tee", sizeof(ScoreData.m_aName));
|
str_copy(ScoreData.m_aName, "nameless tee", sizeof(ScoreData.m_aName));
|
||||||
ScoreData.m_ClientID = 0;
|
ScoreData.m_ClientID = 0;
|
||||||
ScoreData.m_Time = 100.0;
|
ScoreData.m_Time = Time;
|
||||||
str_copy(ScoreData.m_aTimestamp, "2021-11-24 19:24:08", sizeof(ScoreData.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++)
|
for(int i = 0; i < NUM_CHECKPOINTS; i++)
|
||||||
ScoreData.m_aCpCurrent[i] = i;
|
ScoreData.m_aCpCurrent[i] = WithTimeCheckPoints ? i : 0;
|
||||||
str_copy(ScoreData.m_aRequestingPlayer, "deen", sizeof(ScoreData.m_aRequestingPlayer));
|
str_copy(ScoreData.m_aRequestingPlayer, "deen", sizeof(ScoreData.m_aRequestingPlayer));
|
||||||
ASSERT_FALSE(CScoreWorker::SaveScore(m_pConn, &ScoreData, false, m_aError, sizeof(m_aError))) << m_aError;
|
ASSERT_FALSE(CScoreWorker::SaveScore(m_pConn, &ScoreData, false, m_aError, sizeof(m_aError))) << m_aError;
|
||||||
}
|
}
|
||||||
|
@ -175,6 +175,31 @@ TEST_P(SingleScore, RankServer)
|
||||||
ExpectLines(m_pPlayerResult, {"nameless tee - 01:40.00 - better than 100% - requested by brainless tee", "Global rank 1 - USA rank 1"}, true);
|
ExpectLines(m_pPlayerResult, {"nameless tee - 01:40.00 - better than 100% - requested by brainless tee", "Global rank 1 - USA rank 1"}, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_P(SingleScore, LoadPlayerData)
|
||||||
|
{
|
||||||
|
InsertRank(120.0, true);
|
||||||
|
str_copy(m_PlayerRequest.m_aName, "", sizeof(m_PlayerRequest.m_aRequestingPlayer));
|
||||||
|
ASSERT_FALSE(CScoreWorker::LoadPlayerData(m_pConn, &m_PlayerRequest, m_aError, sizeof(m_aError))) << m_aError;
|
||||||
|
|
||||||
|
EXPECT_EQ(m_pPlayerResult->m_MessageKind, CScorePlayerResult::PLAYER_INFO);
|
||||||
|
ASSERT_EQ(m_pPlayerResult->m_Data.m_Info.m_Time, 0.0);
|
||||||
|
for(int i = 0; i < NUM_CHECKPOINTS; i++)
|
||||||
|
{
|
||||||
|
ASSERT_EQ(m_pPlayerResult->m_Data.m_Info.m_CpTime[i], 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
str_copy(m_PlayerRequest.m_aRequestingPlayer, "nameless tee", sizeof(m_PlayerRequest.m_aRequestingPlayer));
|
||||||
|
str_copy(m_PlayerRequest.m_aName, "", sizeof(m_PlayerRequest.m_aRequestingPlayer));
|
||||||
|
ASSERT_FALSE(CScoreWorker::LoadPlayerData(m_pConn, &m_PlayerRequest, m_aError, sizeof(m_aError))) << m_aError;
|
||||||
|
|
||||||
|
EXPECT_EQ(m_pPlayerResult->m_MessageKind, CScorePlayerResult::PLAYER_INFO);
|
||||||
|
ASSERT_EQ(m_pPlayerResult->m_Data.m_Info.m_Time, 100.0);
|
||||||
|
for(int i = 0; i < NUM_CHECKPOINTS; i++)
|
||||||
|
{
|
||||||
|
ASSERT_EQ(m_pPlayerResult->m_Data.m_Info.m_CpTime[i], i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
TEST_P(SingleScore, TimesExists)
|
TEST_P(SingleScore, TimesExists)
|
||||||
{
|
{
|
||||||
ASSERT_FALSE(CScoreWorker::ShowTimes(m_pConn, &m_PlayerRequest, m_aError, sizeof(m_aError))) << m_aError;
|
ASSERT_FALSE(CScoreWorker::ShowTimes(m_pConn, &m_PlayerRequest, m_aError, sizeof(m_aError))) << m_aError;
|
||||||
|
|
Loading…
Reference in a new issue