diff --git a/src/game/server/ddracechat.cpp b/src/game/server/ddracechat.cpp index f3696ca59..0fe0ba148 100644 --- a/src/game/server/ddracechat.cpp +++ b/src/game/server/ddracechat.cpp @@ -377,6 +377,37 @@ void CGameContext::ConToggleSpec(IConsole::IResult *pResult, void *pUserData) pPlayer->m_Paused = (pPlayer->m_Paused == CPlayer::PAUSED_SPEC) ? CPlayer::PAUSED_NONE : CPlayer::PAUSED_SPEC; } +void CGameContext::ConTeamTop5(IConsole::IResult *pResult, void *pUserData) +{ + CGameContext *pSelf = (CGameContext *) 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 + pSelf->Server()->TickSpeed() >= pSelf->Server()->Tick()) + return; +#endif + + if (g_Config.m_SvHideScore) + { + pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "teamtop5", + "Showing the team top 5 is not allowed on this server."); + return; + } + + if (pResult->NumArguments() > 0 && pResult->GetInteger(0) >= 0) + pSelf->Score()->ShowTeamTop5(pResult, pResult->m_ClientID, pUserData, + pResult->GetInteger(0)); + else + pSelf->Score()->ShowTeamTop5(pResult, pResult->m_ClientID, pUserData); + +#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) { CGameContext *pSelf = (CGameContext *) pUserData; @@ -462,6 +493,41 @@ void CGameContext::ConTimes(IConsole::IResult *pResult, void *pUserData) } #endif +void CGameContext::ConTeamRank(IConsole::IResult *pResult, void *pUserData) +{ + CGameContext *pSelf = (CGameContext *) 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 + pSelf->Server()->TickSpeed() >= pSelf->Server()->Tick()) + return; +#endif + + CPlayer *pPlayer = pSelf->m_apPlayers[pResult->m_ClientID]; + if (!pPlayer) + return; + + if (pResult->NumArguments() > 0) + if (!g_Config.m_SvHideScore) + pSelf->Score()->ShowTeamRank(pResult->m_ClientID, pResult->GetString(0), + true); + else + pSelf->Console()->Print( + 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(pSelf->m_apPlayers[pResult->m_ClientID] && g_Config.m_SvUseSQL) + pSelf->m_apPlayers[pResult->m_ClientID]->m_LastSQLQuery = pSelf->Server()->Tick(); +#endif +} + void CGameContext::ConRank(IConsole::IResult *pResult, void *pUserData) { CGameContext *pSelf = (CGameContext *) pUserData; diff --git a/src/game/server/ddracechat.h b/src/game/server/ddracechat.h index 0fc796667..364bb49e0 100644 --- a/src/game/server/ddracechat.h +++ b/src/game/server/ddracechat.h @@ -15,9 +15,11 @@ CHAT_COMMAND("info", "", CFGFLAG_CHAT|CFGFLAG_SERVER, ConInfo, this, "Shows info CHAT_COMMAND("me", "r", CFGFLAG_CHAT|CFGFLAG_SERVER, ConMe, this, "Like the famous irc command '/me says hi' will display ' says hi'") CHAT_COMMAND("pause", "", CFGFLAG_CHAT|CFGFLAG_SERVER, ConTogglePause, this, "Toggles pause (if not activated on the server, it toggles spec)") CHAT_COMMAND("spec", "", CFGFLAG_CHAT|CFGFLAG_SERVER, ConToggleSpec, this, "Toggles spec") +CHAT_COMMAND("teamrank", "?r", CFGFLAG_CHAT|CFGFLAG_SERVER, ConTeamRank, this, "Shows the team rank of player with name r (your team rank by default)") CHAT_COMMAND("rank", "?r", CFGFLAG_CHAT|CFGFLAG_SERVER, ConRank, this, "Shows the rank of player with name r (your rank by default)") CHAT_COMMAND("rules", "", CFGFLAG_CHAT|CFGFLAG_SERVER, ConRules, this, "Shows the server rules") CHAT_COMMAND("team", "?i", CFGFLAG_CHAT|CFGFLAG_SERVER, ConJoinTeam, this, "Lets you join team i (shows your team if left blank)") +CHAT_COMMAND("teamtop5", "?i", CFGFLAG_CHAT|CFGFLAG_SERVER, ConTeamTop5, this, "Shows five team ranks of the ladder beginning with rank i (1 by default)") CHAT_COMMAND("top5", "?i", CFGFLAG_CHAT|CFGFLAG_SERVER, ConTop5, this, "Shows five ranks of the ladder beginning with rank i (1 by default)") CHAT_COMMAND("showothers", "?i", CFGFLAG_CHAT|CFGFLAG_SERVER, ConShowOthers, this, "Whether to showplayers from other teams or not (off by default), optional i = 0 for off else for on") CHAT_COMMAND("saytime", "", CFGFLAG_CHAT|CFGFLAG_SERVER, ConSayTime, this, "Privately messages you your current time in this current running race") diff --git a/src/game/server/gamecontext.h b/src/game/server/gamecontext.h index c51acb281..0974ad0a7 100644 --- a/src/game/server/gamecontext.h +++ b/src/game/server/gamecontext.h @@ -226,6 +226,7 @@ private: static void ConTogglePause(IConsole::IResult *pResult, void *pUserData); static void ConToggleSpec(IConsole::IResult *pResult, void *pUserData); static void ConForcePause(IConsole::IResult *pResult, void *pUserData); + static void ConTeamTop5(IConsole::IResult *pResult, void *pUserData); static void ConTop5(IConsole::IResult *pResult, void *pUserData); #if defined(CONF_SQL) static void ConTimes(IConsole::IResult *pResult, void *pUserData); @@ -234,6 +235,7 @@ private: #endif static void ConUTF8(IConsole::IResult *pResult, void *pUserData); + static void ConTeamRank(IConsole::IResult *pResult, void *pUserData); static void ConRank(IConsole::IResult *pResult, void *pUserData); static void ConBroadTime(IConsole::IResult *pResult, void *pUserData); static void ConJoinTeam(IConsole::IResult *pResult, void *pUserData); diff --git a/src/game/server/score.h b/src/game/server/score.h index 2ab21a7c9..b08f7c8fe 100644 --- a/src/game/server/score.h +++ b/src/game/server/score.h @@ -45,10 +45,15 @@ public: virtual void LoadScore(int ClientID) = 0; virtual void SaveScore(int ClientID, float Time, float CpTime[NUM_CHECKPOINTS]) = 0; + + virtual void SaveTeamScore(int* ClientIDs, unsigned int Size, float Time) = 0; virtual void ShowTop5(IConsole::IResult *pResult, int ClientID, void *pUserData, int Debut=1) = 0; virtual void ShowRank(int ClientID, const char* pName, bool Search=false) = 0; + virtual void ShowTeamTop5(IConsole::IResult *pResult, int ClientID, void *pUserData, int Debut=1) = 0; + virtual void ShowTeamRank(int ClientID, const char* pName, bool Search=false) = 0; + virtual void ShowTopPoints(IConsole::IResult *pResult, int ClientID, void *pUserData, int Debut=1) = 0; virtual void ShowPoints(int ClientID, const char* pName, bool Search=false) = 0; }; diff --git a/src/game/server/score/file_score.cpp b/src/game/server/score/file_score.cpp index 955763a4d..880c95209 100644 --- a/src/game/server/score/file_score.cpp +++ b/src/game/server/score/file_score.cpp @@ -209,6 +209,11 @@ void CFileScore::LoadScore(int ClientID) PlayerData(ClientID)->Set(pPlayer->m_Score, pPlayer->m_aCpTime); } +void CFileScore::SaveTeamScore(int* ClientIDs, unsigned int Size, float Time) +{ + dbg_msg("FileScore", "SaveTeamScore not implemented for FileScore"); +} + void CFileScore::SaveScore(int ClientID, float Time, float CpTime[NUM_CHECKPOINTS]) { @@ -278,10 +283,24 @@ void CFileScore::ShowRank(int ClientID, const char* pName, bool Search) GameServer()->SendChatTarget(ClientID, aBuf); } +void CFileScore::ShowTeamTop5(IConsole::IResult *pResult, int ClientID, void *pUserData, int Debut) +{ + char aBuf[512]; + str_format(aBuf, sizeof(aBuf), "Team ranks not supported in file based servers"); + GameServer()->SendChatTarget(ClientID, aBuf); +} + +void CFileScore::ShowTeamRank(int ClientID, const char* pName, bool Search) +{ + char aBuf[512]; + str_format(aBuf, sizeof(aBuf), "Team ranks not supported in file based servers"); + GameServer()->SendChatTarget(ClientID, aBuf); +} + void CFileScore::ShowTopPoints(IConsole::IResult *pResult, int ClientID, void *pUserData, int Debut) { char aBuf[512]; - str_format(aBuf, sizeof(aBuf), "Points not supported in file based servers"); + str_format(aBuf, sizeof(aBuf), "Team ranks not supported in file based servers"); GameServer()->SendChatTarget(ClientID, aBuf); } diff --git a/src/game/server/score/file_score.h b/src/game/server/score/file_score.h index ac618f0f0..1089fcc2f 100644 --- a/src/game/server/score/file_score.h +++ b/src/game/server/score/file_score.h @@ -65,11 +65,16 @@ public: virtual void LoadScore(int ClientID); virtual void SaveScore(int ClientID, float Time, float CpTime[NUM_CHECKPOINTS]); + virtual void SaveTeamScore(int* ClientIDs, unsigned int Size, float Time); virtual void ShowTop5(IConsole::IResult *pResult, int ClientID, void *pUserData, int Debut = 1); virtual void ShowRank(int ClientID, const char* pName, bool Search = false); + virtual void ShowTeamTop5(IConsole::IResult *pResult, int ClientID, + void *pUserData, int Debut = 1); + virtual void ShowTeamRank(int ClientID, const char* pName, bool Search = false); + virtual void ShowTopPoints(IConsole::IResult *pResult, int ClientID, void *pUserData, int Debut); virtual void ShowPoints(int ClientID, const char* pName, bool Search); }; diff --git a/src/game/server/score/sql_score.cpp b/src/game/server/score/sql_score.cpp index f73a94d21..bd0efa7fe 100644 --- a/src/game/server/score/sql_score.cpp +++ b/src/game/server/score/sql_score.cpp @@ -3,7 +3,6 @@ /* CSqlScore class by Sushi */ #if defined(CONF_SQL) #include -#include #include #include @@ -180,6 +179,9 @@ void CSqlScore::Init() str_format(aBuf, sizeof(aBuf), "CREATE TABLE IF NOT EXISTS %s_%s_race (Name VARCHAR(%d) NOT NULL, Timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP , Time FLOAT DEFAULT 0, cp1 FLOAT DEFAULT 0, cp2 FLOAT DEFAULT 0, cp3 FLOAT DEFAULT 0, cp4 FLOAT DEFAULT 0, cp5 FLOAT DEFAULT 0, cp6 FLOAT DEFAULT 0, cp7 FLOAT DEFAULT 0, cp8 FLOAT DEFAULT 0, cp9 FLOAT DEFAULT 0, cp10 FLOAT DEFAULT 0, cp11 FLOAT DEFAULT 0, cp12 FLOAT DEFAULT 0, cp13 FLOAT DEFAULT 0, cp14 FLOAT DEFAULT 0, cp15 FLOAT DEFAULT 0, cp16 FLOAT DEFAULT 0, cp17 FLOAT DEFAULT 0, cp18 FLOAT DEFAULT 0, cp19 FLOAT DEFAULT 0, cp20 FLOAT DEFAULT 0, cp21 FLOAT DEFAULT 0, cp22 FLOAT DEFAULT 0, cp23 FLOAT DEFAULT 0, cp24 FLOAT DEFAULT 0, cp25 FLOAT DEFAULT 0, KEY Name (Name)) CHARACTER SET utf8 ;", m_pPrefix, m_aMap, MAX_NAME_LENGTH); m_pStatement->execute(aBuf); + str_format(aBuf, sizeof(aBuf), "CREATE TABLE IF NOT EXISTS %s_%s_teamrace (Name VARCHAR(%d) NOT NULL, Timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP, Time FLOAT DEFAULT 0, ID VARBINARY(16) NOT NULL, KEY Name (Name)) CHARACTER SET utf8 ;", m_pPrefix, m_aMap, MAX_NAME_LENGTH); + m_pStatement->execute(aBuf); + // Check if table has new column with timestamp str_format(aBuf, sizeof(aBuf), "SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = '%s_%s_race' AND column_name = 'Timestamp'",m_pPrefix, m_aMap); m_pResults = m_pStatement->executeQuery(aBuf); @@ -191,6 +193,17 @@ void CSqlScore::Init() m_pStatement->execute(aBuf); } + // Check if table has new column with timestamp + str_format(aBuf, sizeof(aBuf), "SELECT column_name FROM INFORMATION_SCHEMA.COLUMNS WHERE table_name = '%s_%s_teamrace' AND column_name = 'Timestamp'",m_pPrefix, m_aMap); + m_pResults = m_pStatement->executeQuery(aBuf); + + if(m_pResults->rowsCount() < 1) + { + // If not... add the column + str_format(aBuf, sizeof(aBuf), "ALTER TABLE %s_%s_teamrace ADD Timestamp TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP AFTER Name, ADD INDEX(Name);",m_pPrefix, m_aMap); + m_pStatement->execute(aBuf); + } + dbg_msg("SQL", "Tables were created successfully"); // get the best time @@ -293,6 +306,62 @@ void CSqlScore::LoadScore(int ClientID) #endif } +void CSqlScore::SaveTeamScoreThread(void *pUser) +{ + lock_wait(gs_SqlLock); + + CSqlTeamScoreData *pData = (CSqlTeamScoreData *)pUser; + + // Connect to database + if(pData->m_pSqlData->Connect()) + { + try + { + char aBuf[2300]; + //char bBuf[2300]; + //bBuf[0] = '\0'; + + pData->m_pSqlData->m_pStatement->execute("SET @id = UUID();"); + + for(unsigned int i = 0; i < pData->m_Size; i++) + { + pData->m_pSqlData->ClearString(pData->m_aNames[i]); + //strcat(bBuf, pData->m_aNames[i]); + //if (i < pData->m_Size - 2) + // strcat(bBuf, ", "); + //else if (i < pData->m_Size - 1) + // strcat(bBuf, " & "); + + // if no entry found... create a new one + str_format(aBuf, sizeof(aBuf), "INSERT IGNORE INTO %s_%s_teamrace(Name, Timestamp, Time, ID) VALUES ('%s', CURRENT_TIMESTAMP(), '%.2f', @id);", pData->m_pSqlData->m_pPrefix, pData->m_pSqlData->m_aMap, pData->m_aNames[i], pData->m_Time); + pData->m_pSqlData->m_pStatement->execute(aBuf); + } + + //str_format(aBuf, sizeof(aBuf), "INSERT IGNORE INTO %s_%s_teamrace(Name, Timestamp, Time) VALUES ('%s', CURRENT_TIMESTAMP(), '%.2f');", pData->m_pSqlData->m_pPrefix, pData->m_pSqlData->m_aMap, bBuf, pData->m_Time); + //pData->m_pSqlData->m_pStatement->execute(aBuf); + + dbg_msg("SQL", "Updating time done"); + + // delete results statement + delete pData->m_pSqlData->m_pStatement; + } + catch (sql::SQLException &e) + { + char aBuf[256]; + str_format(aBuf, sizeof(aBuf), "MySQL Error: %s", e.what()); + dbg_msg("SQL", aBuf); + dbg_msg("SQL", "ERROR: Could not update time"); + } + + // disconnect from database + pData->m_pSqlData->Disconnect();//TODO:Check if an exception is caught will this still execute ? + } + + delete pData; + + lock_release(gs_SqlLock); +} + void CSqlScore::SaveScoreThread(void *pUser) { lock_wait(gs_SqlLock); @@ -354,6 +423,223 @@ void CSqlScore::SaveScore(int ClientID, float Time, float CpTime[NUM_CHECKPOINTS #endif } +void CSqlScore::SaveTeamScore(int* aClientIDs, unsigned int Size, float Time) +{ + CConsole* pCon = (CConsole*)GameServer()->Console(); + if(pCon->m_Cheated) + return; + CSqlTeamScoreData *Tmp = new CSqlTeamScoreData(); + for(unsigned int i = 0; i < Size; i++) + { + Tmp->m_aClientIDs[i] = aClientIDs[i]; + str_copy(Tmp->m_aNames[i], Server()->ClientName(aClientIDs[i]), sizeof(Tmp->m_aNames[i])); + } + Tmp->m_Size = Size; + Tmp->m_Time = Time; + Tmp->m_pSqlData = this; + + void *SaveTeamThread = thread_create(SaveTeamScoreThread, Tmp); +#if defined(CONF_FAMILY_UNIX) + pthread_detach((pthread_t)SaveTeamThread); +#endif +} + +void CSqlScore::ShowTeamRankThread(void *pUser) +{ + lock_wait(gs_SqlLock); + + CSqlScoreData *pData = (CSqlScoreData *)pUser; + + // Connect to database + if(pData->m_pSqlData->Connect()) + { + try + { + // check strings + char originalName[MAX_NAME_LENGTH]; + strcpy(originalName,pData->m_aName); + pData->m_pSqlData->ClearString(pData->m_aName); + + // check sort methode + char aBuf[600]; + char aNames[2300]; + aNames[0] = '\0'; + + pData->m_pSqlData->m_pStatement->execute("SET @rownum := 0;"); + str_format(aBuf, sizeof(aBuf), "SELECT Rank, Name, Time, UNIX_TIMESTAMP(CURRENT_TIMESTAMP)-UNIX_TIMESTAMP(Timestamp) as Ago, UNIX_TIMESTAMP(Timestamp) as stamp FROM ((SELECT @rownum := @rownum + 1 AS RANK, ID FROM (SELECT ID, MIN(Time) as Time FROM %s_%s_teamrace WHERE Name = '%s' GROUP BY ID) as all_top_times ORDER BY Time ASC LIMIT 1) as l) LEFT JOIN %s_%s_teamrace as r ON l.ID = r.ID ORDER BY Name ASC;", pData->m_pSqlData->m_pPrefix, pData->m_pSqlData->m_aMap, pData->m_aName, pData->m_pSqlData->m_pPrefix, pData->m_pSqlData->m_aMap); + + pData->m_pSqlData->m_pResults = pData->m_pSqlData->m_pStatement->executeQuery(aBuf); + + int Rows = pData->m_pSqlData->m_pResults->rowsCount(); + + if(Rows < 1) + { + str_format(aBuf, sizeof(aBuf), "%s has no team ranks", originalName); + pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, aBuf); + } + else + { + pData->m_pSqlData->m_pResults->first(); + + int since = (int)pData->m_pSqlData->m_pResults->getInt("Ago"); + char agoString[40]; + mem_zero(agoString, sizeof(agoString)); + agoTimeToString(since,agoString); + + float Time = (float)pData->m_pSqlData->m_pResults->getDouble("Time"); + int Rank = (int)pData->m_pSqlData->m_pResults->getInt("Rank"); + + for(int Row = 0; Row < Rows; Row++) + { + strcat(aNames, pData->m_pSqlData->m_pResults->getString("Name").c_str()); + pData->m_pSqlData->m_pResults->next(); + + if (Row < Rows - 2) + strcat(aNames, ", "); + else if (Row < Rows - 1) + strcat(aNames, " & "); + } + + pData->m_pSqlData->m_pResults->first(); + + if(g_Config.m_SvHideScore) + str_format(aBuf, sizeof(aBuf), "Your team time: %d minute(s) %5.2f second(s)", (int)(Time/60), Time-((int)Time/60*60)); + else + str_format(aBuf, sizeof(aBuf), "%d. %s Team time: %d minute(s) %5.2f second(s), requested by %s", Rank, aNames, (int)(Time/60), Time-((int)Time/60*60), pData->m_aRequestingPlayer, agoString); + + if(pData->m_pSqlData->m_pResults->getInt("stamp") != 0) + { + pData->m_pSqlData->GameServer()->SendChat(-1, CGameContext::CHAT_ALL, aBuf, pData->m_ClientID); + str_format(aBuf, sizeof(aBuf), "Finished: %s ago", agoString); + } + if(pData->m_Search) + strcat(aBuf, pData->m_aRequestingPlayer); + pData->m_pSqlData->GameServer()->SendChat(-1, CGameContext::CHAT_ALL, aBuf, pData->m_ClientID); + + } + + dbg_msg("SQL", "Showing teamrank done"); + + // delete results and statement + delete pData->m_pSqlData->m_pResults; + delete pData->m_pSqlData->m_pStatement; + } + catch (sql::SQLException &e) + { + char aBuf[256]; + str_format(aBuf, sizeof(aBuf), "MySQL Error: %s", e.what()); + dbg_msg("SQL", aBuf); + dbg_msg("SQL", "ERROR: Could not show team rank"); + } + + // disconnect from database + pData->m_pSqlData->Disconnect();//TODO:Check if an exception is caught will this still execute ? + } + + delete pData; + + lock_release(gs_SqlLock); +} + +void CSqlScore::ShowTeamTop5Thread(void *pUser) +{ + lock_wait(gs_SqlLock); + + CSqlScoreData *pData = (CSqlScoreData *)pUser; + + // Connect to database + if(pData->m_pSqlData->Connect()) + { + try + { + // check sort methode + char aBuf[512]; + + str_format(aBuf, sizeof(aBuf), "SELECT r.ID, Name, Time, UNIX_TIMESTAMP(CURRENT_TIMESTAMP)-UNIX_TIMESTAMP(Timestamp) as Ago, UNIX_TIMESTAMP(Timestamp) as stamp FROM ((SELECT ID FROM (SELECT ID, MIN(Time) as Time FROM %s_%s_teamrace GROUP BY ID) as all_top_times ORDER BY Time ASC LIMIT %d, 5) as l) LEFT JOIN %s_%s_teamrace as r ON l.ID = r.ID ORDER BY Time ASC, Name ASC, r.ID;", pData->m_pSqlData->m_pPrefix, pData->m_pSqlData->m_aMap, pData->m_Num-1, pData->m_pSqlData->m_pPrefix, pData->m_pSqlData->m_aMap); + pData->m_pSqlData->m_pResults = pData->m_pSqlData->m_pStatement->executeQuery(aBuf); + + // show teamtop5 + pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, "------- Team Top 5 -------"); + + int Rows = pData->m_pSqlData->m_pResults->rowsCount(); + + if (Rows >= 1) { + char aID[17]; + char aID2[17]; + char aNames[2300]; + int Rank = pData->m_Num; + float Time = 0; + int aCuts[Rows]; + int CutPos = 0; + + aNames[0] = '\0'; + aCuts[0] = -1; + + pData->m_pSqlData->m_pResults->first(); + strcpy(aID, pData->m_pSqlData->m_pResults->getString("ID").c_str()); + for(int Row = 0; Row < Rows; Row++) + { + strcpy(aID2, pData->m_pSqlData->m_pResults->getString("ID").c_str()); + if (str_comp(aID, aID2) != 0) + { + strcpy(aID, aID2); + aCuts[CutPos++] = Row - 1; + } + pData->m_pSqlData->m_pResults->next(); + } + aCuts[CutPos] = Rows - 1; + + CutPos = 0; + pData->m_pSqlData->m_pResults->first(); + for(int Row = 0; Row < Rows; Row++) + { + strcat(aNames, pData->m_pSqlData->m_pResults->getString("Name").c_str()); + + if (Row < aCuts[CutPos] - 1) + strcat(aNames, ", "); + else if (Row < aCuts[CutPos]) + strcat(aNames, " & "); + + Time = (float)pData->m_pSqlData->m_pResults->getDouble("Time"); + + if (Row == aCuts[CutPos]) + { + str_format(aBuf, sizeof(aBuf), "%d. %s Team Time: %d minute(s) %.2f second(s)", Rank, aNames, (int)(Time/60), Time-((int)Time/60*60)); + pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, aBuf); + Rank++; + CutPos++; + aNames[0] = '\0'; + } + + pData->m_pSqlData->m_pResults->next(); + } + } + + pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, "-------------------------------"); + + dbg_msg("SQL", "Showing teamtop5 done"); + + // delete results and statement + delete pData->m_pSqlData->m_pResults; + delete pData->m_pSqlData->m_pStatement; + } + catch (sql::SQLException &e) + { + char aBuf[256]; + str_format(aBuf, sizeof(aBuf), "MySQL Error: %s", e.what()); + dbg_msg("SQL", aBuf); + dbg_msg("SQL", "ERROR: Could not show top5"); + } + + // disconnect from database + pData->m_pSqlData->Disconnect(); + } + + delete pData; + + lock_release(gs_SqlLock); +} + void CSqlScore::ShowRankThread(void *pUser) { lock_wait(gs_SqlLock); @@ -446,6 +732,21 @@ void CSqlScore::ShowRankThread(void *pUser) lock_release(gs_SqlLock); } +void CSqlScore::ShowTeamRank(int ClientID, const char* pName, bool Search) +{ + CSqlScoreData *Tmp = new CSqlScoreData(); + Tmp->m_ClientID = ClientID; + str_copy(Tmp->m_aName, pName, sizeof(Tmp->m_aName)); + Tmp->m_Search = Search; + str_format(Tmp->m_aRequestingPlayer, sizeof(Tmp->m_aRequestingPlayer), "%s", Server()->ClientName(ClientID)); + Tmp->m_pSqlData = this; + + void *TeamRankThread = thread_create(ShowTeamRankThread, Tmp); +#if defined(CONF_FAMILY_UNIX) + pthread_detach((pthread_t)TeamRankThread); +#endif +} + void CSqlScore::ShowRank(int ClientID, const char* pName, bool Search) { CSqlScoreData *Tmp = new CSqlScoreData(); @@ -600,6 +901,19 @@ void CSqlScore::ShowTimesThread(void *pUser) lock_release(gs_SqlLock); } +void CSqlScore::ShowTeamTop5(IConsole::IResult *pResult, int ClientID, void *pUserData, int Debut) +{ + CSqlScoreData *Tmp = new CSqlScoreData(); + Tmp->m_Num = Debut; + Tmp->m_ClientID = ClientID; + Tmp->m_pSqlData = this; + + void *TeamTop5Thread = thread_create(ShowTeamTop5Thread, Tmp); +#if defined(CONF_FAMILY_UNIX) + pthread_detach((pthread_t)TeamTop5Thread); +#endif +} + void CSqlScore::ShowTop5(IConsole::IResult *pResult, int ClientID, void *pUserData, int Debut) { CSqlScoreData *Tmp = new CSqlScoreData(); diff --git a/src/game/server/score/sql_score.h b/src/game/server/score/sql_score.h index 4c6c44702..6fcbfcf8e 100644 --- a/src/game/server/score/sql_score.h +++ b/src/game/server/score/sql_score.h @@ -51,8 +51,11 @@ class CSqlScore: public IScore static void LoadScoreThread(void *pUser); static void SaveScoreThread(void *pUser); + static void SaveTeamScoreThread(void *pUser); static void ShowRankThread(void *pUser); static void ShowTop5Thread(void *pUser); + static void ShowTeamRankThread(void *pUser); + static void ShowTeamTop5Thread(void *pUser); static void ShowTimesThread(void *pUser); static void ShowPointsThread(void *pUser); static void ShowTopPointsThread(void *pUser); @@ -78,11 +81,15 @@ public: virtual void LoadScore(int ClientID); virtual void SaveScore(int ClientID, float Time, float CpTime[NUM_CHECKPOINTS]); + virtual void SaveTeamScore(int* aClientIDs, unsigned int Size, float Time); virtual void ShowRank(int ClientID, const char* pName, bool Search = false); + virtual void ShowTeamRank(int ClientID, const char* pName, bool Search = false); virtual void ShowTimes(int ClientID, const char* pName, int Debut = 1); virtual void ShowTimes(int ClientID, int Debut = 1); virtual void ShowTop5(IConsole::IResult *pResult, int ClientID, void *pUserData, int Debut = 1); + virtual void ShowTeamTop5(IConsole::IResult *pResult, int ClientID, + void *pUserData, int Debut = 1); virtual void ShowPoints(int ClientID, const char* pName, bool Search = false); virtual void ShowTopPoints(IConsole::IResult *pResult, int ClientID, void *pUserData, int Debut = 1); @@ -106,4 +113,22 @@ struct CSqlScoreData char m_aRequestingPlayer[MAX_NAME_LENGTH]; }; +struct CSqlTeamScoreData +{ + CSqlScore *m_pSqlData; + unsigned int m_Size; + int m_aClientIDs[MAX_CLIENTS]; +#if defined(CONF_FAMILY_WINDOWS) + char m_aNames[16][MAX_CLIENTS]; // Don't edit this, or all your teeth will fall http://bugs.mysql.com/bug.php?id=50046 +#else + char m_aNames[MAX_NAME_LENGTH * 2 - 1][MAX_CLIENTS]; +#endif + + float m_Time; + float m_aCpCurrent[NUM_CHECKPOINTS]; + int m_Num; + bool m_Search; + char m_aRequestingPlayer[MAX_NAME_LENGTH]; +}; + #endif diff --git a/src/game/server/teams.cpp b/src/game/server/teams.cpp index ac1e10286..baab6956d 100644 --- a/src/game/server/teams.cpp +++ b/src/game/server/teams.cpp @@ -110,6 +110,10 @@ void CGameTeams::OnCharacterFinish(int ClientID) { ChangeTeamState(m_Core.Team(ClientID), TEAMSTATE_FINISHED); //TODO: Make it better //ChangeTeamState(m_Core.Team(ClientID), TEAMSTATE_OPEN); + + CPlayer *TeamPlayers[MAX_CLIENTS]; + unsigned int PlayersCount = 0; + for (int i = 0; i < MAX_CLIENTS; ++i) { if (m_Core.Team(ClientID) == m_Core.Team(i)) @@ -119,10 +123,14 @@ void CGameTeams::OnCharacterFinish(int ClientID) { OnFinish(pPlayer); m_TeeFinished[i] = false; + + TeamPlayers[PlayersCount++] = pPlayer; } } } + OnTeamFinish(TeamPlayers, PlayersCount); + } } } @@ -331,6 +339,30 @@ float *CGameTeams::GetCpCurrent(CPlayer* Player) return NULL; } +void CGameTeams::OnTeamFinish(CPlayer** Players, unsigned int Size) +{ + float time = (float) (Server()->Tick() - GetStartTime(Players[0])) + / ((float) Server()->TickSpeed()); + if (time < 0.000001f) + return; + + bool CallSaveScore = false; + +#if defined(CONF_SQL) + CallSaveScore = g_Config.m_SvUseSQL; +#endif + + int PlayerCIDs[Size]; + + for(unsigned int i = 0; i < Size; i++) + { + PlayerCIDs[i] = Players[i]->GetCID(); + } + + if (CallSaveScore) + GameServer()->Score()->SaveTeamScore(PlayerCIDs, Size, time); +} + void CGameTeams::OnFinish(CPlayer* Player) { if (!Player || !Player->IsPlaying()) diff --git a/src/game/server/teams.h b/src/game/server/teams.h index 8146fcfe4..2fea256af 100644 --- a/src/game/server/teams.h +++ b/src/game/server/teams.h @@ -74,6 +74,7 @@ public: void SetStartTime(CPlayer* Player, int StartTime); void SetRefreshTime(CPlayer* Player, int RefreshTime); void SetCpActive(CPlayer* Player, int CpActive); + void OnTeamFinish(CPlayer** Players, unsigned int Size); void OnFinish(CPlayer* Player); bool TeeFinished(int ClientID) {