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"
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;
@ -171,13 +171,13 @@ void CGameControllerDDRace::Tick()
m_Teams.ProcessSaveTeam();
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 <vector>
struct CScoreInitResult;
struct CScoreLoadBestTimeResult;
class CGameControllerDDRace : public IGameController
{
public:
@ -40,6 +40,6 @@ public:
std::map<int, std::vector<vec2>> m_TeleOuts;
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

View file

@ -73,11 +73,6 @@ CScore::CScore(CGameContext *pGameServer, CDbConnectionPool *pPool) :
m_pGameServer(pGameServer),
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];
secure_random_fill(aSeed, sizeof(aSeed));
m_Prng.Seed(aSeed);
@ -109,8 +104,16 @@ CScore::CScore(CGameContext *pGameServer, CDbConnectionPool *pPool) :
Server()->SetErrorShutdown("sql too few words in wordlist");
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)

View file

@ -44,6 +44,7 @@ public:
CPlayerData *PlayerData(int ID) { return &m_aPlayerData[ID]; }
void LoadBestTime();
void MapInfo(int ClientID, const char *pMapName);
void MapVote(int ClientID, const char *pMapName);
void LoadPlayerData(int ClientID, const char *pName = "");

View file

@ -94,10 +94,10 @@ bool CTeamrank::SamePlayers(const std::vector<std::string> *pvSortedNames)
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);
CScoreInitResult *pResult = dynamic_cast<CScoreInitResult *>(pGameData->m_pResult.get());
auto pData = dynamic_cast<const CSqlLoadBestTimeData *>(pGameData);
auto pResult = dynamic_cast<CScoreLoadBestTimeResult *>(pGameData->m_pResult.get());
char aBuf[512];
// get the best time

View file

@ -62,18 +62,18 @@ struct CScorePlayerResult : ISqlResult
void SetVariant(Variant v);
};
struct CScoreInitResult : ISqlResult
struct CScoreLoadBestTimeResult : ISqlResult
{
CScoreInitResult() :
CScoreLoadBestTimeResult() :
m_CurrentRecord(0)
{
}
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))
{
}
@ -274,7 +274,7 @@ struct CTeamrank
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 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;
// 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
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()
{
Connect();
Init();
LoadBestTime();
InsertMap();
}
@ -68,11 +68,11 @@ struct Score : public testing::TestWithParam<IDbConnection *>
ASSERT_FALSE(m_pConn->ExecuteUpdate(&NumInserted, m_aError, sizeof(m_aError))) << m_aError;
}
void Init()
void LoadBestTime()
{
CSqlInitData initData(std::make_shared<CScoreInitResult>());
str_copy(initData.m_aMap, "Kobra 3", sizeof(initData.m_aMap));
ASSERT_FALSE(CScoreWorker::Init(m_pConn, &initData, m_aError, sizeof(m_aError))) << m_aError;
CSqlLoadBestTimeData loadBestTimeData(std::make_shared<CScoreLoadBestTimeResult>());
str_copy(loadBestTimeData.m_aMap, "Kobra 3", sizeof(loadBestTimeData.m_aMap));
ASSERT_FALSE(CScoreWorker::LoadBestTime(m_pConn, &loadBestTimeData, m_aError, sizeof(m_aError))) << m_aError;
}
void InsertMap()