2020-06-24 21:14:09 +00:00
|
|
|
#include "score.h"
|
2020-07-04 17:53:27 +00:00
|
|
|
#include "entities/character.h"
|
|
|
|
#include "gamemodes/DDRace.h"
|
2021-01-09 14:37:02 +00:00
|
|
|
#include "player.h"
|
2020-07-04 17:53:27 +00:00
|
|
|
#include "save.h"
|
2021-11-24 12:09:07 +00:00
|
|
|
#include "scoreworker.h"
|
2020-07-04 17:53:27 +00:00
|
|
|
|
|
|
|
#include <base/system.h>
|
|
|
|
#include <engine/server/databases/connection.h>
|
|
|
|
#include <engine/server/databases/connection_pool.h>
|
|
|
|
#include <engine/server/sql_string_helpers.h>
|
|
|
|
#include <engine/shared/config.h>
|
|
|
|
#include <engine/shared/console.h>
|
|
|
|
#include <engine/shared/linereader.h>
|
|
|
|
#include <engine/storage.h>
|
2020-11-03 13:48:24 +00:00
|
|
|
#include <game/generated/wordlist.h>
|
2020-07-04 17:53:27 +00:00
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
#include <algorithm>
|
2020-07-04 17:53:27 +00:00
|
|
|
#include <cstring>
|
2020-09-26 19:41:58 +00:00
|
|
|
#include <fstream>
|
2020-07-04 17:53:27 +00:00
|
|
|
#include <random>
|
2020-06-24 21:14:09 +00:00
|
|
|
|
2020-07-04 17:53:27 +00:00
|
|
|
std::shared_ptr<CScorePlayerResult> CScore::NewSqlPlayerResult(int ClientID)
|
|
|
|
{
|
|
|
|
CPlayer *pCurPlayer = GameServer()->m_apPlayers[ClientID];
|
|
|
|
if(pCurPlayer->m_ScoreQueryResult != nullptr) // TODO: send player a message: "too many requests"
|
|
|
|
return nullptr;
|
|
|
|
pCurPlayer->m_ScoreQueryResult = std::make_shared<CScorePlayerResult>();
|
|
|
|
return pCurPlayer->m_ScoreQueryResult;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CScore::ExecPlayerThread(
|
2021-01-31 16:58:30 +00:00
|
|
|
bool (*pFuncPtr)(IDbConnection *, const ISqlData *, char *pError, int ErrorSize),
|
2020-09-26 19:41:58 +00:00
|
|
|
const char *pThreadName,
|
|
|
|
int ClientID,
|
|
|
|
const char *pName,
|
|
|
|
int Offset)
|
2020-07-04 17:53:27 +00:00
|
|
|
{
|
|
|
|
auto pResult = NewSqlPlayerResult(ClientID);
|
|
|
|
if(pResult == nullptr)
|
|
|
|
return;
|
|
|
|
auto Tmp = std::unique_ptr<CSqlPlayerRequest>(new CSqlPlayerRequest(pResult));
|
2021-09-13 09:47:47 +00:00
|
|
|
str_copy(Tmp->m_aName, pName, sizeof(Tmp->m_aName));
|
|
|
|
str_copy(Tmp->m_aMap, g_Config.m_SvMap, sizeof(Tmp->m_aMap));
|
|
|
|
str_copy(Tmp->m_aServer, g_Config.m_SvSqlServerName, sizeof(Tmp->m_aServer));
|
|
|
|
str_copy(Tmp->m_aRequestingPlayer, Server()->ClientName(ClientID), sizeof(Tmp->m_aRequestingPlayer));
|
2020-07-04 17:53:27 +00:00
|
|
|
Tmp->m_Offset = Offset;
|
|
|
|
|
|
|
|
m_pPool->Execute(pFuncPtr, std::move(Tmp), pThreadName);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool CScore::RateLimitPlayer(int ClientID)
|
|
|
|
{
|
|
|
|
CPlayer *pPlayer = GameServer()->m_apPlayers[ClientID];
|
|
|
|
if(pPlayer == 0)
|
|
|
|
return true;
|
2021-06-23 05:05:49 +00:00
|
|
|
if(pPlayer->m_LastSQLQuery + (int64_t)g_Config.m_SvSqlQueriesDelay * Server()->TickSpeed() >= Server()->Tick())
|
2020-07-04 17:53:27 +00:00
|
|
|
return true;
|
|
|
|
pPlayer->m_LastSQLQuery = Server()->Tick();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void CScore::GeneratePassphrase(char *pBuf, int BufSize)
|
|
|
|
{
|
|
|
|
for(int i = 0; i < 3; i++)
|
|
|
|
{
|
|
|
|
if(i != 0)
|
|
|
|
str_append(pBuf, " ", BufSize);
|
|
|
|
// TODO: decide if the slight bias towards lower numbers is ok
|
|
|
|
int Rand = m_Prng.RandomBits() % m_aWordlist.size();
|
|
|
|
str_append(pBuf, m_aWordlist[Rand].c_str(), BufSize);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CScore::CScore(CGameContext *pGameServer, CDbConnectionPool *pPool) :
|
2020-09-26 19:41:58 +00:00
|
|
|
m_pPool(pPool),
|
|
|
|
m_pGameServer(pGameServer),
|
|
|
|
m_pServer(pGameServer->Server())
|
2020-07-04 17:53:27 +00:00
|
|
|
{
|
|
|
|
auto InitResult = std::make_shared<CScoreInitResult>();
|
|
|
|
auto Tmp = std::unique_ptr<CSqlInitData>(new CSqlInitData(InitResult));
|
2020-09-26 19:41:58 +00:00
|
|
|
((CGameControllerDDRace *)(pGameServer->m_pController))->m_pInitResult = InitResult;
|
2021-09-13 09:47:47 +00:00
|
|
|
str_copy(Tmp->m_aMap, g_Config.m_SvMap, sizeof(Tmp->m_aMap));
|
2020-07-04 17:53:27 +00:00
|
|
|
|
2021-06-23 05:05:49 +00:00
|
|
|
uint64_t aSeed[2];
|
2020-07-04 17:53:27 +00:00
|
|
|
secure_random_fill(aSeed, sizeof(aSeed));
|
|
|
|
m_Prng.Seed(aSeed);
|
2020-11-03 13:48:24 +00:00
|
|
|
|
2021-12-17 20:58:28 +00:00
|
|
|
IOHANDLE File = GameServer()->Storage()->OpenFile("wordlist.txt", IOFLAG_READ | IOFLAG_SKIP_BOM, IStorage::TYPE_ALL);
|
2020-11-03 13:48:24 +00:00
|
|
|
if(File)
|
|
|
|
{
|
|
|
|
CLineReader LineReader;
|
|
|
|
LineReader.Init(File);
|
|
|
|
char *pLine;
|
|
|
|
while((pLine = LineReader.Get()))
|
|
|
|
{
|
2021-09-13 09:47:47 +00:00
|
|
|
char aWord[32] = {0};
|
|
|
|
sscanf(pLine, "%*s %31s", aWord);
|
|
|
|
aWord[31] = 0;
|
|
|
|
m_aWordlist.push_back(aWord);
|
2020-11-03 13:48:24 +00:00
|
|
|
}
|
2022-02-11 15:30:18 +00:00
|
|
|
io_close(File);
|
2020-11-03 13:48:24 +00:00
|
|
|
}
|
|
|
|
else
|
2020-07-04 17:53:27 +00:00
|
|
|
{
|
2020-11-03 13:48:24 +00:00
|
|
|
dbg_msg("sql", "failed to open wordlist, using fallback");
|
|
|
|
m_aWordlist.assign(std::begin(g_aFallbackWordlist), std::end(g_aFallbackWordlist));
|
2020-07-04 17:53:27 +00:00
|
|
|
}
|
2020-11-03 13:48:24 +00:00
|
|
|
|
2020-07-04 17:53:27 +00:00
|
|
|
if(m_aWordlist.size() < 1000)
|
|
|
|
{
|
|
|
|
dbg_msg("sql", "too few words in wordlist");
|
|
|
|
Server()->SetErrorShutdown("sql too few words in wordlist");
|
|
|
|
return;
|
|
|
|
}
|
2020-11-03 13:48:24 +00:00
|
|
|
|
2021-11-24 12:09:07 +00:00
|
|
|
m_pPool->Execute(CScoreWorker::Init, std::move(Tmp), "load best time");
|
2020-07-04 17:53:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CScore::LoadPlayerData(int ClientID)
|
|
|
|
{
|
2021-11-24 12:09:07 +00:00
|
|
|
ExecPlayerThread(CScoreWorker::LoadPlayerData, "load player data", ClientID, "", 0);
|
2020-07-04 17:53:27 +00:00
|
|
|
}
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
void CScore::MapVote(int ClientID, const char *MapName)
|
2020-07-04 17:53:27 +00:00
|
|
|
{
|
|
|
|
if(RateLimitPlayer(ClientID))
|
|
|
|
return;
|
2021-11-24 12:09:07 +00:00
|
|
|
ExecPlayerThread(CScoreWorker::MapVote, "map vote", ClientID, MapName, 0);
|
2020-07-04 17:53:27 +00:00
|
|
|
}
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
void CScore::MapInfo(int ClientID, const char *MapName)
|
2020-07-04 17:53:27 +00:00
|
|
|
{
|
|
|
|
if(RateLimitPlayer(ClientID))
|
|
|
|
return;
|
2021-11-24 12:09:07 +00:00
|
|
|
ExecPlayerThread(CScoreWorker::MapInfo, "map info", ClientID, MapName, 0);
|
2020-07-04 17:53:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CScore::SaveScore(int ClientID, float Time, const char *pTimestamp, float CpTime[NUM_CHECKPOINTS], bool NotEligible)
|
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
CConsole *pCon = (CConsole *)GameServer()->Console();
|
2020-07-04 17:53:27 +00:00
|
|
|
if(pCon->m_Cheated || NotEligible)
|
|
|
|
return;
|
|
|
|
|
|
|
|
CPlayer *pCurPlayer = GameServer()->m_apPlayers[ClientID];
|
|
|
|
if(pCurPlayer->m_ScoreFinishResult != nullptr)
|
|
|
|
dbg_msg("sql", "WARNING: previous save score result didn't complete, overwriting it now");
|
|
|
|
pCurPlayer->m_ScoreFinishResult = std::make_shared<CScorePlayerResult>();
|
|
|
|
auto Tmp = std::unique_ptr<CSqlScoreData>(new CSqlScoreData(pCurPlayer->m_ScoreFinishResult));
|
2021-09-13 09:47:47 +00:00
|
|
|
str_copy(Tmp->m_aMap, g_Config.m_SvMap, sizeof(Tmp->m_aMap));
|
|
|
|
FormatUuid(GameServer()->GameUuid(), Tmp->m_aGameUuid, sizeof(Tmp->m_aGameUuid));
|
2020-07-04 17:53:27 +00:00
|
|
|
Tmp->m_ClientID = ClientID;
|
2021-09-13 09:47:47 +00:00
|
|
|
str_copy(Tmp->m_aName, Server()->ClientName(ClientID), sizeof(Tmp->m_aName));
|
2020-07-04 17:53:27 +00:00
|
|
|
Tmp->m_Time = Time;
|
|
|
|
str_copy(Tmp->m_aTimestamp, pTimestamp, sizeof(Tmp->m_aTimestamp));
|
|
|
|
for(int i = 0; i < NUM_CHECKPOINTS; i++)
|
|
|
|
Tmp->m_aCpCurrent[i] = CpTime[i];
|
|
|
|
|
2021-11-24 12:09:07 +00:00
|
|
|
m_pPool->ExecuteWrite(CScoreWorker::SaveScore, std::move(Tmp), "save score");
|
2020-07-04 17:53:27 +00:00
|
|
|
}
|
|
|
|
|
2022-01-22 13:12:59 +00:00
|
|
|
void CScore::SaveTeamScore(int *pClientIDs, unsigned int Size, float Time, const char *pTimestamp)
|
2020-07-04 17:53:27 +00:00
|
|
|
{
|
2020-09-26 19:41:58 +00:00
|
|
|
CConsole *pCon = (CConsole *)GameServer()->Console();
|
2020-07-04 17:53:27 +00:00
|
|
|
if(pCon->m_Cheated)
|
|
|
|
return;
|
|
|
|
for(unsigned int i = 0; i < Size; i++)
|
|
|
|
{
|
2022-01-22 13:12:59 +00:00
|
|
|
if(GameServer()->m_apPlayers[pClientIDs[i]]->m_NotEligibleForFinish)
|
2020-07-04 17:53:27 +00:00
|
|
|
return;
|
|
|
|
}
|
2020-09-26 19:41:58 +00:00
|
|
|
auto Tmp = std::unique_ptr<CSqlTeamScoreData>(new CSqlTeamScoreData());
|
2020-07-04 17:53:27 +00:00
|
|
|
for(unsigned int i = 0; i < Size; i++)
|
2022-01-22 13:12:59 +00:00
|
|
|
str_copy(Tmp->m_aaNames[i], Server()->ClientName(pClientIDs[i]), sizeof(Tmp->m_aaNames[i]));
|
2020-07-04 17:53:27 +00:00
|
|
|
Tmp->m_Size = Size;
|
|
|
|
Tmp->m_Time = Time;
|
|
|
|
str_copy(Tmp->m_aTimestamp, pTimestamp, sizeof(Tmp->m_aTimestamp));
|
2021-09-13 09:47:47 +00:00
|
|
|
FormatUuid(GameServer()->GameUuid(), Tmp->m_aGameUuid, sizeof(Tmp->m_aGameUuid));
|
|
|
|
str_copy(Tmp->m_aMap, g_Config.m_SvMap, sizeof(Tmp->m_aMap));
|
2020-07-04 17:53:27 +00:00
|
|
|
|
2021-11-24 12:09:07 +00:00
|
|
|
m_pPool->ExecuteWrite(CScoreWorker::SaveTeamScore, std::move(Tmp), "save team score");
|
2020-07-04 17:53:27 +00:00
|
|
|
}
|
|
|
|
|
2021-11-24 12:09:07 +00:00
|
|
|
void CScore::ShowRank(int ClientID, const char *pName)
|
2020-07-04 17:53:27 +00:00
|
|
|
{
|
2021-11-24 12:09:07 +00:00
|
|
|
if(RateLimitPlayer(ClientID))
|
|
|
|
return;
|
|
|
|
ExecPlayerThread(CScoreWorker::ShowRank, "show rank", ClientID, pName, 0);
|
2020-07-04 17:53:27 +00:00
|
|
|
}
|
|
|
|
|
2021-11-24 12:09:07 +00:00
|
|
|
void CScore::ShowTeamRank(int ClientID, const char *pName)
|
2020-07-04 17:53:27 +00:00
|
|
|
{
|
|
|
|
if(RateLimitPlayer(ClientID))
|
|
|
|
return;
|
2021-11-24 12:09:07 +00:00
|
|
|
ExecPlayerThread(CScoreWorker::ShowTeamRank, "show team rank", ClientID, pName, 0);
|
2020-07-04 17:53:27 +00:00
|
|
|
}
|
|
|
|
|
2021-11-24 12:09:07 +00:00
|
|
|
void CScore::ShowTop(int ClientID, int Offset)
|
2020-07-04 17:53:27 +00:00
|
|
|
{
|
2021-11-24 12:09:07 +00:00
|
|
|
if(RateLimitPlayer(ClientID))
|
|
|
|
return;
|
|
|
|
ExecPlayerThread(CScoreWorker::ShowTop, "show top5", ClientID, "", Offset);
|
2020-07-04 17:53:27 +00:00
|
|
|
}
|
|
|
|
|
2021-11-24 12:09:07 +00:00
|
|
|
void CScore::ShowTeamTop5(int ClientID, int Offset)
|
2020-07-04 17:53:27 +00:00
|
|
|
{
|
|
|
|
if(RateLimitPlayer(ClientID))
|
|
|
|
return;
|
2021-11-24 12:09:07 +00:00
|
|
|
ExecPlayerThread(CScoreWorker::ShowTeamTop5, "show team top5", ClientID, "", Offset);
|
2020-07-04 17:53:27 +00:00
|
|
|
}
|
|
|
|
|
2021-11-24 12:09:07 +00:00
|
|
|
void CScore::ShowTeamTop5(int ClientID, const char *pName, int Offset)
|
2020-07-04 17:53:27 +00:00
|
|
|
{
|
2021-11-24 12:09:07 +00:00
|
|
|
if(RateLimitPlayer(ClientID))
|
|
|
|
return;
|
|
|
|
ExecPlayerThread(CScoreWorker::ShowPlayerTeamTop5, "show team top5 player", ClientID, pName, Offset);
|
2020-07-04 17:53:27 +00:00
|
|
|
}
|
|
|
|
|
2021-11-24 12:09:07 +00:00
|
|
|
void CScore::ShowTimes(int ClientID, int Offset)
|
2020-07-04 17:53:27 +00:00
|
|
|
{
|
2021-03-03 14:50:43 +00:00
|
|
|
if(RateLimitPlayer(ClientID))
|
2020-07-04 17:53:27 +00:00
|
|
|
return;
|
2021-11-24 12:09:07 +00:00
|
|
|
ExecPlayerThread(CScoreWorker::ShowTimes, "show times", ClientID, "", Offset);
|
2020-07-04 17:53:27 +00:00
|
|
|
}
|
|
|
|
|
2021-11-24 12:09:07 +00:00
|
|
|
void CScore::ShowTimes(int ClientID, const char *pName, int Offset)
|
2020-07-04 17:53:27 +00:00
|
|
|
{
|
|
|
|
if(RateLimitPlayer(ClientID))
|
|
|
|
return;
|
2021-11-24 12:09:07 +00:00
|
|
|
ExecPlayerThread(CScoreWorker::ShowTimes, "show times", ClientID, pName, Offset);
|
2020-07-04 17:53:27 +00:00
|
|
|
}
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
void CScore::ShowPoints(int ClientID, const char *pName)
|
2020-07-04 17:53:27 +00:00
|
|
|
{
|
|
|
|
if(RateLimitPlayer(ClientID))
|
|
|
|
return;
|
2021-11-24 12:09:07 +00:00
|
|
|
ExecPlayerThread(CScoreWorker::ShowPoints, "show points", ClientID, pName, 0);
|
2020-07-04 17:53:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CScore::ShowTopPoints(int ClientID, int Offset)
|
|
|
|
{
|
|
|
|
if(RateLimitPlayer(ClientID))
|
|
|
|
return;
|
2021-11-24 12:09:07 +00:00
|
|
|
ExecPlayerThread(CScoreWorker::ShowTopPoints, "show top points", ClientID, "", Offset);
|
2020-07-04 17:53:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CScore::RandomMap(int ClientID, int Stars)
|
|
|
|
{
|
|
|
|
auto pResult = std::make_shared<CScoreRandomMapResult>(ClientID);
|
|
|
|
GameServer()->m_SqlRandomMapResult = pResult;
|
|
|
|
|
|
|
|
auto Tmp = std::unique_ptr<CSqlRandomMapRequest>(new CSqlRandomMapRequest(pResult));
|
|
|
|
Tmp->m_Stars = Stars;
|
2021-09-13 09:47:47 +00:00
|
|
|
str_copy(Tmp->m_aCurrentMap, g_Config.m_SvMap, sizeof(Tmp->m_aCurrentMap));
|
|
|
|
str_copy(Tmp->m_aServerType, g_Config.m_SvServerType, sizeof(Tmp->m_aServerType));
|
|
|
|
str_copy(Tmp->m_aRequestingPlayer, GameServer()->Server()->ClientName(ClientID), sizeof(Tmp->m_aRequestingPlayer));
|
2020-07-04 17:53:27 +00:00
|
|
|
|
2021-11-24 12:09:07 +00:00
|
|
|
m_pPool->Execute(CScoreWorker::RandomMap, std::move(Tmp), "random map");
|
2020-07-04 17:53:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CScore::RandomUnfinishedMap(int ClientID, int Stars)
|
|
|
|
{
|
|
|
|
auto pResult = std::make_shared<CScoreRandomMapResult>(ClientID);
|
|
|
|
GameServer()->m_SqlRandomMapResult = pResult;
|
|
|
|
|
|
|
|
auto Tmp = std::unique_ptr<CSqlRandomMapRequest>(new CSqlRandomMapRequest(pResult));
|
|
|
|
Tmp->m_Stars = Stars;
|
2021-09-13 09:47:47 +00:00
|
|
|
str_copy(Tmp->m_aCurrentMap, g_Config.m_SvMap, sizeof(Tmp->m_aCurrentMap));
|
|
|
|
str_copy(Tmp->m_aServerType, g_Config.m_SvServerType, sizeof(Tmp->m_aServerType));
|
|
|
|
str_copy(Tmp->m_aRequestingPlayer, GameServer()->Server()->ClientName(ClientID), sizeof(Tmp->m_aRequestingPlayer));
|
2020-07-04 17:53:27 +00:00
|
|
|
|
2021-11-24 12:09:07 +00:00
|
|
|
m_pPool->Execute(CScoreWorker::RandomUnfinishedMap, std::move(Tmp), "random unfinished map");
|
2020-07-04 17:53:27 +00:00
|
|
|
}
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
void CScore::SaveTeam(int ClientID, const char *Code, const char *Server)
|
2020-07-04 17:53:27 +00:00
|
|
|
{
|
|
|
|
if(RateLimitPlayer(ClientID))
|
|
|
|
return;
|
2020-10-26 10:28:18 +00:00
|
|
|
auto *pController = ((CGameControllerDDRace *)(GameServer()->m_pController));
|
2020-07-04 17:53:27 +00:00
|
|
|
int Team = pController->m_Teams.m_Core.Team(ClientID);
|
|
|
|
if(pController->m_Teams.GetSaving(Team))
|
|
|
|
return;
|
|
|
|
|
|
|
|
auto SaveResult = std::make_shared<CScoreSaveResult>(ClientID, pController);
|
2020-12-08 11:03:43 +00:00
|
|
|
SaveResult->m_SaveID = RandomUuid();
|
2021-02-16 17:15:50 +00:00
|
|
|
int Result = SaveResult->m_SavedTeam.Save(Team);
|
2020-07-04 17:53:27 +00:00
|
|
|
if(CSaveTeam::HandleSaveError(Result, ClientID, GameServer()))
|
|
|
|
return;
|
|
|
|
pController->m_Teams.SetSaving(Team, SaveResult);
|
|
|
|
|
|
|
|
auto Tmp = std::unique_ptr<CSqlTeamSave>(new CSqlTeamSave(SaveResult));
|
2021-09-13 09:47:47 +00:00
|
|
|
str_copy(Tmp->m_aCode, Code, sizeof(Tmp->m_aCode));
|
|
|
|
str_copy(Tmp->m_aMap, g_Config.m_SvMap, sizeof(Tmp->m_aMap));
|
|
|
|
str_copy(Tmp->m_aServer, Server, sizeof(Tmp->m_aServer));
|
|
|
|
str_copy(Tmp->m_aClientName, this->Server()->ClientName(ClientID), sizeof(Tmp->m_aClientName));
|
2020-07-04 17:53:27 +00:00
|
|
|
Tmp->m_aGeneratedCode[0] = '\0';
|
|
|
|
GeneratePassphrase(Tmp->m_aGeneratedCode, sizeof(Tmp->m_aGeneratedCode));
|
|
|
|
|
|
|
|
pController->m_Teams.KillSavedTeam(ClientID, Team);
|
2021-11-24 12:09:07 +00:00
|
|
|
m_pPool->ExecuteWrite(CScoreWorker::SaveTeam, std::move(Tmp), "save team");
|
2020-07-04 17:53:27 +00:00
|
|
|
}
|
|
|
|
|
2020-09-26 19:41:58 +00:00
|
|
|
void CScore::LoadTeam(const char *Code, int ClientID)
|
2020-07-04 17:53:27 +00:00
|
|
|
{
|
|
|
|
if(RateLimitPlayer(ClientID))
|
|
|
|
return;
|
2020-10-26 10:28:18 +00:00
|
|
|
auto *pController = ((CGameControllerDDRace *)(GameServer()->m_pController));
|
2020-07-04 17:53:27 +00:00
|
|
|
int Team = pController->m_Teams.m_Core.Team(ClientID);
|
|
|
|
if(pController->m_Teams.GetSaving(Team))
|
|
|
|
return;
|
|
|
|
if(Team < TEAM_FLOCK || Team >= MAX_CLIENTS || (g_Config.m_SvTeam != 3 && Team == TEAM_FLOCK))
|
|
|
|
{
|
|
|
|
GameServer()->SendChatTarget(ClientID, "You have to be in a team (from 1-63)");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if(pController->m_Teams.GetTeamState(Team) != CGameTeams::TEAMSTATE_OPEN)
|
|
|
|
{
|
|
|
|
GameServer()->SendChatTarget(ClientID, "Team can't be loaded while racing");
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
auto SaveResult = std::make_shared<CScoreSaveResult>(ClientID, pController);
|
|
|
|
SaveResult->m_Status = CScoreSaveResult::LOAD_FAILED;
|
|
|
|
pController->m_Teams.SetSaving(Team, SaveResult);
|
|
|
|
auto Tmp = std::unique_ptr<CSqlTeamLoad>(new CSqlTeamLoad(SaveResult));
|
2021-09-13 09:47:47 +00:00
|
|
|
str_copy(Tmp->m_aCode, Code, sizeof(Tmp->m_aCode));
|
|
|
|
str_copy(Tmp->m_aMap, g_Config.m_SvMap, sizeof(Tmp->m_aMap));
|
2020-07-04 17:53:27 +00:00
|
|
|
Tmp->m_ClientID = ClientID;
|
2021-09-13 09:47:47 +00:00
|
|
|
str_copy(Tmp->m_aRequestingPlayer, Server()->ClientName(ClientID), sizeof(Tmp->m_aRequestingPlayer));
|
2020-07-04 17:53:27 +00:00
|
|
|
Tmp->m_NumPlayer = 0;
|
|
|
|
for(int i = 0; i < MAX_CLIENTS; i++)
|
|
|
|
{
|
|
|
|
if(pController->m_Teams.m_Core.Team(i) == Team)
|
|
|
|
{
|
|
|
|
// put all names at the beginning of the array
|
|
|
|
str_copy(Tmp->m_aClientNames[Tmp->m_NumPlayer], Server()->ClientName(i), sizeof(Tmp->m_aClientNames[Tmp->m_NumPlayer]));
|
|
|
|
Tmp->m_aClientID[Tmp->m_NumPlayer] = i;
|
|
|
|
Tmp->m_NumPlayer++;
|
|
|
|
}
|
|
|
|
}
|
2021-11-24 12:09:07 +00:00
|
|
|
m_pPool->ExecuteWrite(CScoreWorker::LoadTeam, std::move(Tmp), "load team");
|
2020-07-04 17:53:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void CScore::GetSaves(int ClientID)
|
|
|
|
{
|
|
|
|
if(RateLimitPlayer(ClientID))
|
|
|
|
return;
|
2021-11-24 12:09:07 +00:00
|
|
|
ExecPlayerThread(CScoreWorker::GetSaves, "get saves", ClientID, "", 0);
|
2020-07-04 17:53:27 +00:00
|
|
|
}
|