Add /points and /toppoints using points.cfg file

This commit is contained in:
def 2013-07-21 04:52:23 +02:00
parent e49960a34a
commit c42e9f1399
12 changed files with 345 additions and 9 deletions

2
points.cfg Normal file
View file

@ -0,0 +1,2 @@
3 Spiral
5 rockettry

View file

@ -1567,21 +1567,23 @@ int str_length(const char *str)
return (int)strlen(str);
}
void str_format(char *buffer, int buffer_size, const char *format, ...)
int str_format(char *buffer, int buffer_size, const char *format, ...)
{
int ret;
#if defined(CONF_FAMILY_WINDOWS)
va_list ap;
va_start(ap, format);
_vsnprintf(buffer, buffer_size, format, ap);
ret = _vsnprintf(buffer, buffer_size, format, ap);
va_end(ap);
#else
va_list ap;
va_start(ap, format);
vsnprintf(buffer, buffer_size, format, ap);
ret = vsnprintf(buffer, buffer_size, format, ap);
va_end(ap);
#endif
buffer[buffer_size-1] = 0; /* assure null termination */
return ret;
}

View file

@ -760,12 +760,15 @@ int str_length(const char *str);
format - printf formating string.
... - Parameters for the formating.
Returns:
Length of written string
Remarks:
- See the C manual for syntax for the printf formating string.
- The strings are treated as zero-termineted strings.
- Garantees that dst string will contain zero-termination.
*/
void str_format(char *buffer, int buffer_size, const char *format, ...);
int str_format(char *buffer, int buffer_size, const char *format, ...);
/*
Function: str_sanitize_strong

View file

@ -4,7 +4,6 @@
#include <base/system.h>
#include <engine/storage.h>
#include "engine.h"
#include "config.h"
// compiled-in data-dir path
#define DATA_DIR "data"
@ -45,4 +44,4 @@ public:
IStorage *CreateStorage(const char *pApplicationName, const char *pArgv0);
#endif
#endif

View file

@ -857,3 +857,64 @@ void CGameContext::ConSetTimerType(IConsole::IResult *pResult, void *pUserData)
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD,"timer",aBuf);
}
#if defined(CONF_SQL)
void CGameContext::ConPoints(IConsole::IResult *pResult, void *pUserData)
{
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 + 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),
true);
else
pSelf->Console()->Print(
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
#if defined(CONF_SQL)
void CGameContext::ConTopPoints(IConsole::IResult *pResult, void *pUserData)
{
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 + pSelf->Server()->TickSpeed() >= pSelf->Server()->Tick())
return;
if (g_Config.m_SvHideScore)
{
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "toppoints",
"Showing the global top points is not allowed on this server.");
return;
}
if (pResult->NumArguments() > 0 && pResult->GetInteger(0) >= 0)
pSelf->Score()->ShowTopPoints(pResult, pResult->m_ClientID, pUserData,
pResult->GetInteger(0));
else
pSelf->Score()->ShowTopPoints(pResult, pResult->m_ClientID, pUserData);
if(pSelf->m_apPlayers[pResult->m_ClientID] && g_Config.m_SvUseSQL)
pSelf->m_apPlayers[pResult->m_ClientID]->m_LastSQLQuery = pSelf->Server()->Tick();
}
#endif

View file

@ -27,6 +27,8 @@ CHAT_COMMAND("timer", "?s", CFGFLAG_CHAT|CFGFLAG_SERVER, ConSetTimerType, this,
#if defined(CONF_SQL)
CHAT_COMMAND("times", "?s?i", CFGFLAG_CHAT|CFGFLAG_SERVER, ConTimes, this, "/times ?s?i shows last 5 times of the server or of a player beginning with name s starting with time i (i = 1 by default)")
CHAT_COMMAND("points", "?r", CFGFLAG_CHAT|CFGFLAG_SERVER, ConPoints, this, "Shows the global points of a player beginning with name r (your rank by default)")
CHAT_COMMAND("toppoints", "?i", CFGFLAG_CHAT|CFGFLAG_SERVER, ConTopPoints, this, "Shows five points of the global point ladder beginning with rank i (1 by default)")
#endif
#undef CHAT_COMMAND

View file

@ -229,6 +229,8 @@ private:
static void ConTop5(IConsole::IResult *pResult, void *pUserData);
#if defined(CONF_SQL)
static void ConTimes(IConsole::IResult *pResult, void *pUserData);
static void ConPoints(IConsole::IResult *pResult, void *pUserData);
static void ConTopPoints(IConsole::IResult *pResult, void *pUserData);
#endif
static void ConUTF8(IConsole::IResult *pResult, void *pUserData);

View file

@ -48,6 +48,9 @@ public:
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 ShowTopPoints(IConsole::IResult *pResult, int ClientID, void *pUserData, int Debut=1) = 0;
virtual void ShowPoints(int ClientID, const char* pName, bool Search=false) = 0;
};
#endif

View file

@ -277,3 +277,17 @@ void CFileScore::ShowRank(int ClientID, const char* pName, bool Search)
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");
GameServer()->SendChatTarget(ClientID, aBuf);
}
void CFileScore::ShowPoints(int ClientID, const char* pName, bool Search)
{
char aBuf[512];
str_format(aBuf, sizeof(aBuf), "Points not supported in file based servers");
GameServer()->SendChatTarget(ClientID, aBuf);
}

View file

@ -69,6 +69,9 @@ public:
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 ShowTopPoints(IConsole::IResult *pResult, int ClientID, void *pUserData, int Debut);
virtual void ShowPoints(int ClientID, const char* pName, bool Search);
};
#endif

View file

@ -3,6 +3,9 @@
/* CSqlScore class by Sushi */
#if defined(CONF_SQL)
#include <string.h>
#include <iostream>
#include <fstream>
#include <algorithm>
#include <engine/shared/config.h>
#include "../entities/character.h"
@ -28,6 +31,50 @@ CSqlScore::CSqlScore(CGameContext *pGameServer) : m_pGameServer(pGameServer),
gs_SqlLock = lock_create();
Init();
LoadPointMapList();
}
int CSqlScore::LoadPointMapList()
{
m_PointsInfos = NULL;
m_PointsSize = 0;
std::ifstream f("points.cfg");
if (f.fail())
return -1;
if(!Connect())
return -1;
m_PointsSize = std::count(std::istreambuf_iterator<char>(f), std::istreambuf_iterator<char>(), '\n');
f.seekg(0);
m_PointsInfos = new CPointsInfo[m_PointsSize];
char aBuf[256];
unsigned int Position = 0;
while (f.getline(aBuf, 256) && Position < m_PointsSize)
{
CPointsInfo& Info = m_PointsInfos[Position];
if (sscanf(aBuf, "%u %127[^\t\n]", &Info.m_Points, Info.m_aMapName) == 2)
{
NormalizeMapname(Info.m_aMapName);
str_format(aBuf, sizeof(aBuf), "SELECT Name FROM record_%s_race;", Info.m_aMapName);
try
{
m_pStatement->executeQuery(aBuf);
}
catch (sql::SQLException &e)
{
continue;
}
Position++;
}
}
m_PointsSize = Position;
return 0;
}
CSqlScore::~CSqlScore()
@ -363,7 +410,7 @@ void CSqlScore::ShowRankThread(void *pUser)
if(g_Config.m_SvHideScore)
str_format(aBuf, sizeof(aBuf), "Your time: %d minute(s) %5.2f second(s)", (int)(Time/60), Time-((int)Time/60*60));
else
str_format(aBuf, sizeof(aBuf), "%d. %s Time: %d minute(s) %5.2f second(s), requested by (%s)", Rank, pData->m_pSqlData->m_pResults->getString("Name").c_str(), (int)(Time/60), Time-((int)Time/60*60), pData->m_aRequestingPlayer, agoString);
str_format(aBuf, sizeof(aBuf), "%d. %s Time: %d minute(s) %5.2f second(s), requested by %s", Rank, pData->m_pSqlData->m_pResults->getString("Name").c_str(), (int)(Time/60), Time-((int)Time/60*60), pData->m_aRequestingPlayer, agoString);
if(pData->m_pSqlData->m_pResults->getInt("stamp") != 0)
{
@ -405,7 +452,7 @@ void CSqlScore::ShowRank(int ClientID, const char* pName, bool Search)
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));
str_format(Tmp->m_aRequestingPlayer, sizeof(Tmp->m_aRequestingPlayer), "%s", Server()->ClientName(ClientID));
Tmp->m_pSqlData = this;
void *RankThread = thread_create(ShowRankThread, Tmp);
@ -719,4 +766,186 @@ void CSqlScore::agoTimeToString(int agoTime, char agoString[])
}
}
}
void CSqlScore::ShowPointsThread(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);
unsigned int PointsSize = pData->m_pSqlData->m_PointsSize;
CPointsInfo *PointsInfos = pData->m_pSqlData->m_PointsInfos;
if (!PointsInfos)
pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, "There are no maps configured for points");
goto end;
char aBuf[600 + 200 * PointsSize];
char aBuf2[600 + 200 * PointsSize];
char *pBuf = aBuf2;
int Size;
for(unsigned int i = 0; i < PointsSize; i++)
{
if (i < PointsSize - 1)
Size = str_format(pBuf, sizeof(aBuf2) - (pBuf - aBuf2), "(SELECT DISTINCT Name, %u AS Points FROM record_%s_race) UNION ALL ", PointsInfos[i].m_Points, PointsInfos[i].m_aMapName);
else
Size = str_format(pBuf, sizeof(aBuf2) - (pBuf - aBuf2), "(SELECT DISTINCT Name, %u AS Points FROM record_%s_race)", PointsInfos[i].m_Points, PointsInfos[i].m_aMapName);
pBuf += Size;
}
pData->m_pSqlData->m_pStatement->execute("SET @rownum := 0;");
str_format(aBuf, sizeof(aBuf), "SELECT * FROM ((SELECT @rownum := @rownum + 1 AS Rank, Name, Sum(Points) As Points FROM ((%s) AS t) GROUP BY Name ORDER BY Points DESC) AS r) WHERE Name = '%s';", aBuf2, pData->m_aName);
pData->m_pSqlData->m_pResults = pData->m_pSqlData->m_pStatement->executeQuery(aBuf);
if(pData->m_pSqlData->m_pResults->rowsCount() != 1)
{
str_format(aBuf, sizeof(aBuf), "%s has not collected any points so far", originalName);
pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, aBuf);
}
else
{
pData->m_pSqlData->m_pResults->next();
int count = (int)pData->m_pSqlData->m_pResults->getInt("Points");
int rank = (int)pData->m_pSqlData->m_pResults->getInt("Rank");
str_format(aBuf, sizeof(aBuf), "%d. %s Points: %d, requested by %s", rank, pData->m_pSqlData->m_pResults->getString("Name").c_str(), count, pData->m_aRequestingPlayer);
pData->m_pSqlData->GameServer()->SendChat(-1, CGameContext::CHAT_ALL, aBuf, pData->m_ClientID);
}
dbg_msg("SQL", "Showing points 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 points");
}
end:
// 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::ShowPoints(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 *PointsThread = thread_create(ShowPointsThread, Tmp);
#if defined(CONF_FAMILY_UNIX)
pthread_detach((pthread_t)PointsThread);
#endif
}
void CSqlScore::ShowTopPointsThread(void *pUser)
{
lock_wait(gs_SqlLock);
CSqlScoreData *pData = (CSqlScoreData *)pUser;
// Connect to database
if(pData->m_pSqlData->Connect())
{
try
{
unsigned int PointsSize = pData->m_pSqlData->m_PointsSize;
CPointsInfo *PointsInfos = pData->m_pSqlData->m_PointsInfos;
if (!PointsInfos)
pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, "There are no maps configured for points");
goto end;
char aBuf[600 + 200 * PointsSize];
char aBuf2[600 + 200 * PointsSize];
char *pBuf = aBuf2;
int Size;
for(unsigned int i = 0; i < PointsSize; i++)
{
if (i < PointsSize - 1)
Size = str_format(pBuf, sizeof(aBuf2) - (pBuf - aBuf2), "(SELECT DISTINCT Name, %u AS Points FROM record_%s_race) UNION ALL ", PointsInfos[i].m_Points, PointsInfos[i].m_aMapName);
else
Size = str_format(pBuf, sizeof(aBuf2) - (pBuf - aBuf2), "(SELECT DISTINCT Name, %u AS Points FROM record_%s_race)", PointsInfos[i].m_Points, PointsInfos[i].m_aMapName);
pBuf += Size;
}
pData->m_pSqlData->m_pStatement->execute("SET @rownum := 0;");
str_format(aBuf, sizeof(aBuf), "SELECT @rownum := @rownum + 1 AS Rank, Name, Sum(Points) As Points FROM ((%s) AS t) GROUP BY Name ORDER BY Points DESC LIMIT %d, 5;", aBuf2, pData->m_Num-1);
pData->m_pSqlData->m_pResults = pData->m_pSqlData->m_pStatement->executeQuery(aBuf);
// show top points
pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, "-------- Top Points --------");
int Rank = pData->m_Num;
while(pData->m_pSqlData->m_pResults->next())
{
str_format(aBuf, sizeof(aBuf), "%d. %s Points: %d", Rank, pData->m_pSqlData->m_pResults->getString("Name").c_str(), pData->m_pSqlData->m_pResults->getInt("Points"));
pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, aBuf);
Rank++;
}
pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, "-------------------------------");
dbg_msg("SQL", "Showing toppoints 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 toppoints");
}
end:
// disconnect from database
pData->m_pSqlData->Disconnect();
}
delete pData;
lock_release(gs_SqlLock);
}
void CSqlScore::ShowTopPoints(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 *TopPointsThread = thread_create(ShowTopPointsThread, Tmp);
#if defined(CONF_FAMILY_UNIX)
pthread_detach((pthread_t)TopPointsThread);
#endif
}
#endif

View file

@ -13,6 +13,12 @@
#include "../score.h"
struct CPointsInfo
{
char m_aMapName[128];
unsigned int m_Points;
};
class CSqlScore: public IScore
{
CGameContext *m_pGameServer;
@ -41,11 +47,15 @@ class CSqlScore: public IScore
return m_pServer;
}
int LoadPointMapList();
static void LoadScoreThread(void *pUser);
static void SaveScoreThread(void *pUser);
static void ShowRankThread(void *pUser);
static void ShowTop5Thread(void *pUser);
static void ShowTimesThread(void *pUser);
static void ShowPointsThread(void *pUser);
static void ShowTopPointsThread(void *pUser);
void Init();
@ -62,6 +72,9 @@ public:
CSqlScore(CGameContext *pGameServer);
~CSqlScore();
CPointsInfo* m_PointsInfos;
unsigned int m_PointsSize;
virtual void LoadScore(int ClientID);
virtual void SaveScore(int ClientID, float Time,
float CpTime[NUM_CHECKPOINTS]);
@ -70,7 +83,10 @@ public:
virtual void ShowTimes(int ClientID, int Debut = 1);
virtual void ShowTop5(IConsole::IResult *pResult, int ClientID,
void *pUserData, int Debut = 1);
static void agoTimeToString(int agoTime, char agoStrign[]);
virtual void ShowPoints(int ClientID, const char* pName, bool Search = false);
virtual void ShowTopPoints(IConsole::IResult *pResult, int ClientID,
void *pUserData, int Debut = 1);
static void agoTimeToString(int agoTime, char agoString[]);
};
struct CSqlScoreData