Fix scoreboard showing wrong best time

by requesting the best time again when it initially failed. This is
still not perfectly accurate since a player on another server can get a
better time, which will not get updated when the current server had no
database problems.

As reported by thekid36 on Discord:

> The best time shown on the scoreboard on the turkish server on a
> ddmax.Next map (mapname: 42) is 30min..while the best time should be 4
> min (it's correct on ger2 server)

So the way it works is that the best time is loaded from database when
loading map. Additionally it gets updated when a new finish is done. If
the initial load failed, but a finish with 30 min is done on the server,
we get this result
This commit is contained in:
def 2022-12-31 12:23:21 +01:00
parent 21b3b3b098
commit 694b9cd67d
8 changed files with 35 additions and 27 deletions

View file

@ -15,7 +15,7 @@
#define TEST_TYPE_NAME "TestDDraceNetwork" #define TEST_TYPE_NAME "TestDDraceNetwork"
CGameControllerDDRace::CGameControllerDDRace(class CGameContext *pGameServer) : CGameControllerDDRace::CGameControllerDDRace(class CGameContext *pGameServer) :
IGameController(pGameServer), m_Teams(pGameServer), m_pInitResult(nullptr) IGameController(pGameServer), m_Teams(pGameServer), m_pLoadBestTimeResult(nullptr)
{ {
m_pGameType = g_Config.m_SvTestingCommands ? TEST_TYPE_NAME : GAME_TYPE_NAME; m_pGameType = g_Config.m_SvTestingCommands ? TEST_TYPE_NAME : GAME_TYPE_NAME;
@ -171,13 +171,13 @@ void CGameControllerDDRace::Tick()
m_Teams.ProcessSaveTeam(); m_Teams.ProcessSaveTeam();
m_Teams.Tick(); m_Teams.Tick();
if(m_pInitResult != nullptr && m_pInitResult->m_Completed) if(m_pLoadBestTimeResult != nullptr && m_pLoadBestTimeResult->m_Completed)
{ {
if(m_pInitResult->m_Success) if(m_pLoadBestTimeResult->m_Success)
{ {
m_CurrentRecord = m_pInitResult->m_CurrentRecord; m_CurrentRecord = m_pLoadBestTimeResult->m_CurrentRecord;
} }
m_pInitResult = nullptr; m_pLoadBestTimeResult = nullptr;
} }
} }

View file

@ -8,7 +8,7 @@
#include <map> #include <map>
#include <vector> #include <vector>
struct CScoreInitResult; struct CScoreLoadBestTimeResult;
class CGameControllerDDRace : public IGameController class CGameControllerDDRace : public IGameController
{ {
public: public:
@ -40,6 +40,6 @@ public:
std::map<int, std::vector<vec2>> m_TeleOuts; std::map<int, std::vector<vec2>> m_TeleOuts;
std::map<int, std::vector<vec2>> m_TeleCheckOuts; std::map<int, std::vector<vec2>> m_TeleCheckOuts;
std::shared_ptr<CScoreInitResult> m_pInitResult; std::shared_ptr<CScoreLoadBestTimeResult> m_pLoadBestTimeResult;
}; };
#endif // GAME_SERVER_GAMEMODES_DDRACE_H #endif // GAME_SERVER_GAMEMODES_DDRACE_H

View file

@ -73,11 +73,6 @@ CScore::CScore(CGameContext *pGameServer, CDbConnectionPool *pPool) :
m_pGameServer(pGameServer), m_pGameServer(pGameServer),
m_pServer(pGameServer->Server()) m_pServer(pGameServer->Server())
{ {
auto InitResult = std::make_shared<CScoreInitResult>();
auto Tmp = std::make_unique<CSqlInitData>(InitResult);
((CGameControllerDDRace *)(pGameServer->m_pController))->m_pInitResult = InitResult;
str_copy(Tmp->m_aMap, g_Config.m_SvMap, sizeof(Tmp->m_aMap));
uint64_t aSeed[2]; uint64_t aSeed[2];
secure_random_fill(aSeed, sizeof(aSeed)); secure_random_fill(aSeed, sizeof(aSeed));
m_Prng.Seed(aSeed); m_Prng.Seed(aSeed);
@ -109,8 +104,16 @@ CScore::CScore(CGameContext *pGameServer, CDbConnectionPool *pPool) :
Server()->SetErrorShutdown("sql too few words in wordlist"); Server()->SetErrorShutdown("sql too few words in wordlist");
return; return;
} }
}
m_pPool->Execute(CScoreWorker::Init, std::move(Tmp), "load best time"); void CScore::LoadBestTime()
{
auto LoadBestTimeResult = std::make_shared<CScoreLoadBestTimeResult>();
((CGameControllerDDRace *)(m_pGameServer->m_pController))->m_pLoadBestTimeResult = LoadBestTimeResult;
auto Tmp = std::make_unique<CSqlLoadBestTimeData>(LoadBestTimeResult);
str_copy(Tmp->m_aMap, g_Config.m_SvMap, sizeof(Tmp->m_aMap));
m_pPool->Execute(CScoreWorker::LoadBestTime, std::move(Tmp), "load best time");
} }
void CScore::LoadPlayerData(int ClientID, const char *pName) void CScore::LoadPlayerData(int ClientID, const char *pName)

View file

@ -44,6 +44,7 @@ public:
CPlayerData *PlayerData(int ID) { return &m_aPlayerData[ID]; } CPlayerData *PlayerData(int ID) { return &m_aPlayerData[ID]; }
void LoadBestTime();
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, const char *pName = ""); void LoadPlayerData(int ClientID, const char *pName = "");

View file

@ -94,10 +94,10 @@ bool CTeamrank::SamePlayers(const std::vector<std::string> *pvSortedNames)
return true; return true;
} }
bool CScoreWorker::Init(IDbConnection *pSqlServer, const ISqlData *pGameData, char *pError, int ErrorSize) bool CScoreWorker::LoadBestTime(IDbConnection *pSqlServer, const ISqlData *pGameData, char *pError, int ErrorSize)
{ {
const CSqlInitData *pData = dynamic_cast<const CSqlInitData *>(pGameData); auto pData = dynamic_cast<const CSqlLoadBestTimeData *>(pGameData);
CScoreInitResult *pResult = dynamic_cast<CScoreInitResult *>(pGameData->m_pResult.get()); auto pResult = dynamic_cast<CScoreLoadBestTimeResult *>(pGameData->m_pResult.get());
char aBuf[512]; char aBuf[512];
// get the best time // get the best time

View file

@ -62,18 +62,18 @@ struct CScorePlayerResult : ISqlResult
void SetVariant(Variant v); void SetVariant(Variant v);
}; };
struct CScoreInitResult : ISqlResult struct CScoreLoadBestTimeResult : ISqlResult
{ {
CScoreInitResult() : CScoreLoadBestTimeResult() :
m_CurrentRecord(0) m_CurrentRecord(0)
{ {
} }
float m_CurrentRecord; float m_CurrentRecord;
}; };
struct CSqlInitData : ISqlData struct CSqlLoadBestTimeData : ISqlData
{ {
CSqlInitData(std::shared_ptr<CScoreInitResult> pResult) : CSqlLoadBestTimeData(std::shared_ptr<CScoreLoadBestTimeResult> pResult) :
ISqlData(std::move(pResult)) ISqlData(std::move(pResult))
{ {
} }
@ -274,7 +274,7 @@ struct CTeamrank
struct CScoreWorker struct CScoreWorker
{ {
static bool Init(IDbConnection *pSqlServer, const ISqlData *pGameData, char *pError, int ErrorSize); static bool LoadBestTime(IDbConnection *pSqlServer, const ISqlData *pGameData, char *pError, int ErrorSize);
static bool RandomMap(IDbConnection *pSqlServer, const ISqlData *pGameData, char *pError, int ErrorSize); static bool RandomMap(IDbConnection *pSqlServer, const ISqlData *pGameData, char *pError, int ErrorSize);
static bool RandomUnfinishedMap(IDbConnection *pSqlServer, const ISqlData *pGameData, char *pError, int ErrorSize); static bool RandomUnfinishedMap(IDbConnection *pSqlServer, const ISqlData *pGameData, char *pError, int ErrorSize);

View file

@ -779,7 +779,11 @@ void CGameTeams::OnFinish(CPlayer *Player, float Time, const char *pTimestamp)
bool NeedToSendNewServerRecord = false; bool NeedToSendNewServerRecord = false;
// update server best time // update server best time
if(GameServer()->m_pController->m_CurrentRecord == 0 || Time < GameServer()->m_pController->m_CurrentRecord) if(GameServer()->m_pController->m_CurrentRecord == 0)
{
GameServer()->Score()->LoadBestTime();
}
else if(Time < GameServer()->m_pController->m_CurrentRecord)
{ {
// check for nameless // check for nameless
if(g_Config.m_SvNamelessScore || !str_startswith(Server()->ClientName(ClientID), "nameless tee")) if(g_Config.m_SvNamelessScore || !str_startswith(Server()->ClientName(ClientID), "nameless tee"))

View file

@ -41,7 +41,7 @@ struct Score : public testing::TestWithParam<IDbConnection *>
Score() Score()
{ {
Connect(); Connect();
Init(); LoadBestTime();
InsertMap(); InsertMap();
} }
@ -68,11 +68,11 @@ struct Score : public testing::TestWithParam<IDbConnection *>
ASSERT_FALSE(m_pConn->ExecuteUpdate(&NumInserted, m_aError, sizeof(m_aError))) << m_aError; ASSERT_FALSE(m_pConn->ExecuteUpdate(&NumInserted, m_aError, sizeof(m_aError))) << m_aError;
} }
void Init() void LoadBestTime()
{ {
CSqlInitData initData(std::make_shared<CScoreInitResult>()); CSqlLoadBestTimeData loadBestTimeData(std::make_shared<CScoreLoadBestTimeResult>());
str_copy(initData.m_aMap, "Kobra 3", sizeof(initData.m_aMap)); str_copy(loadBestTimeData.m_aMap, "Kobra 3", sizeof(loadBestTimeData.m_aMap));
ASSERT_FALSE(CScoreWorker::Init(m_pConn, &initData, m_aError, sizeof(m_aError))) << m_aError; ASSERT_FALSE(CScoreWorker::LoadBestTime(m_pConn, &loadBestTimeData, m_aError, sizeof(m_aError))) << m_aError;
} }
void InsertMap() void InsertMap()