diff --git a/src/game/server/ddracechat.cpp b/src/game/server/ddracechat.cpp index 2b677fcf4..3ba13bd3d 100644 --- a/src/game/server/ddracechat.cpp +++ b/src/game/server/ddracechat.cpp @@ -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); } diff --git a/src/game/server/entities/character.cpp b/src/game/server/entities/character.cpp index 07ab908a7..c5a8e282f 100644 --- a/src/game/server/entities/character.cpp +++ b/src/game/server/entities/character.cpp @@ -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); diff --git a/src/game/server/player.cpp b/src/game/server/player.cpp index 68b98ba1e..c7a137665 100644 --- a/src/game/server/player.cpp +++ b/src/game/server/player.cpp @@ -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; + } } } diff --git a/src/game/server/score.cpp b/src/game/server/score.cpp index 927d7c9b0..e55e268b8 100644 --- a/src/game/server/score.cpp +++ b/src/game/server/score.cpp @@ -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)) diff --git a/src/game/server/score.h b/src/game/server/score.h index 501a4308a..7ed6abbb2 100644 --- a/src/game/server/score.h +++ b/src/game/server/score.h @@ -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); diff --git a/src/game/server/scoreworker.cpp b/src/game/server/scoreworker.cpp index 181f7b1ab..668fe98db 100644 --- a/src/game/server/scoreworker.cpp +++ b/src/game/server/scoreworker.cpp @@ -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(pGameData); + auto *pResult = dynamic_cast(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(pGameData); diff --git a/src/game/server/scoreworker.h b/src/game/server/scoreworker.h index ef3b6525c..9e38501e5 100644 --- a/src/game/server/scoreworker.h +++ b/src/game/server/scoreworker.h @@ -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 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);