diff --git a/CMakeLists.txt b/CMakeLists.txt index fc37b459d..40ae9314a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1914,6 +1914,7 @@ set_src(GAME_SERVER GLOB_RECURSE src/game/server player.h save.cpp save.h + score.cpp score.h score/file_score.cpp score/file_score.h diff --git a/src/engine/shared/config_variables.h b/src/engine/shared/config_variables.h index 69ff6112f..7fc021770 100644 --- a/src/engine/shared/config_variables.h +++ b/src/engine/shared/config_variables.h @@ -213,13 +213,12 @@ MACRO_CONFIG_INT(SvShotgunBulletSound, sv_shotgun_bullet_sound, 0, 0, 1, CFGFLAG 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") -#if defined(CONF_SQL) -MACRO_CONFIG_INT(SvUseSQL, sv_use_sql, 0, 0, 1, CFGFLAG_SERVER, "Enables SQL DB instead of record file") MACRO_CONFIG_STR(SvSqlServerName, sv_sql_servername, 5, "UNK", CFGFLAG_SERVER, "SQL Server name that is inserted into record table") MACRO_CONFIG_STR(SvSqlValidServerNames, sv_sql_valid_servernames, 64, "UNK", CFGFLAG_SERVER, "Comma separated list of valid server names for saving a game to ([A-Z][A-Z][A-Z].?") MACRO_CONFIG_INT(SvSaveGames, sv_savegames, 1, 0, 1, CFGFLAG_SERVER, "Enables savegames (/save and /load)") MACRO_CONFIG_INT(SvSaveGamesDelay, sv_savegames_delay, 60, 0, 10000, CFGFLAG_SERVER, "Delay in seconds for loading a savegame") - +#if defined(CONF_SQL) +MACRO_CONFIG_INT(SvUseSQL, sv_use_sql, 0, 0, 1, CFGFLAG_SERVER, "Enables SQL DB instead of record file") MACRO_CONFIG_STR(SvSqlFailureFile, sv_sql_failure_file, 64, "failed_sql.sql", CFGFLAG_SERVER, "File to store failed Sql-Inserts (ranks)") MACRO_CONFIG_INT(SvSqlQueriesDelay, sv_sql_queries_delay, 1, 0, 20, CFGFLAG_SERVER, "Delay in seconds between SQL queries of a single player") #endif diff --git a/src/game/server/ddracechat.cpp b/src/game/server/ddracechat.cpp index 95af8e1ce..375d25d25 100644 --- a/src/game/server/ddracechat.cpp +++ b/src/game/server/ddracechat.cpp @@ -6,9 +6,6 @@ #include #include #include -#if defined(CONF_SQL) -#include -#endif bool CheckClientID(int ClientID); @@ -372,12 +369,6 @@ void CGameContext::ConTeamTop5(IConsole::IResult *pResult, void *pUserData) if (!CheckClientID(pResult->m_ClientID)) return; -#if defined(CONF_SQL) - if(pSelf->m_apPlayers[pResult->m_ClientID] && g_Config.m_SvUseSQL) - if(pSelf->m_apPlayers[pResult->m_ClientID]->m_LastSQLQuery + g_Config.m_SvSqlQueriesDelay * pSelf->Server()->TickSpeed() >= pSelf->Server()->Tick()) - return; -#endif - if (g_Config.m_SvHideScore) { pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "teamtop5", @@ -389,11 +380,6 @@ void CGameContext::ConTeamTop5(IConsole::IResult *pResult, void *pUserData) pSelf->Score()->ShowTeamTop5(pResult->m_ClientID, pResult->GetInteger(0)); else pSelf->Score()->ShowTeamTop5(pResult->m_ClientID); - -#if defined(CONF_SQL) - if(pSelf->m_apPlayers[pResult->m_ClientID] && g_Config.m_SvUseSQL) - pSelf->m_apPlayers[pResult->m_ClientID]->m_LastSQLQuery = pSelf->Server()->Tick(); -#endif } void CGameContext::ConTop5(IConsole::IResult *pResult, void *pUserData) @@ -402,12 +388,6 @@ void CGameContext::ConTop5(IConsole::IResult *pResult, void *pUserData) if (!CheckClientID(pResult->m_ClientID)) return; -#if defined(CONF_SQL) - if(pSelf->m_apPlayers[pResult->m_ClientID] && g_Config.m_SvUseSQL) - if(pSelf->m_apPlayers[pResult->m_ClientID]->m_LastSQLQuery + g_Config.m_SvSqlQueriesDelay * pSelf->Server()->TickSpeed() >= pSelf->Server()->Tick()) - return; -#endif - if (g_Config.m_SvHideScore) { pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "top5", @@ -419,59 +399,43 @@ void CGameContext::ConTop5(IConsole::IResult *pResult, void *pUserData) pSelf->Score()->ShowTop5(pResult->m_ClientID, pResult->GetInteger(0)); else pSelf->Score()->ShowTop5(pResult->m_ClientID); - -#if defined(CONF_SQL) - if(pSelf->m_apPlayers[pResult->m_ClientID] && g_Config.m_SvUseSQL) - pSelf->m_apPlayers[pResult->m_ClientID]->m_LastSQLQuery = pSelf->Server()->Tick(); -#endif } void CGameContext::ConTimes(IConsole::IResult *pResult, void *pUserData) { -#if defined(CONF_SQL) - if(!CheckClientID(pResult->m_ClientID)) return; CGameContext *pSelf = (CGameContext *)pUserData; + if(!CheckClientID(pResult->m_ClientID)) + return; - if(pSelf->m_apPlayers[pResult->m_ClientID] && g_Config.m_SvUseSQL) - if(pSelf->m_apPlayers[pResult->m_ClientID]->m_LastSQLQuery + g_Config.m_SvSqlQueriesDelay * pSelf->Server()->TickSpeed() >= pSelf->Server()->Tick()) - return; - - if(g_Config.m_SvUseSQL) + if(pResult->NumArguments() == 0) { - CSqlScore *pScore = (CSqlScore *)pSelf->Score(); - CPlayer *pPlayer = pSelf->m_apPlayers[pResult->m_ClientID]; - if(!pPlayer) - return; - - if(pResult->NumArguments() == 0) + pSelf->Score()->ShowTimes(pResult->m_ClientID, 1); + } + else if(pResult->NumArguments() == 1) + { + if(pResult->GetInteger(0) != 0) { - pScore->ShowTimes(pPlayer->GetCID(),1); - } - else if(pResult->NumArguments() < 3) - { - if (pResult->NumArguments() == 1) - { - if(pResult->GetInteger(0) != 0) - pScore->ShowTimes(pPlayer->GetCID(),pResult->GetInteger(0)); - else - pScore->ShowTimes(pPlayer->GetCID(), (str_comp(pResult->GetString(0), "me") == 0) ? pSelf->Server()->ClientName(pResult->m_ClientID) : pResult->GetString(0),1); - } - else if (pResult->GetInteger(1) != 0) - { - pScore->ShowTimes(pPlayer->GetCID(), (str_comp(pResult->GetString(0), "me") == 0) ? pSelf->Server()->ClientName(pResult->m_ClientID) : pResult->GetString(0),pResult->GetInteger(1)); - } + pSelf->Score()->ShowTimes(pResult->m_ClientID, pResult->GetInteger(0)); } else { - pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "times", "/times needs 0, 1 or 2 parameter. 1. = name, 2. = start number"); - pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "times", "Example: /times, /times me, /times Hans, /times \"Papa Smurf\" 5"); - pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "times", "Bad: /times Papa Smurf 5 # Good: /times \"Papa Smurf\" 5 "); + const char *pRequestedName = (str_comp(pResult->GetString(0), "me") == 0) ? + pSelf->Server()->ClientName(pResult->m_ClientID) : pResult->GetString(0); + pSelf->Score()->ShowTimes(pResult->m_ClientID, pRequestedName, pResult->GetInteger(1)); } - - if(pSelf->m_apPlayers[pResult->m_ClientID] && g_Config.m_SvUseSQL) - pSelf->m_apPlayers[pResult->m_ClientID]->m_LastSQLQuery = pSelf->Server()->Tick(); } -#endif + else if(pResult->NumArguments() == 2 && pResult->GetInteger(1) != 0) + { + const char *pRequestedName = (str_comp(pResult->GetString(0), "me") == 0) ? + pSelf->Server()->ClientName(pResult->m_ClientID) : pResult->GetString(0); + pSelf->Score()->ShowTimes(pResult->m_ClientID, pRequestedName, pResult->GetInteger(1)); + } + else + { + pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "times", "/times needs 0, 1 or 2 parameter. 1. = name, 2. = start number"); + pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "times", "Example: /times, /times me, /times Hans, /times \"Papa Smurf\" 5"); + pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "times", "Bad: /times Papa Smurf 5 # Good: /times \"Papa Smurf\" 5 "); + } } void CGameContext::ConDND(IConsole::IResult *pResult, void *pUserData) @@ -521,18 +485,7 @@ void CGameContext::ConMap(IConsole::IResult *pResult, void *pUserData) if(pSelf->RateLimitPlayerVote(pResult->m_ClientID) || pSelf->RateLimitPlayerMapVote(pResult->m_ClientID)) return; -#if defined(CONF_SQL) - if(g_Config.m_SvUseSQL) - if(pPlayer->m_LastSQLQuery + g_Config.m_SvSqlQueriesDelay * pSelf->Server()->TickSpeed() >= pSelf->Server()->Tick()) - return; -#endif - pSelf->Score()->MapVote(pResult->m_ClientID, pResult->GetString(0)); - -#if defined(CONF_SQL) - if(g_Config.m_SvUseSQL) - pPlayer->m_LastSQLQuery = pSelf->Server()->Tick(); -#endif } void CGameContext::ConMapInfo(IConsole::IResult *pResult, void *pUserData) @@ -545,21 +498,11 @@ void CGameContext::ConMapInfo(IConsole::IResult *pResult, void *pUserData) if (!pPlayer) return; -#if defined(CONF_SQL) - if(g_Config.m_SvUseSQL) - if(pPlayer->m_LastSQLQuery + g_Config.m_SvSqlQueriesDelay * pSelf->Server()->TickSpeed() >= pSelf->Server()->Tick()) - return; -#endif - if (pResult->NumArguments() > 0) pSelf->Score()->MapInfo(pResult->m_ClientID, pResult->GetString(0)); else pSelf->Score()->MapInfo(pResult->m_ClientID, g_Config.m_SvMap); -#if defined(CONF_SQL) - if(g_Config.m_SvUseSQL) - pPlayer->m_LastSQLQuery = pSelf->Server()->Tick(); -#endif } void CGameContext::ConTimeout(IConsole::IResult *pResult, void *pUserData) @@ -692,21 +635,12 @@ void CGameContext::ConSave(IConsole::IResult *pResult, void *pUserData) if (!CheckClientID(pResult->m_ClientID)) return; - CPlayer *pPlayer = pSelf->m_apPlayers[pResult->m_ClientID]; - if (!pPlayer) - return; - -#if defined(CONF_SQL) if(!g_Config.m_SvSaveGames) { pSelf->SendChatTarget(pResult->m_ClientID, "Save-function is disabled on this server"); return; } - if(g_Config.m_SvUseSQL) - if(pPlayer->m_LastSQLQuery + g_Config.m_SvSqlQueriesDelay * pSelf->Server()->TickSpeed() >= pSelf->Server()->Tick()) - return; - const char* pCode = ""; if(pResult->NumArguments() > 0) pCode = pResult->GetString(0); @@ -738,9 +672,6 @@ void CGameContext::ConSave(IConsole::IResult *pResult, void *pUserData) if(str_in_list(g_Config.m_SvSqlValidServerNames, ",", aCountry)) { pSelf->Score()->SaveTeam(pResult->m_ClientID, pCode, aCountry); - - if(g_Config.m_SvUseSQL) - pPlayer->m_LastSQLQuery = pSelf->Server()->Tick(); } else { @@ -748,8 +679,6 @@ void CGameContext::ConSave(IConsole::IResult *pResult, void *pUserData) str_format(aBuf, sizeof(aBuf), "Unknown server name '%s'.", aCountry); pSelf->SendChatTarget(pResult->m_ClientID, aBuf); } - -#endif } void CGameContext::ConLoad(IConsole::IResult *pResult, void *pUserData) @@ -758,31 +687,16 @@ void CGameContext::ConLoad(IConsole::IResult *pResult, void *pUserData) if (!CheckClientID(pResult->m_ClientID)) return; - CPlayer *pPlayer = pSelf->m_apPlayers[pResult->m_ClientID]; - if (!pPlayer) - return; - -#if defined(CONF_SQL) if(!g_Config.m_SvSaveGames) { pSelf->SendChatTarget(pResult->m_ClientID, "Save-function is disabled on this server"); return; } - if(g_Config.m_SvUseSQL) - if(pPlayer->m_LastSQLQuery + g_Config.m_SvSqlQueriesDelay * pSelf->Server()->TickSpeed() >= pSelf->Server()->Tick()) - return; -#endif - if(pResult->NumArguments() > 0) pSelf->Score()->LoadTeam(pResult->GetString(0), pResult->m_ClientID); else pSelf->Score()->GetSaves(pResult->m_ClientID); - -#if defined(CONF_SQL) - if(g_Config.m_SvUseSQL) - pPlayer->m_LastSQLQuery = pSelf->Server()->Tick(); -#endif } void CGameContext::ConTeamRank(IConsole::IResult *pResult, void *pUserData) @@ -791,17 +705,8 @@ void CGameContext::ConTeamRank(IConsole::IResult *pResult, void *pUserData) if (!CheckClientID(pResult->m_ClientID)) return; - CPlayer *pPlayer = pSelf->m_apPlayers[pResult->m_ClientID]; - if (!pPlayer) - return; - -#if defined(CONF_SQL) - if(g_Config.m_SvUseSQL) - if(pPlayer->m_LastSQLQuery + g_Config.m_SvSqlQueriesDelay * pSelf->Server()->TickSpeed() >= pSelf->Server()->Tick()) - return; -#endif - if (pResult->NumArguments() > 0) + { if (!g_Config.m_SvHideScore) pSelf->Score()->ShowTeamRank(pResult->m_ClientID, pResult->GetString(0)); else @@ -809,14 +714,10 @@ void CGameContext::ConTeamRank(IConsole::IResult *pResult, void *pUserData) IConsole::OUTPUT_LEVEL_STANDARD, "teamrank", "Showing the team rank of other players is not allowed on this server."); + } else pSelf->Score()->ShowTeamRank(pResult->m_ClientID, pSelf->Server()->ClientName(pResult->m_ClientID)); - -#if defined(CONF_SQL) - if(g_Config.m_SvUseSQL) - pPlayer->m_LastSQLQuery = pSelf->Server()->Tick(); -#endif } void CGameContext::ConRank(IConsole::IResult *pResult, void *pUserData) @@ -825,17 +726,8 @@ void CGameContext::ConRank(IConsole::IResult *pResult, void *pUserData) if (!CheckClientID(pResult->m_ClientID)) return; - CPlayer *pPlayer = pSelf->m_apPlayers[pResult->m_ClientID]; - if (!pPlayer) - return; - -#if defined(CONF_SQL) - if(g_Config.m_SvUseSQL) - if(pPlayer->m_LastSQLQuery + g_Config.m_SvSqlQueriesDelay * pSelf->Server()->TickSpeed() >= pSelf->Server()->Tick()) - return; -#endif - if (pResult->NumArguments() > 0) + { if (!g_Config.m_SvHideScore) pSelf->Score()->ShowRank(pResult->m_ClientID, pResult->GetString(0)); else @@ -843,14 +735,10 @@ void CGameContext::ConRank(IConsole::IResult *pResult, void *pUserData) IConsole::OUTPUT_LEVEL_STANDARD, "rank", "Showing the rank of other players is not allowed on this server."); + } else pSelf->Score()->ShowRank(pResult->m_ClientID, pSelf->Server()->ClientName(pResult->m_ClientID)); - -#if defined(CONF_SQL) - if(g_Config.m_SvUseSQL) - pPlayer->m_LastSQLQuery = pSelf->Server()->Tick(); -#endif } void CGameContext::ConLockTeam(IConsole::IResult *pResult, void *pUserData) @@ -1522,20 +1410,12 @@ void CGameContext::ConProtectedKill(IConsole::IResult *pResult, void *pUserData) void CGameContext::ConPoints(IConsole::IResult *pResult, void *pUserData) { -#if defined(CONF_SQL) CGameContext *pSelf = (CGameContext *) pUserData; if (!CheckClientID(pResult->m_ClientID)) return; - if(pSelf->m_apPlayers[pResult->m_ClientID] && g_Config.m_SvUseSQL) - if(pSelf->m_apPlayers[pResult->m_ClientID]->m_LastSQLQuery + g_Config.m_SvSqlQueriesDelay * pSelf->Server()->TickSpeed() >= pSelf->Server()->Tick()) - return; - - CPlayer *pPlayer = pSelf->m_apPlayers[pResult->m_ClientID]; - if (!pPlayer) - return; - if (pResult->NumArguments() > 0) + { if (!g_Config.m_SvHideScore) pSelf->Score()->ShowPoints(pResult->m_ClientID, pResult->GetString(0)); else @@ -1543,26 +1423,18 @@ void CGameContext::ConPoints(IConsole::IResult *pResult, void *pUserData) IConsole::OUTPUT_LEVEL_STANDARD, "points", "Showing the global points of other players is not allowed on this server."); + } else pSelf->Score()->ShowPoints(pResult->m_ClientID, pSelf->Server()->ClientName(pResult->m_ClientID)); - - if(pSelf->m_apPlayers[pResult->m_ClientID] && g_Config.m_SvUseSQL) - pSelf->m_apPlayers[pResult->m_ClientID]->m_LastSQLQuery = pSelf->Server()->Tick(); -#endif } void CGameContext::ConTopPoints(IConsole::IResult *pResult, void *pUserData) { -#if defined(CONF_SQL) CGameContext *pSelf = (CGameContext *) pUserData; if (!CheckClientID(pResult->m_ClientID)) return; - if(pSelf->m_apPlayers[pResult->m_ClientID] && g_Config.m_SvUseSQL) - if(pSelf->m_apPlayers[pResult->m_ClientID]->m_LastSQLQuery + g_Config.m_SvSqlQueriesDelay * pSelf->Server()->TickSpeed() >= pSelf->Server()->Tick()) - return; - if (g_Config.m_SvHideScore) { pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "toppoints", @@ -1575,7 +1447,4 @@ void CGameContext::ConTopPoints(IConsole::IResult *pResult, void *pUserData) else pSelf->Score()->ShowTopPoints(pResult->m_ClientID); - if(pSelf->m_apPlayers[pResult->m_ClientID] && g_Config.m_SvUseSQL) - pSelf->m_apPlayers[pResult->m_ClientID]->m_LastSQLQuery = pSelf->Server()->Tick(); -#endif } diff --git a/src/game/server/ddracecommands.cpp b/src/game/server/ddracecommands.cpp index 1fbad4147..80b7b501a 100644 --- a/src/game/server/ddracecommands.cpp +++ b/src/game/server/ddracecommands.cpp @@ -5,9 +5,6 @@ #include #include #include -#if defined(CONF_SQL) -#include -#endif bool CheckClientID(int ClientID); diff --git a/src/game/server/gamecontext.cpp b/src/game/server/gamecontext.cpp index 2ef6bca57..0eb52b793 100644 --- a/src/game/server/gamecontext.cpp +++ b/src/game/server/gamecontext.cpp @@ -941,7 +941,6 @@ void CGameContext::OnTick() } } -#if defined(CONF_SQL) if(m_SqlRandomMapResult != nullptr && m_SqlRandomMapResult.use_count() == 1) { if(m_SqlRandomMapResult->m_Done) @@ -955,7 +954,6 @@ void CGameContext::OnTick() } m_SqlRandomMapResult = nullptr; } -#endif #ifdef CONF_DEBUG if(g_Config.m_DbgDummies) diff --git a/src/game/server/gamecontext.h b/src/game/server/gamecontext.h index 591225c89..0a05fb08e 100644 --- a/src/game/server/gamecontext.h +++ b/src/game/server/gamecontext.h @@ -58,7 +58,7 @@ class IConsole; class IEngine; class IStorage; struct CAntibotData; -struct CSqlRandomMapResult; +struct CScoreRandomMapResult; class CGameContext : public IGameServer { @@ -269,7 +269,7 @@ public: bool RateLimitPlayerVote(int ClientID); bool RateLimitPlayerMapVote(int ClientID); - std::shared_ptr m_SqlRandomMapResult; + std::shared_ptr m_SqlRandomMapResult; private: diff --git a/src/game/server/gamemodes/DDRace.cpp b/src/game/server/gamemodes/DDRace.cpp index dd9c76c99..5d70058c9 100644 --- a/src/game/server/gamemodes/DDRace.cpp +++ b/src/game/server/gamemodes/DDRace.cpp @@ -9,10 +9,6 @@ #include "DDRace.h" #include "gamemode.h" -#if defined(CONF_SQL) -#include -#endif - CGameControllerDDRace::CGameControllerDDRace(class CGameContext *pGameServer) : IGameController(pGameServer), m_Teams(pGameServer), m_pInitResult(nullptr) { @@ -29,7 +25,6 @@ CGameControllerDDRace::~CGameControllerDDRace() void CGameControllerDDRace::Tick() { IGameController::Tick(); -#if defined(CONF_SQL) m_Teams.ProcessSaveTeam(); if(m_pInitResult != nullptr && m_pInitResult.use_count() == 1) @@ -40,7 +35,6 @@ void CGameControllerDDRace::Tick() } m_pInitResult = nullptr; } -#endif } void CGameControllerDDRace::InitTeleporter() diff --git a/src/game/server/gamemodes/DDRace.h b/src/game/server/gamemodes/DDRace.h index 0db166138..68737a50c 100644 --- a/src/game/server/gamemodes/DDRace.h +++ b/src/game/server/gamemodes/DDRace.h @@ -8,7 +8,7 @@ #include #include -struct CSqlInitResult; +struct CScoreInitResult; class CGameControllerDDRace: public IGameController { public: @@ -24,6 +24,6 @@ public: void InitTeleporter(); virtual void Tick(); - std::shared_ptr m_pInitResult; + std::shared_ptr m_pInitResult; }; #endif // GAME_SERVER_GAMEMODES_DDRACE_H diff --git a/src/game/server/player.cpp b/src/game/server/player.cpp index 64161edc0..7baa33e42 100644 --- a/src/game/server/player.cpp +++ b/src/game/server/player.cpp @@ -12,10 +12,6 @@ #include "gamemodes/DDRace.h" #include -#if defined(CONF_SQL) -#include "score/sql_score.h" -#endif - MACRO_ALLOC_POOL_ID_IMPL(CPlayer, MAX_CLIENTS) IServer *CPlayer::Server() const { return m_pGameServer->Server(); } @@ -124,11 +120,9 @@ void CPlayer::Reset() // Variable initialized: m_Last_Team = 0; -#if defined(CONF_SQL) m_LastSQLQuery = 0; - m_SqlQueryResult = nullptr; - m_SqlFinishResult = nullptr; -#endif + m_ScoreQueryResult = nullptr; + m_ScoreFinishResult = nullptr; int64 Now = Server()->Tick(); int64 TickSpeed = Server()->TickSpeed(); @@ -174,18 +168,16 @@ void CPlayer::Tick() #ifdef CONF_DEBUG if(!g_Config.m_DbgDummies || m_ClientID < MAX_CLIENTS-g_Config.m_DbgDummies) #endif -#if defined(CONF_SQL) - if(m_SqlQueryResult != nullptr && m_SqlQueryResult.use_count() == 1) + if(m_ScoreQueryResult != nullptr && m_ScoreQueryResult.use_count() == 1) { - ProcessSqlResult(*m_SqlQueryResult); - m_SqlQueryResult = nullptr; + ProcessScoreResult(*m_ScoreQueryResult); + m_ScoreQueryResult = nullptr; } - if(m_SqlFinishResult != nullptr && m_SqlFinishResult.use_count() == 1) + if(m_ScoreFinishResult != nullptr && m_ScoreFinishResult.use_count() == 1) { - ProcessSqlResult(*m_SqlFinishResult); - m_SqlFinishResult = nullptr; + ProcessScoreResult(*m_ScoreFinishResult); + m_ScoreFinishResult = nullptr; } -#endif if(!Server()->ClientIngame(m_ClientID)) return; @@ -920,34 +912,33 @@ void CPlayer::SpectatePlayerName(const char *pName) } } -#if defined(CONF_SQL) -void CPlayer::ProcessSqlResult(CSqlPlayerResult &Result) +void CPlayer::ProcessScoreResult(CScorePlayerResult &Result) { if(Result.m_Done) // SQL request was successful { switch(Result.m_MessageKind) { - case CSqlPlayerResult::DIRECT: - for(int i = 0; i < CSqlPlayerResult::MAX_MESSAGES; i++) + case CScorePlayerResult::DIRECT: + for(int i = 0; i < CScorePlayerResult::MAX_MESSAGES; i++) { if(Result.m_Data.m_aaMessages[i][0] == 0) break; GameServer()->SendChatTarget(m_ClientID, Result.m_Data.m_aaMessages[i]); } break; - case CSqlPlayerResult::ALL: - for(int i = 0; i < CSqlPlayerResult::MAX_MESSAGES; i++) + case CScorePlayerResult::ALL: + for(int i = 0; i < CScorePlayerResult::MAX_MESSAGES; i++) { if(Result.m_Data.m_aaMessages[i][0] == 0) break; GameServer()->SendChat(-1, CGameContext::CHAT_ALL, Result.m_Data.m_aaMessages[i]); } break; - case CSqlPlayerResult::BROADCAST: + case CScorePlayerResult::BROADCAST: if(Result.m_Data.m_Broadcast[0] != 0) GameServer()->SendBroadcast(Result.m_Data.m_Broadcast, -1); break; - case CSqlPlayerResult::MAP_VOTE: + case CScorePlayerResult::MAP_VOTE: GameServer()->m_VoteKick = false; GameServer()->m_VoteSpec = false; GameServer()->m_LastMapVote = time_get(); @@ -963,7 +954,7 @@ void CPlayer::ProcessSqlResult(CSqlPlayerResult &Result) GameServer()->CallVote(m_ClientID, Result.m_Data.m_MapVote.m_Map, aCmd, "/map", aChatmsg); break; - case CSqlPlayerResult::PLAYER_INFO: + case CScorePlayerResult::PLAYER_INFO: GameServer()->Score()->PlayerData(m_ClientID)->Set( Result.m_Data.m_Info.m_Time, Result.m_Data.m_Info.m_CpTime @@ -993,4 +984,3 @@ void CPlayer::ProcessSqlResult(CSqlPlayerResult &Result) } } } -#endif diff --git a/src/game/server/player.h b/src/game/server/player.h index 513e160d4..48b46dd08 100644 --- a/src/game/server/player.h +++ b/src/game/server/player.h @@ -10,10 +10,6 @@ #include "gamecontext.h" #include -#if defined(CONF_SQL) -class CSqlPlayerResult; -#endif - // player object class CPlayer { @@ -194,12 +190,10 @@ public: int m_DefEmoteReset; bool m_Halloween; bool m_FirstPacket; -#if defined(CONF_SQL) - void ProcessSqlResult(CSqlPlayerResult &Result); int64 m_LastSQLQuery; - std::shared_ptr m_SqlQueryResult; - std::shared_ptr m_SqlFinishResult; -#endif + void ProcessScoreResult(CScorePlayerResult &Result); + std::shared_ptr m_ScoreQueryResult; + std::shared_ptr m_ScoreFinishResult; bool m_NotEligibleForFinish; int64 m_EligibleForFinishCheck; bool m_VotedForPractice; diff --git a/src/game/server/score.cpp b/src/game/server/score.cpp new file mode 100644 index 000000000..39edec3ad --- /dev/null +++ b/src/game/server/score.cpp @@ -0,0 +1,35 @@ +#include "score.h" + +CScorePlayerResult::CScorePlayerResult() : + m_Done(false) +{ + SetVariant(Variant::DIRECT); +} + +void CScorePlayerResult::SetVariant(Variant v) +{ + m_MessageKind = v; + switch(v) + { + case DIRECT: + case ALL: + for(int i = 0; i < MAX_MESSAGES; i++) + m_Data.m_aaMessages[i][0] = 0; + break; + case BROADCAST: + m_Data.m_Broadcast[0] = 0; + break; + case MAP_VOTE: + m_Data.m_MapVote.m_Map[0] = '\0'; + m_Data.m_MapVote.m_Reason[0] = '\0'; + m_Data.m_MapVote.m_Server[0] = '\0'; + break; + case PLAYER_INFO: + m_Data.m_Info.m_Score = -9999; + m_Data.m_Info.m_Birthday = 0; + m_Data.m_Info.m_HasFinishScore = false; + m_Data.m_Info.m_Time = 0; + for(int i = 0; i < NUM_CHECKPOINTS; i++) + m_Data.m_Info.m_CpTime[i] = 0; + } +} diff --git a/src/game/server/score.h b/src/game/server/score.h index 63598fe73..ae1b87087 100644 --- a/src/game/server/score.h +++ b/src/game/server/score.h @@ -4,6 +4,8 @@ #include #include +#include +#include #include "save.h" enum @@ -12,6 +14,94 @@ enum TIMESTAMP_STR_LENGTH = 20, // 2019-04-02 19:38:36 }; +struct CScorePlayerResult +{ + std::atomic_bool m_Done; + CScorePlayerResult(); + + enum { + MAX_MESSAGES = 7, + }; + + enum Variant + { + DIRECT, + ALL, + BROADCAST, + MAP_VOTE, + PLAYER_INFO, + } m_MessageKind; + union { + char m_aaMessages[MAX_MESSAGES][512]; + char m_Broadcast[1024]; + struct { + float m_Time; + float m_CpTime[NUM_CHECKPOINTS]; + int m_Score; + int m_HasFinishScore; + int m_Birthday; // 0 indicates no birthday + } m_Info; + struct + { + char m_Reason[VOTE_REASON_LENGTH]; + char m_Server[32+1]; + char m_Map[MAX_MAP_LENGTH+1]; + } m_MapVote; + } m_Data; // PLAYER_INFO + + void SetVariant(Variant v); +}; + +struct CScoreRandomMapResult +{ + std::atomic_bool m_Done; + CScoreRandomMapResult(int ClientID) : + m_Done(false), + m_ClientID(ClientID) + { + m_Map[0] = '\0'; + m_aMessage[0] = '\0'; + } + int m_ClientID; + char m_Map[MAX_MAP_LENGTH]; + char m_aMessage[512]; +}; + +struct CScoreSaveResult +{ + CScoreSaveResult(int PlayerID, IGameController* Controller) : + m_Status(SAVE_FAILED), + m_SavedTeam(CSaveTeam(Controller)), + m_RequestingPlayer(PlayerID) + { + m_aMessage[0] = '\0'; + m_aBroadcast[0] = '\0'; + } + enum + { + SAVE_SUCCESS, + // load team in the following two cases + SAVE_FAILED, + LOAD_SUCCESS, + LOAD_FAILED, + } m_Status; + char m_aMessage[512]; + char m_aBroadcast[512]; + CSaveTeam m_SavedTeam; + int m_RequestingPlayer; + CUuid m_SaveID; +}; + +struct CScoreInitResult +{ + CScoreInitResult() : + m_Done(false), + m_CurrentRecord(0) + { } + std::atomic_bool m_Done; + float m_CurrentRecord; +}; + class CPlayerData { public: @@ -67,6 +157,9 @@ public: virtual void ShowTopPoints(int ClientID, int Offset=1) = 0; virtual void ShowPoints(int ClientID, const char *pName) = 0; + virtual void ShowTimes(int ClientID, const char *pName, int Offset = 1) = 0; + virtual void ShowTimes(int ClientID, int Offset = 1) = 0; + virtual void RandomMap(int ClientID, int Stars) = 0; virtual void RandomUnfinishedMap(int ClientID, int Stars) = 0; diff --git a/src/game/server/score/file_score.cpp b/src/game/server/score/file_score.cpp index 4b4184c6d..7518ae50c 100644 --- a/src/game/server/score/file_score.cpp +++ b/src/game/server/score/file_score.cpp @@ -317,6 +317,20 @@ void CFileScore::ShowPoints(int ClientID, const char* pName) GameServer()->SendChatTarget(ClientID, aBuf); } +void CFileScore::ShowTimes(int ClientID, const char *pName, int Offset) +{ + char aBuf[512]; + str_format(aBuf, sizeof(aBuf), "Show times not supported in file based servers"); + GameServer()->SendChatTarget(ClientID, aBuf); +} + +void CFileScore::ShowTimes(int ClientID, int Offset) +{ + char aBuf[512]; + str_format(aBuf, sizeof(aBuf), "Show times not supported in file based servers"); + GameServer()->SendChatTarget(ClientID, aBuf); +} + void CFileScore::RandomMap(int ClientID, int Stars) { char aBuf[512]; diff --git a/src/game/server/score/file_score.h b/src/game/server/score/file_score.h index 465d95acb..429cc37b6 100644 --- a/src/game/server/score/file_score.h +++ b/src/game/server/score/file_score.h @@ -75,6 +75,8 @@ public: virtual void ShowTopPoints(int ClientID, int Offset); virtual void ShowPoints(int ClientID, const char* pName); + virtual void ShowTimes(int ClientID, const char *pName, int Offset = 1); + virtual void ShowTimes(int ClientID, int Offset = 1); virtual void RandomMap(int ClientID, int Stars); virtual void RandomUnfinishedMap(int ClientID, int Stars); virtual void SaveTeam(int ClientID, const char* Code, const char* Server); diff --git a/src/game/server/score/sql_score.cpp b/src/game/server/score/sql_score.cpp index 5e7e1c1d1..8a308d7ee 100644 --- a/src/game/server/score/sql_score.cpp +++ b/src/game/server/score/sql_score.cpp @@ -23,40 +23,6 @@ std::atomic_int CSqlScore::ms_InstanceCount(0); -CSqlPlayerResult::CSqlPlayerResult() : - m_Done(false) -{ - SetVariant(Variant::DIRECT); -} - -void CSqlPlayerResult::SetVariant(Variant v) -{ - m_MessageKind = v; - switch(v) - { - case DIRECT: - case ALL: - for(int i = 0; i < MAX_MESSAGES; i++) - m_Data.m_aaMessages[i][0] = 0; - break; - case BROADCAST: - m_Data.m_Broadcast[0] = 0; - break; - case MAP_VOTE: - m_Data.m_MapVote.m_Map[0] = '\0'; - m_Data.m_MapVote.m_Reason[0] = '\0'; - m_Data.m_MapVote.m_Server[0] = '\0'; - break; - case PLAYER_INFO: - m_Data.m_Info.m_Score = -9999; - m_Data.m_Info.m_Birthday = 0; - m_Data.m_Info.m_HasFinishScore = false; - m_Data.m_Info.m_Time = 0; - for(int i = 0; i < NUM_CHECKPOINTS; i++) - m_Data.m_Info.m_CpTime[i] = 0; - } -} - template < typename TResult > CSqlExecData::CSqlExecData( bool (*pFuncPtr) (CSqlServer*, const CSqlData *, bool), @@ -76,17 +42,17 @@ CSqlExecData::~CSqlExecData() --CSqlScore::ms_InstanceCount; } -std::shared_ptr CSqlScore::NewSqlPlayerResult(int ClientID) +std::shared_ptr CSqlScore::NewSqlPlayerResult(int ClientID) { CPlayer *pCurPlayer = GameServer()->m_apPlayers[ClientID]; - if(pCurPlayer->m_SqlQueryResult != nullptr) // TODO: send player a message: "too many requests" + if(pCurPlayer->m_ScoreQueryResult != nullptr) // TODO: send player a message: "too many requests" return nullptr; - pCurPlayer->m_SqlQueryResult = std::make_shared(); - return pCurPlayer->m_SqlQueryResult; + pCurPlayer->m_ScoreQueryResult = std::make_shared(); + return pCurPlayer->m_ScoreQueryResult; } void CSqlScore::ExecPlayerThread( - bool (*pFuncPtr) (CSqlServer*, const CSqlData *, bool), + bool (*pFuncPtr) (CSqlServer*, const CSqlData *, bool), const char* pThreadName, int ClientID, const char* pName, @@ -101,11 +67,22 @@ void CSqlScore::ExecPlayerThread( Tmp->m_RequestingPlayer = Server()->ClientName(ClientID); Tmp->m_Offset = Offset; - thread_init_and_detach(CSqlExecData::ExecSqlFunc, - new CSqlExecData(pFuncPtr, Tmp), + thread_init_and_detach(CSqlExecData::ExecSqlFunc, + new CSqlExecData(pFuncPtr, Tmp), pThreadName); } +bool CSqlScore::RateLimitPlayer(int ClientID) +{ + CPlayer *pPlayer = GameServer()->m_apPlayers[ClientID]; + if(pPlayer == 0) + return true; + if(pPlayer->m_LastSQLQuery + g_Config.m_SvSqlQueriesDelay * Server()->TickSpeed() >= Server()->Tick()) + return true; + pPlayer->m_LastSQLQuery = Server()->Tick(); + return false; +} + void CSqlScore::GeneratePassphrase(char *pBuf, int BufSize) { for(int i = 0; i < 3; i++) @@ -182,7 +159,7 @@ CSqlScore::CSqlScore(CGameContext *pGameServer) : { CSqlConnector::ResetReachable(); - auto InitResult = std::make_shared(); + auto InitResult = std::make_shared(); CSqlInitData *Tmp = new CSqlInitData(InitResult); ((CGameControllerDDRace*)(pGameServer->m_pController))->m_pInitResult = InitResult; Tmp->m_Map = g_Config.m_SvMap; @@ -214,12 +191,12 @@ CSqlScore::CSqlScore(CGameContext *pGameServer) : Server()->SetErrorShutdown("sql too few words in wordlist"); return; } - thread_init_and_detach(CSqlExecData::ExecSqlFunc, - new CSqlExecData(Init, Tmp), + thread_init_and_detach(CSqlExecData::ExecSqlFunc, + new CSqlExecData(Init, Tmp), "SqlScore constructor"); } -bool CSqlScore::Init(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure) +bool CSqlScore::Init(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure) { const CSqlInitData *pData = dynamic_cast(pGameData); @@ -258,10 +235,10 @@ void CSqlScore::LoadPlayerData(int ClientID) } // update stuff -bool CSqlScore::LoadPlayerDataThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure) +bool CSqlScore::LoadPlayerDataThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure) { const CSqlPlayerRequest *pData = dynamic_cast(pGameData); - pData->m_pResult->SetVariant(CSqlPlayerResult::PLAYER_INFO); + pData->m_pResult->SetVariant(CScorePlayerResult::PLAYER_INFO); if (HandleFailure) return true; @@ -329,10 +306,12 @@ bool CSqlScore::LoadPlayerDataThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure) +bool CSqlScore::MapVoteThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure) { const CSqlPlayerRequest *pData = dynamic_cast(pGameData); auto paMessages = pData->m_pResult->m_Data.m_aaMessages; @@ -374,7 +353,7 @@ bool CSqlScore::MapVoteThread(CSqlServer* pSqlServer, const CSqlDataGetResults()->first(); auto Server = pSqlServer->GetResults()->getString("Server"); auto Map = pSqlServer->GetResults()->getString("Map"); - pData->m_pResult->SetVariant(CSqlPlayerResult::MAP_VOTE); + pData->m_pResult->SetVariant(CScorePlayerResult::MAP_VOTE); auto MapVote = &pData->m_pResult->m_Data.m_MapVote; strcpy(MapVote->m_Reason, "/map"); str_copy(MapVote->m_Server, Server.c_str(), sizeof(MapVote->m_Server)); @@ -396,10 +375,12 @@ bool CSqlScore::MapVoteThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure) +bool CSqlScore::MapInfoThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure) { const CSqlPlayerRequest *pData = dynamic_cast(pGameData); @@ -527,10 +508,10 @@ void CSqlScore::SaveScore(int ClientID, float Time, const char *pTimestamp, floa return; CPlayer *pCurPlayer = GameServer()->m_apPlayers[ClientID]; - if(pCurPlayer->m_SqlFinishResult != nullptr) + if(pCurPlayer->m_ScoreFinishResult != nullptr) dbg_msg("sql", "WARNING: previous save score result didn't complete, overwriting it now"); - pCurPlayer->m_SqlFinishResult = std::make_shared(); - CSqlScoreData *Tmp = new CSqlScoreData(pCurPlayer->m_SqlFinishResult); + pCurPlayer->m_ScoreFinishResult = std::make_shared(); + CSqlScoreData *Tmp = new CSqlScoreData(pCurPlayer->m_ScoreFinishResult); Tmp->m_Map = g_Config.m_SvMap; FormatUuid(GameServer()->GameUuid(), Tmp->m_GameUuid, sizeof(Tmp->m_GameUuid)); Tmp->m_ClientID = ClientID; @@ -540,12 +521,12 @@ void CSqlScore::SaveScore(int ClientID, float Time, const char *pTimestamp, floa for(int i = 0; i < NUM_CHECKPOINTS; i++) Tmp->m_aCpCurrent[i] = CpTime[i]; - thread_init_and_detach(CSqlExecData::ExecSqlFunc, - new CSqlExecData(SaveScoreThread, Tmp), + thread_init_and_detach(CSqlExecData::ExecSqlFunc, + new CSqlExecData(SaveScoreThread, Tmp), "save score"); } -bool CSqlScore::SaveScoreThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure) +bool CSqlScore::SaveScoreThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure) { const CSqlScoreData *pData = dynamic_cast(pGameData); auto paMessages = pData->m_pResult->m_Data.m_aaMessages; @@ -593,7 +574,7 @@ bool CSqlScore::SaveScoreThread(CSqlServer* pSqlServer, const CSqlDatam_pResult->SetVariant(CSqlPlayerResult::BROADCAST); + pData->m_pResult->SetVariant(CScorePlayerResult::BROADCAST); strcpy(pData->m_pResult->m_Data.m_Broadcast, "Database connection failed, score written to a file instead. Admins will add it manually in a few days."); pData->m_pResult->m_Done = true; @@ -802,10 +783,12 @@ bool CSqlScore::SaveTeamScoreThread(CSqlServer* pSqlServer, const CSqlData void CSqlScore::ShowRank(int ClientID, const char* pName) { + if(RateLimitPlayer(ClientID)) + return; ExecPlayerThread(ShowRankThread, "show rank", ClientID, pName, 0); } -bool CSqlScore::ShowRankThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure) +bool CSqlScore::ShowRankThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure) { const CSqlPlayerRequest *pData = dynamic_cast(pGameData); if (HandleFailure) @@ -854,7 +837,7 @@ bool CSqlScore::ShowRankThread(CSqlServer* pSqlServer, const CSqlDatam_pResult->m_MessageKind = CSqlPlayerResult::ALL; + pData->m_pResult->m_MessageKind = CScorePlayerResult::ALL; str_format(pData->m_pResult->m_Data.m_aaMessages[0], sizeof(pData->m_pResult->m_Data.m_aaMessages[0]), "%d. %s Time: %02d:%05.2f, requested by %s", Rank, pSqlServer->GetResults()->getString("Name").c_str(), @@ -876,10 +859,12 @@ bool CSqlScore::ShowRankThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure) +bool CSqlScore::ShowTeamRankThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure) { const CSqlPlayerRequest *pData = dynamic_cast(pGameData); if (HandleFailure) @@ -954,7 +939,7 @@ bool CSqlScore::ShowTeamRankThread(CSqlServer* pSqlServer, const CSqlDatam_pResult->m_MessageKind = CSqlPlayerResult::ALL; + pData->m_pResult->m_MessageKind = CScorePlayerResult::ALL; str_format(pData->m_pResult->m_Data.m_aaMessages[0], sizeof(pData->m_pResult->m_Data.m_aaMessages[0]), "%d. %s Team time: %02d:%05.02f, requested by %s", Rank, aNames, (int)(Time/60), Time-((int)Time/60*60), pData->m_RequestingPlayer.Str()); @@ -975,10 +960,12 @@ bool CSqlScore::ShowTeamRankThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure) +bool CSqlScore::ShowTop5Thread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure) { const CSqlPlayerRequest *pData = dynamic_cast(pGameData); if (HandleFailure) @@ -1041,10 +1028,12 @@ bool CSqlScore::ShowTop5Thread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure) +bool CSqlScore::ShowTeamTop5Thread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure) { const CSqlPlayerRequest *pData = dynamic_cast(pGameData); auto paMessages = pData->m_pResult->m_Data.m_aaMessages; @@ -1129,15 +1118,19 @@ bool CSqlScore::ShowTeamTop5Thread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure) +bool CSqlScore::ShowTimesThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure) { const CSqlPlayerRequest *pData = dynamic_cast(pGameData); auto paMessages = pData->m_pResult->m_Data.m_aaMessages; @@ -1238,10 +1231,12 @@ bool CSqlScore::ShowTimesThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure) +bool CSqlScore::ShowPointsThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure) { const CSqlPlayerRequest *pData = dynamic_cast(pGameData); auto paMessages = pData->m_pResult->m_Data.m_aaMessages; @@ -1275,7 +1270,7 @@ bool CSqlScore::ShowPointsThread(CSqlServer* pSqlServer, const CSqlDataGetResults()->getInt("Points"); int Rank = pSqlServer->GetResults()->getInt("Rank"); auto Name = pSqlServer->GetResults()->getString("Name"); - pData->m_pResult->m_MessageKind = CSqlPlayerResult::ALL; + pData->m_pResult->m_MessageKind = CScorePlayerResult::ALL; str_format(paMessages[0], sizeof(paMessages[0]), "%d. %s Points: %d, requested by %s", Rank, Name.c_str(), Count, pData->m_RequestingPlayer.Str()); @@ -1295,10 +1290,12 @@ bool CSqlScore::ShowPointsThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure) +bool CSqlScore::ShowTopPointsThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure) { const CSqlPlayerRequest *pData = dynamic_cast(pGameData); auto paMessages = pData->m_pResult->m_Data.m_aaMessages; @@ -1355,7 +1352,7 @@ bool CSqlScore::ShowTopPointsThread(CSqlServer* pSqlServer, const CSqlData(ClientID); + auto pResult = std::make_shared(ClientID); GameServer()->m_SqlRandomMapResult = pResult; auto *Tmp = new CSqlRandomMapRequest(pResult); @@ -1365,12 +1362,12 @@ void CSqlScore::RandomMap(int ClientID, int Stars) Tmp->m_RequestingPlayer = GameServer()->Server()->ClientName(ClientID); thread_init_and_detach( - CSqlExecData::ExecSqlFunc, - new CSqlExecData(RandomMapThread, Tmp), + CSqlExecData::ExecSqlFunc, + new CSqlExecData(RandomMapThread, Tmp), "random map"); } -bool CSqlScore::RandomMapThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure) +bool CSqlScore::RandomMapThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure) { const CSqlRandomMapRequest *pData = dynamic_cast(pGameData); @@ -1430,7 +1427,7 @@ bool CSqlScore::RandomMapThread(CSqlServer* pSqlServer, const CSqlData(ClientID); + auto pResult = std::make_shared(ClientID); GameServer()->m_SqlRandomMapResult = pResult; auto *Tmp = new CSqlRandomMapRequest(pResult); @@ -1440,12 +1437,12 @@ void CSqlScore::RandomUnfinishedMap(int ClientID, int Stars) Tmp->m_RequestingPlayer = GameServer()->Server()->ClientName(ClientID); thread_init_and_detach( - CSqlExecData::ExecSqlFunc, - new CSqlExecData(RandomUnfinishedMapThread, Tmp), + CSqlExecData::ExecSqlFunc, + new CSqlExecData(RandomUnfinishedMapThread, Tmp), "random unfinished map"); } -bool CSqlScore::RandomUnfinishedMapThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure) +bool CSqlScore::RandomUnfinishedMapThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure) { const CSqlRandomMapRequest *pData = dynamic_cast(pGameData); @@ -1510,12 +1507,14 @@ bool CSqlScore::RandomUnfinishedMapThread(CSqlServer* pSqlServer, const CSqlData void CSqlScore::SaveTeam(int ClientID, const char* Code, const char* Server) { + if(RateLimitPlayer(ClientID)) + return; auto pController = ((CGameControllerDDRace*)(GameServer()->m_pController)); int Team = pController->m_Teams.m_Core.Team(ClientID); if(pController->m_Teams.GetSaving(Team)) return; - auto SaveResult = std::make_shared(ClientID, pController); + auto SaveResult = std::make_shared(ClientID, pController); int Result = SaveResult->m_SavedTeam.save(Team); if(CSaveTeam::HandleSaveError(Result, ClientID, GameServer())) return; @@ -1532,12 +1531,12 @@ void CSqlScore::SaveTeam(int ClientID, const char* Code, const char* Server) pController->m_Teams.KillSavedTeam(ClientID, Team); thread_init_and_detach( - CSqlExecData::ExecSqlFunc, - new CSqlExecData(SaveTeamThread, Tmp, false), + CSqlExecData::ExecSqlFunc, + new CSqlExecData(SaveTeamThread, Tmp, false), "save team"); } -bool CSqlScore::SaveTeamThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure) +bool CSqlScore::SaveTeamThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure) { const CSqlTeamSave *pData = dynamic_cast(pGameData); @@ -1571,7 +1570,7 @@ bool CSqlScore::SaveTeamThread(CSqlServer* pSqlServer, const CSqlDatam_pResult->m_Status = CSqlSaveResult::SAVE_SUCCESS; + pData->m_pResult->m_Status = CScoreSaveResult::SAVE_SUCCESS; strcpy(pData->m_pResult->m_aBroadcast, "Database connection failed, teamsave written to a file instead. Admins will add it manually in a few days."); str_format(pData->m_pResult->m_aMessage, sizeof(pData->m_pResult->m_aMessage), @@ -1647,18 +1646,18 @@ bool CSqlScore::SaveTeamThread(CSqlServer* pSqlServer, const CSqlDatam_ClientName, Code, pData->m_Server); } - pData->m_pResult->m_Status = CSqlSaveResult::SAVE_SUCCESS; + pData->m_pResult->m_Status = CScoreSaveResult::SAVE_SUCCESS; } else { dbg_msg("sql", "ERROR: This save-code already exists"); - pData->m_pResult->m_Status = CSqlSaveResult::SAVE_FAILED; + pData->m_pResult->m_Status = CScoreSaveResult::SAVE_FAILED; strcpy(pData->m_pResult->m_aMessage, "This save-code already exists"); } } catch (sql::SQLException &e) { - pData->m_pResult->m_Status = CSqlSaveResult::SAVE_FAILED; + pData->m_pResult->m_Status = CScoreSaveResult::SAVE_FAILED; dbg_msg("sql", "MySQL Error: %s", e.what()); dbg_msg("sql", "ERROR: Could not save the team"); @@ -1673,6 +1672,8 @@ bool CSqlScore::SaveTeamThread(CSqlServer* pSqlServer, const CSqlDatam_pController)); int Team = pController->m_Teams.m_Core.Team(ClientID); if(pController->m_Teams.GetSaving(Team)) @@ -1687,7 +1688,7 @@ void CSqlScore::LoadTeam(const char* Code, int ClientID) GameServer()->SendChatTarget(ClientID, "Team can't be loaded while racing"); return; } - auto SaveResult = std::make_shared(ClientID, pController); + auto SaveResult = std::make_shared(ClientID, pController); pController->m_Teams.SetSaving(Team, SaveResult); CSqlTeamLoad *Tmp = new CSqlTeamLoad(SaveResult); Tmp->m_Code = Code; @@ -1706,15 +1707,15 @@ void CSqlScore::LoadTeam(const char* Code, int ClientID) } } thread_init_and_detach( - CSqlExecData::ExecSqlFunc, - new CSqlExecData(LoadTeamThread, Tmp, false), + CSqlExecData::ExecSqlFunc, + new CSqlExecData(LoadTeamThread, Tmp, false), "load team"); } -bool CSqlScore::LoadTeamThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure) +bool CSqlScore::LoadTeamThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure) { const CSqlTeamLoad *pData = dynamic_cast(pGameData); - pData->m_pResult->m_Status = CSqlSaveResult::LOAD_FAILED; + pData->m_pResult->m_Status = CScoreSaveResult::LOAD_FAILED; if (HandleFailure) return true; @@ -1793,7 +1794,7 @@ bool CSqlScore::LoadTeamThread(CSqlServer* pSqlServer, const CSqlDataGetPrefix(), pData->m_Code.ClrStr(), pData->m_Map.ClrStr()); pSqlServer->executeSql(aBuf); - pData->m_pResult->m_Status = CSqlSaveResult::LOAD_SUCCESS; + pData->m_pResult->m_Status = CScoreSaveResult::LOAD_SUCCESS; strcpy(pData->m_pResult->m_aMessage, "Loading successfully done"); } @@ -1814,10 +1815,12 @@ end: void CSqlScore::GetSaves(int ClientID) { + if(RateLimitPlayer(ClientID)) + return; ExecPlayerThread(GetSavesThread, "get saves", ClientID, "", 0); } -bool CSqlScore::GetSavesThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure) +bool CSqlScore::GetSavesThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure) { const CSqlPlayerRequest *pData = dynamic_cast(pGameData); auto paMessages = pData->m_pResult->m_Data.m_aaMessages; diff --git a/src/game/server/score/sql_score.h b/src/game/server/score/sql_score.h index 11ef3f8e5..e72e08f53 100644 --- a/src/game/server/score/sql_score.h +++ b/src/game/server/score/sql_score.h @@ -10,100 +10,11 @@ #include #include #include -#include #include "../score.h" class CSqlServer; -struct CSqlPlayerResult -{ - std::atomic_bool m_Done; - CSqlPlayerResult(); - - enum { - MAX_MESSAGES = 7, - }; - - enum Variant - { - DIRECT, - ALL, - BROADCAST, - MAP_VOTE, - PLAYER_INFO, - } m_MessageKind; - union { - char m_aaMessages[MAX_MESSAGES][512]; - char m_Broadcast[1024]; - struct { - float m_Time; - float m_CpTime[NUM_CHECKPOINTS]; - int m_Score; - int m_HasFinishScore; - int m_Birthday; // 0 indicates no birthday - } m_Info; - struct - { - char m_Reason[VOTE_REASON_LENGTH]; - char m_Server[32+1]; - char m_Map[MAX_MAP_LENGTH+1]; - } m_MapVote; - } m_Data; // PLAYER_INFO - - void SetVariant(Variant v); -}; - -struct CSqlRandomMapResult -{ - std::atomic_bool m_Done; - CSqlRandomMapResult(int ClientID) : - m_Done(false), - m_ClientID(ClientID) - { - m_Map[0] = '\0'; - m_aMessage[0] = '\0'; - } - int m_ClientID; - char m_Map[MAX_MAP_LENGTH]; - char m_aMessage[512]; -}; - -struct CSqlSaveResult -{ - CSqlSaveResult(int PlayerID, IGameController* Controller) : - m_Status(SAVE_FAILED), - m_SavedTeam(CSaveTeam(Controller)), - m_RequestingPlayer(PlayerID) - { - m_aMessage[0] = '\0'; - m_aBroadcast[0] = '\0'; - } - enum - { - SAVE_SUCCESS, - // load team in the following two cases - SAVE_FAILED, - LOAD_SUCCESS, - LOAD_FAILED, - } m_Status; - char m_aMessage[512]; - char m_aBroadcast[512]; - CSaveTeam m_SavedTeam; - int m_RequestingPlayer; - CUuid m_SaveID; -}; - -struct CSqlInitResult -{ - CSqlInitResult() : - m_Done(false), - m_CurrentRecord(0) - { } - std::atomic_bool m_Done; - float m_CurrentRecord; -}; - // holding relevant data for one thread, and function pointer for return values template < typename TResult > struct CSqlData @@ -115,16 +26,16 @@ struct CSqlData virtual ~CSqlData() = default; }; -struct CSqlInitData : CSqlData +struct CSqlInitData : CSqlData { - using CSqlData::CSqlData; + using CSqlData::CSqlData; // current map sqlstr::CSqlString m_Map; }; -struct CSqlPlayerRequest : CSqlData +struct CSqlPlayerRequest : CSqlData { - using CSqlData::CSqlData; + using CSqlData::CSqlData; // object being requested, either map (128 bytes) or player (16 bytes) sqlstr::CSqlString m_Name; // current map @@ -134,18 +45,18 @@ struct CSqlPlayerRequest : CSqlData int m_Offset; }; -struct CSqlRandomMapRequest : CSqlData +struct CSqlRandomMapRequest : CSqlData { - using CSqlData::CSqlData; + using CSqlData::CSqlData; sqlstr::CSqlString<32> m_ServerType; sqlstr::CSqlString m_CurrentMap; sqlstr::CSqlString m_RequestingPlayer; int m_Stars; }; -struct CSqlScoreData : CSqlData +struct CSqlScoreData : CSqlData { - using CSqlData::CSqlData; + using CSqlData::CSqlData; sqlstr::CSqlString m_Map; char m_GameUuid[UUID_MAXSTRSIZE]; @@ -171,9 +82,9 @@ struct CSqlTeamScoreData : CSqlData sqlstr::CSqlString m_aNames[MAX_CLIENTS]; }; -struct CSqlTeamSave : CSqlData +struct CSqlTeamSave : CSqlData { - using CSqlData::CSqlData; + using CSqlData::CSqlData; virtual ~CSqlTeamSave() {}; char m_ClientName[MAX_NAME_LENGTH]; @@ -184,9 +95,9 @@ struct CSqlTeamSave : CSqlData char m_Server[5]; }; -struct CSqlTeamLoad : CSqlData +struct CSqlTeamLoad : CSqlData { - using CSqlData::CSqlData; + using CSqlData::CSqlData; sqlstr::CSqlString<128> m_Code; sqlstr::CSqlString m_Map; sqlstr::CSqlString m_RequestingPlayer; @@ -222,27 +133,27 @@ class CSqlScore: public IScore { static LOCK ms_FailureFileLock; - static bool Init(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure); + static bool Init(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure); - static bool RandomMapThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure = false); - static bool RandomUnfinishedMapThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure = false); - static bool MapVoteThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure = false); + static bool RandomMapThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure = false); + static bool RandomUnfinishedMapThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure = false); + static bool MapVoteThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure = false); - static bool LoadPlayerDataThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure = false); - static bool MapInfoThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure = false); - static bool ShowRankThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure = false); - static bool ShowTeamRankThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure = false); - static bool ShowTop5Thread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure = false); - static bool ShowTeamTop5Thread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure = false); - static bool ShowTimesThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure = false); - static bool ShowPointsThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure = false); - static bool ShowTopPointsThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure = false); - static bool GetSavesThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure = false); + static bool LoadPlayerDataThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure = false); + static bool MapInfoThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure = false); + static bool ShowRankThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure = false); + static bool ShowTeamRankThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure = false); + static bool ShowTop5Thread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure = false); + static bool ShowTeamTop5Thread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure = false); + static bool ShowTimesThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure = false); + static bool ShowPointsThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure = false); + static bool ShowTopPointsThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure = false); + static bool GetSavesThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure = false); - static bool SaveTeamThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure = false); - static bool LoadTeamThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure = false); + static bool SaveTeamThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure = false); + static bool LoadTeamThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure = false); - static bool SaveScoreThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure = false); + static bool SaveScoreThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure = false); static bool SaveTeamScoreThread(CSqlServer* pSqlServer, const CSqlData *pGameData, bool HandleFailure = false); CGameContext *GameServer() { return m_pGameServer; } @@ -256,16 +167,19 @@ class CSqlScore: public IScore void GeneratePassphrase(char *pBuf, int BufSize); // returns new SqlResult bound to the player, if no current Thread is active for this player - std::shared_ptr NewSqlPlayerResult(int ClientID); + std::shared_ptr NewSqlPlayerResult(int ClientID); // Creates for player database requests void ExecPlayerThread( - bool (*pFuncPtr) (CSqlServer*, const CSqlData *, bool), + bool (*pFuncPtr) (CSqlServer*, const CSqlData *, bool), const char* pThreadName, int ClientID, const char* pName, int Offset ); + // returns true if the player should be rate limited + bool RateLimitPlayer(int ClientID); + public: // keeps track of score-threads static std::atomic_int ms_InstanceCount; diff --git a/src/game/server/teams.cpp b/src/game/server/teams.cpp index eeb3f9748..ac4250e98 100644 --- a/src/game/server/teams.cpp +++ b/src/game/server/teams.cpp @@ -2,9 +2,6 @@ #include "teams.h" #include "score.h" #include -#if defined(CONF_SQL) -#include "score/sql_score.h" -#endif CGameTeams::CGameTeams(CGameContext *pGameContext) : m_pGameContext(pGameContext) @@ -23,9 +20,7 @@ void CGameTeams::Reset() m_TeamLocked[i] = false; m_Invited[i] = 0; m_Practice[i] = false; -#if defined(CONF_SQL) m_pSaveTeamResult[i] = nullptr; -#endif } } @@ -511,12 +506,6 @@ float *CGameTeams::GetCpCurrent(CPlayer* Player) void CGameTeams::OnTeamFinish(CPlayer** Players, unsigned int Size, float Time, const char *pTimestamp) { - bool CallSaveScore = false; - -#if defined(CONF_SQL) - CallSaveScore = g_Config.m_SvUseSQL; -#endif - int PlayerCIDs[MAX_CLIENTS]; for(unsigned int i = 0; i < Size; i++) @@ -533,7 +522,7 @@ void CGameTeams::OnTeamFinish(CPlayer** Players, unsigned int Size, float Time, } } - if (CallSaveScore && Size >= 2) + if (Size >= 2) GameServer()->Score()->SaveTeamScore(PlayerCIDs, Size, Time, pTimestamp); } @@ -600,10 +589,7 @@ void CGameTeams::OnFinish(CPlayer* Player, float Time, const char *pTimestamp) Server()->SaveDemo(ClientID, Time); } - bool CallSaveScore = false; -#if defined(CONF_SQL) - CallSaveScore = g_Config.m_SvUseSQL && g_Config.m_SvSaveWorseScores; -#endif + bool CallSaveScore = g_Config.m_SvSaveWorseScores; if (!pData->m_BestTime || Time < pData->m_BestTime) { @@ -685,7 +671,6 @@ void CGameTeams::OnFinish(CPlayer* Player, float Time, const char *pTimestamp) } } -#if defined(CONF_SQL) void CGameTeams::ProcessSaveTeam() { for(int Team = 0; Team < MAX_CLIENTS; Team++) @@ -694,12 +679,12 @@ void CGameTeams::ProcessSaveTeam() continue; if(m_pSaveTeamResult[Team]->m_aBroadcast[0] != '\0') GameServer()->SendBroadcast(m_pSaveTeamResult[Team]->m_aBroadcast, -1); - if(m_pSaveTeamResult[Team]->m_aMessage[0] != '\0' && m_pSaveTeamResult[Team]->m_Status != CSqlSaveResult::LOAD_FAILED) + if(m_pSaveTeamResult[Team]->m_aMessage[0] != '\0' && m_pSaveTeamResult[Team]->m_Status != CScoreSaveResult::LOAD_FAILED) GameServer()->SendChatTeam(Team, m_pSaveTeamResult[Team]->m_aMessage); // TODO: log load/save success/fail in teehistorian switch(m_pSaveTeamResult[Team]->m_Status) { - case CSqlSaveResult::SAVE_SUCCESS: + case CScoreSaveResult::SAVE_SUCCESS: { ResetSavedTeam(m_pSaveTeamResult[Team]->m_RequestingPlayer, Team); char aSaveID[UUID_MAXSTRSIZE]; @@ -707,11 +692,11 @@ void CGameTeams::ProcessSaveTeam() dbg_msg("save", "Save successful: %s", aSaveID); break; } - case CSqlSaveResult::SAVE_FAILED: + case CScoreSaveResult::SAVE_FAILED: if(Count(Team) > 0) m_pSaveTeamResult[Team]->m_SavedTeam.load(Team); break; - case CSqlSaveResult::LOAD_SUCCESS: + case CScoreSaveResult::LOAD_SUCCESS: { if(Count(Team) > 0) m_pSaveTeamResult[Team]->m_SavedTeam.load(Team); @@ -720,7 +705,7 @@ void CGameTeams::ProcessSaveTeam() dbg_msg("save", "Load successful: %s", aSaveID); break; } - case CSqlSaveResult::LOAD_FAILED: + case CScoreSaveResult::LOAD_FAILED: if(m_pSaveTeamResult[Team]->m_aMessage[0] != '\0') GameServer()->SendChatTarget(m_pSaveTeamResult[Team]->m_RequestingPlayer, m_pSaveTeamResult[Team]->m_aMessage); break; @@ -728,7 +713,6 @@ void CGameTeams::ProcessSaveTeam() m_pSaveTeamResult[Team] = nullptr; } } -#endif void CGameTeams::OnCharacterSpawn(int ClientID) { @@ -812,7 +796,6 @@ void CGameTeams::SetClientInvited(int Team, int ClientID, bool Invited) } } -#if defined(CONF_SQL) void CGameTeams::KillSavedTeam(int ClientID, int Team) { for(int i = 0; i < MAX_CLIENTS; i++) @@ -835,4 +818,3 @@ void CGameTeams::ResetSavedTeam(int ClientID, int Team) } } } -#endif diff --git a/src/game/server/teams.h b/src/game/server/teams.h index 80b0b3202..0f584ae56 100644 --- a/src/game/server/teams.h +++ b/src/game/server/teams.h @@ -5,10 +5,6 @@ #include #include -#if defined(CONF_SQL) -class CSqlSaveResult; -#endif - class CGameTeams { int m_TeamState[MAX_CLIENTS]; @@ -16,9 +12,7 @@ class CGameTeams bool m_TeamLocked[MAX_CLIENTS]; uint64_t m_Invited[MAX_CLIENTS]; bool m_Practice[MAX_CLIENTS]; -#if defined(CONF_SQL) - std::shared_ptr m_pSaveTeamResult[MAX_CLIENTS]; -#endif + std::shared_ptr m_pSaveTeamResult[MAX_CLIENTS]; class CGameContext * m_pGameContext; @@ -90,11 +84,9 @@ public: void SetDDRaceState(CPlayer* Player, int DDRaceState); void SetStartTime(CPlayer* Player, int StartTime); void SetCpActive(CPlayer* Player, int CpActive); -#if defined(CONF_SQL) void KillSavedTeam(int ClientID, int Team); void ResetSavedTeam(int ClientID, int Team); void ProcessSaveTeam(); -#endif bool TeeFinished(int ClientID) { @@ -123,20 +115,15 @@ public: { m_TeeFinished[ClientID] = finished; } -#if defined(CONF_SQL) - void SetSaving(int TeamID, std::shared_ptr SaveResult) + + void SetSaving(int TeamID, std::shared_ptr SaveResult) { m_pSaveTeamResult[TeamID] = SaveResult; } -#endif bool GetSaving(int TeamID) { -#if defined(CONF_SQL) return m_pSaveTeamResult[TeamID] != nullptr; -#else - return false; -#endif } void EnablePractice(int Team)