Added timestamp into MySQL ranking, and function to have ago time web2.0 like printed on asking for /rank

This commit is contained in:
Sebastian Wojtowicz 2011-02-13 05:45:17 +01:00 committed by GreYFoXGTi
parent 604ae5286f
commit 60de0da1c3
8 changed files with 279 additions and 214 deletions

View file

@ -45,7 +45,7 @@ void CGameContext::ConMoveRaw(IConsole::IResult *pResult, void *pUserData, int C
void CGameContext::MoveCharacter(int ClientID, int Victim, int X, int Y, bool Raw)
{
CCharacter* pChr = GetPlayerChar(ClientID);
if(!pChr)
return;
@ -135,10 +135,10 @@ void CGameContext::ConHammer(IConsole::IResult *pResult, void *pUserData, int Cl
int Type = pResult->GetInteger(0);
CCharacter* pChr = pSelf->GetPlayerChar(Victim);
if(!pChr)
return;
CServer* pServ = (CServer*)pSelf->Server();
if(Type>3 || Type<0)
{
@ -249,16 +249,16 @@ void CGameContext::ModifyWeapons(int ClientID, int Victim, int Weapon, bool Remo
Console()->PrintResponse(IConsole::OUTPUT_LEVEL_STANDARD, "info", "invalid weapon id");
return;
}
CCharacter* pChr = GetPlayerChar(Victim);
if(!pChr)
return;
if(Weapon == -1)
{
if(Remove && (pChr->GetActiveWeapon() == WEAPON_SHOTGUN || pChr->GetActiveWeapon() == WEAPON_GRENADE || pChr->GetActiveWeapon() == WEAPON_RIFLE))
pChr->SetActiveWeapon(WEAPON_GUN);
if(Remove)
{
pChr->SetWeaponGot(WEAPON_SHOTGUN, false);
@ -266,13 +266,13 @@ void CGameContext::ModifyWeapons(int ClientID, int Victim, int Weapon, bool Remo
pChr->SetWeaponGot(WEAPON_RIFLE, false);
}
else
pChr->GiveAllWeapons();
pChr->GiveAllWeapons();
}
else if(Weapon != WEAPON_NINJA)
{
if(Remove && pChr->GetActiveWeapon() == Weapon)
pChr->SetActiveWeapon(WEAPON_GUN);
if(Remove)
pChr->SetWeaponGot(Weapon, false);
else
@ -285,7 +285,7 @@ void CGameContext::ModifyWeapons(int ClientID, int Victim, int Weapon, bool Remo
Console()->PrintResponse(IConsole::OUTPUT_LEVEL_STANDARD, "info", "you can't remove ninja");
return;
}
pChr->GiveNinja();
}
@ -399,11 +399,11 @@ void CGameContext::ConFreeze(IConsole::IResult *pResult, void *pUserData, int Cl
if(pResult->NumArguments())
Seconds = clamp(pResult->GetInteger(0), -2, 9999);
CCharacter* pChr = pSelf->GetPlayerChar(Victim);
if(!pChr)
return;
if(pSelf->m_apPlayers[Victim])
{
pChr->Freeze(Seconds);
@ -757,7 +757,7 @@ void CGameContext::ConRank(IConsole::IResult *pResult, void *pUserData, int Clie
if(/*g_Config.m_SvSpamprotection && */pPlayer->m_Last_Chat && pPlayer->m_Last_Chat + pSelf->Server()->TickSpeed() + g_Config.m_SvChatDelay > pSelf->Server()->Tick())
return;
pPlayer->m_Last_Chat = pSelf->Server()->Tick();
if(pResult->NumArguments() > 0)
@ -771,7 +771,7 @@ void CGameContext::ConRank(IConsole::IResult *pResult, void *pUserData, int Clie
void CGameContext::ConJoinTeam(IConsole::IResult *pResult, void *pUserData, int ClientID)
{
CGameContext *pSelf = (CGameContext *)pUserData;
CGameControllerDDRace* Controller = (CGameControllerDDRace*)pSelf->m_pController;
if(g_Config.m_SvTeam == 0)
@ -868,7 +868,7 @@ void CGameContext::ConMe(IConsole::IResult *pResult, void *pUserData, int Client
{
CGameContext *pSelf = (CGameContext *)pUserData;
char aBuf[256 + 24];
str_format(aBuf, 256 + 24, "'%s' %s", pSelf->Server()->ClientName(ClientID), pResult->GetString(0));
if(g_Config.m_SvSlashMe)
pSelf->SendChat(-2, CGameContext::CHAT_ALL, aBuf, ClientID);
@ -879,7 +879,7 @@ void CGameContext::ConMe(IConsole::IResult *pResult, void *pUserData, int Client
void CGameContext::ConToggleEyeEmote(IConsole::IResult *pResult, void *pUserData, int ClientID)
{
CGameContext *pSelf = (CGameContext *)pUserData;
CCharacter *pChr = pSelf->m_apPlayers[ClientID]->GetCharacter();
if(pChr)
@ -892,7 +892,7 @@ void CGameContext::ConToggleEyeEmote(IConsole::IResult *pResult, void *pUserData
void CGameContext::ConToggleBroadcast(IConsole::IResult *pResult, void *pUserData, int ClientID)
{
CGameContext *pSelf = (CGameContext *)pUserData;
CCharacter *pChr = pSelf->m_apPlayers[ClientID]->GetCharacter();
if(pChr)
@ -902,39 +902,39 @@ void CGameContext::ConToggleBroadcast(IConsole::IResult *pResult, void *pUserDat
void CGameContext::ConEyeEmote(IConsole::IResult *pResult, void *pUserData, int ClientID)
{
CGameContext *pSelf = (CGameContext *)pUserData;
CCharacter *pChr = pSelf->m_apPlayers[ClientID]->GetCharacter();
if (pResult->NumArguments() == 0)
{
pSelf->Console()->PrintResponse(IConsole::OUTPUT_LEVEL_STANDARD, "info", "Emote commands are: /emote surprise /emote blink /emote close /emote angry /emote happy /emote pain");
pSelf->Console()->PrintResponse(IConsole::OUTPUT_LEVEL_STANDARD, "info", "Example: /emote surprise 10 for 10 seconds or /emote surprise (default 1 second)");
}
else
else
{
if (pChr)
if (pChr)
{
if (!str_comp(pResult->GetString(0), "angry"))
pChr->m_DefEmote = EMOTE_ANGRY;
pChr->m_DefEmote = EMOTE_ANGRY;
else if (!str_comp(pResult->GetString(0), "blink"))
pChr->m_DefEmote = EMOTE_BLINK;
pChr->m_DefEmote = EMOTE_BLINK;
else if (!str_comp(pResult->GetString(0), "close"))
pChr->m_DefEmote = EMOTE_BLINK;
pChr->m_DefEmote = EMOTE_BLINK;
else if (!str_comp(pResult->GetString(0), "happy"))
pChr->m_DefEmote = EMOTE_HAPPY;
pChr->m_DefEmote = EMOTE_HAPPY;
else if (!str_comp(pResult->GetString(0), "pain"))
pChr->m_DefEmote = EMOTE_PAIN;
pChr->m_DefEmote = EMOTE_PAIN;
else if (!str_comp(pResult->GetString(0), "surprise"))
pChr->m_DefEmote = EMOTE_SURPRISE;
pChr->m_DefEmote = EMOTE_SURPRISE;
else
{
pSelf->Console()->PrintResponse(IConsole::OUTPUT_LEVEL_STANDARD, "info", "Unkown emote... Say /emote");
}
int Duration = 1;
if (pResult->NumArguments() > 1)
Duration = pResult->GetInteger(1);
pChr->m_DefEmoteReset = pSelf->Server()->Tick() + Duration * pSelf->Server()->TickSpeed();
}
}

View file

@ -987,11 +987,13 @@ void CCharacter::OnFinish()
}
}
if(!pData->m_BestTime || time < pData->m_BestTime)
if(!pData->m_BestTime || time < pData->m_BestTime && !g_Config.m_SvUseSQL)
{
// update the score
pData->Set(time, m_CpCurrent);
}
else
{
if(str_comp_num(Server()->ClientName(m_pPlayer->GetCID()), "nameless tee", 12) != 0)
GameServer()->Score()->SaveScore(m_pPlayer->GetCID(), time, this);
}

View file

@ -33,10 +33,10 @@ void CGameControllerDDRace::InitTeleporter()
for(int i = 0; i < Width*Height; i++)
{
if(GameServer()->Collision()->TeleLayer()[i].m_Number > 0
if(GameServer()->Collision()->TeleLayer()[i].m_Number > 0
&& GameServer()->Collision()->TeleLayer()[i].m_Type == TILE_TELEOUT)
{
m_TeleOuts[GameServer()->Collision()->TeleLayer()[i].m_Number-1].push_back(vec2(i % GameServer()->Collision()->Layers()->TeleLayer()->m_Width*32+16,
m_TeleOuts[GameServer()->Collision()->TeleLayer()[i].m_Number-1].push_back(vec2(i % GameServer()->Collision()->Layers()->TeleLayer()->m_Width*32+16,
i/GameServer()->Collision()->Layers()->TeleLayer()->m_Width*32+16));
}
}

View file

@ -12,14 +12,14 @@
class CGameControllerDDRace : public IGameController
{
public:
CGameControllerDDRace(class CGameContext *pGameServer);
~CGameControllerDDRace();
CGameTeams m_Teams;
std::map < int , std::vector < vec2 > > m_TeleOuts;
void InitTeleporter();
virtual void Tick();
};

View file

@ -23,17 +23,17 @@ CFileScore::CFileScore(CGameContext *pGameServer) : m_pGameServer(pGameServer),
{
if(gs_ScoreLock == 0)
gs_ScoreLock = lock_create();
Init();
}
CFileScore::~CFileScore()
{
lock_wait(gs_ScoreLock);
// clear list
m_Top.clear();
lock_release(gs_ScoreLock);
}
@ -85,14 +85,14 @@ void CFileScore::Save()
void CFileScore::Init()
{
lock_wait(gs_ScoreLock);
// create folder if not exist
if(g_Config.m_SvScoreFolder[0])
fs_makedir(g_Config.m_SvScoreFolder);
std::fstream f;
f.open(SaveFile().c_str(), std::ios::in);
while(!f.eof() && !f.fail())
{
std::string TmpName, TmpScore, TmpCpLine;
@ -118,7 +118,7 @@ void CFileScore::Init()
}
f.close();
lock_release(gs_ScoreLock);
// save the current best score
if(m_Top.size())
((CGameControllerDDRace*)GameServer()->m_pController)->m_CurrentRecord = m_Top[0].m_Score;
@ -157,23 +157,23 @@ CFileScore::CPlayerScore *CFileScore::SearchName(const char *pName, int *pPositi
void CFileScore::UpdatePlayer(int ID, float Score, float aCpTime[NUM_CHECKPOINTS])
{
const char *pName = Server()->ClientName(ID);
lock_wait(gs_ScoreLock);
CPlayerScore *pPlayer = SearchScore(ID, 0);
if(pPlayer)
{
for(int c = 0; c < NUM_CHECKPOINTS; c++)
pPlayer->m_aCpTime[c] = aCpTime[c];
pPlayer->m_Score = Score;
str_copy(pPlayer->m_aName, pName, sizeof(pPlayer->m_aName));
sort(m_Top.all());
}
else
m_Top.add(*new CPlayerScore(pName, Score, aCpTime));
lock_release(gs_ScoreLock);
Save();
}
@ -187,7 +187,7 @@ void CFileScore::LoadScore(int ClientID)
lock_release(gs_ScoreLock);
Save();
}
// set score
if(pPlayer)
PlayerData(ClientID)->Set(pPlayer->m_Score, pPlayer->m_aCpTime);
@ -219,12 +219,12 @@ void CFileScore::ShowRank(int ClientID, const char* pName, bool Search)
CPlayerScore *pScore;
int Pos;
char aBuf[512];
if(!Search)
pScore = SearchScore(ClientID, &Pos);
else
pScore = SearchName(pName, &Pos, 1);
if(pScore && Pos > -1)
{
float Time = pScore->m_Score;
@ -242,6 +242,6 @@ void CFileScore::ShowRank(int ClientID, const char* pName, bool Search)
str_format(aBuf, sizeof(aBuf), "Several players were found.");
else
str_format(aBuf, sizeof(aBuf), "%s is not ranked", Search?pName:Server()->ClientName(ClientID));
GameServer()->Console()->PrintResponse(IConsole::OUTPUT_LEVEL_STANDARD, "rank", aBuf);
}

View file

@ -11,42 +11,42 @@ class CFileScore : public IScore
{
CGameContext *m_pGameServer;
IServer *m_pServer;
class CPlayerScore
{
public:
char m_aName[MAX_NAME_LENGTH];
float m_Score;
float m_aCpTime[NUM_CHECKPOINTS];
CPlayerScore() {};
CPlayerScore(const char *pName, float Score, float aCpTime[NUM_CHECKPOINTS]);
bool operator<(const CPlayerScore& other) { return (this->m_Score < other.m_Score); }
};
sorted_array<CPlayerScore> m_Top;
CGameContext *GameServer() { return m_pGameServer; }
IServer *Server() { return m_pServer; }
CPlayerScore *SearchScore(int ID, int *pPosition){ return SearchName(Server()->ClientName(ID), pPosition, 0 );};
;
CPlayerScore *SearchName(const char *pName, int *pPosition, bool MatchCase);
void UpdatePlayer(int ID, float Score, float aCpTime[NUM_CHECKPOINTS]);
void Init();
void Save();
static void SaveScoreThread(void *pUser);
public:
CFileScore(CGameContext *pGameServer);
~CFileScore();
virtual void LoadScore(int ClientID);
virtual void SaveScore(int ClientID, float Time, CCharacter *pChar);
virtual void ShowTop5(int ClientID, int Debut=1);
virtual void ShowRank(int ClientID, const char* pName, bool Search=false);
};

View file

@ -9,22 +9,21 @@
static LOCK gs_SqlLock = 0;
CSqlScore::CSqlScore(CGameContext *pGameServer)
: m_pGameServer(pGameServer),
m_pServer(pGameServer->Server()),
m_pDatabase(g_Config.m_SvSqlDatabase),
m_pPrefix(g_Config.m_SvSqlPrefix),
m_pUser(g_Config.m_SvSqlUser),
m_pPass(g_Config.m_SvSqlPw),
m_pIp(g_Config.m_SvSqlIp),
m_Port(g_Config.m_SvSqlPort)
CSqlScore::CSqlScore(CGameContext *pGameServer) : m_pGameServer(pGameServer),
m_pServer(pGameServer->Server()),
m_pDatabase(g_Config.m_SvSqlDatabase),
m_pPrefix(g_Config.m_SvSqlPrefix),
m_pUser(g_Config.m_SvSqlUser),
m_pPass(g_Config.m_SvSqlPw),
m_pIp(g_Config.m_SvSqlIp),
m_Port(g_Config.m_SvSqlPort)
{
str_copy(m_aMap, g_Config.m_SvMap, sizeof(m_aMap));
NormalizeMapname(m_aMap);
if(gs_SqlLock == 0)
gs_SqlLock = lock_create();
Init();
}
@ -36,65 +35,65 @@ CSqlScore::~CSqlScore()
bool CSqlScore::Connect()
{
try
try
{
// Create connection
m_pDriver = get_driver_instance();
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "tcp://%s:%d", m_pIp, m_Port);
m_pConnection = m_pDriver->connect(aBuf, m_pUser, m_pPass);
// Create Statement
m_pStatement = m_pConnection->createStatement();
// Create database if not exists
str_format(aBuf, sizeof(aBuf), "CREATE DATABASE IF NOT EXISTS %s", m_pDatabase);
m_pStatement->execute(aBuf);
// Connect to specific database
m_pConnection->setSchema(m_pDatabase);
dbg_msg("SQL", "SQL connection established");
return true;
}
}
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: SQL connection failed");
return false;
}
catch (const std::exception& ex) {
// ...
// ...
dbg_msg("SQL", "1 %s",ex.what());
} catch (const std::string& ex) {
// ...
// ...
dbg_msg("SQL", "2 %s",ex.c_str());
}
catch( int )
{
dbg_msg("SQL", "3 %s");
}
catch( float )
{
dbg_msg("SQL", "4 %s");
}
catch( char[] )
{
dbg_msg("SQL", "5 %s");
}
catch( char )
{
dbg_msg("SQL", "6 %s");
}
catch( int )
{
dbg_msg("SQL", "3 %s");
}
catch( float )
{
dbg_msg("SQL", "4 %s");
}
catch( char[] )
{
dbg_msg("SQL", "5 %s");
}
catch( char )
{
dbg_msg("SQL", "6 %s");
}
catch (...)
{
dbg_msg("SQL", "Unknown Error cause by the MySQL/C++ Connector, my advice compile server_debug and use it");
dbg_msg("SQL", "ERROR: SQL connection failed");
return false;
}
@ -124,32 +123,46 @@ void CSqlScore::Init()
{
// create tables
char aBuf[768];
str_format(aBuf, sizeof(aBuf), "CREATE TABLE IF NOT EXISTS %s_%s_race (Name VARCHAR(%d) NOT NULL, 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) CHARACTER SET utf8 ;", m_pPrefix, m_aMap, MAX_NAME_LENGTH);
str_format(aBuf, sizeof(aBuf), "CREATE TABLE IF NOT EXISTS %s_%s_race (Name VARCHAR(%d) NOT NULL, Timestamp 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) 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);
if(m_pResults->rowsCount() < 1){
// If not... add the column
str_format(aBuf, sizeof(aBuf), "%s_%s_race has no column Timestamp, I will add it now",m_pPrefix, m_aMap);
dbg_msg("SQL",aBuf);
str_format(aBuf, sizeof(aBuf), "ALTER TABLE %s_%s_race ADD Timestamp TIMESTAMP AFTER Name",m_pPrefix, m_aMap);
dbg_msg("SQL",aBuf);
m_pStatement->execute(aBuf);
}
dbg_msg("SQL", "Tables were created successfully");
// get the best time
str_format(aBuf, sizeof(aBuf), "SELECT Time FROM %s_%s_race ORDER BY `Time` ASC LIMIT 0, 1;", m_pPrefix, m_aMap);
m_pResults = m_pStatement->executeQuery(aBuf);
if(m_pResults->next())
{
((CGameControllerDDRace*)GameServer()->m_pController)->m_CurrentRecord = (float)m_pResults->getDouble("Time");
dbg_msg("SQL", "Getting best time on server done");
// delete results
delete m_pResults;
}
// delete statement
delete m_pStatement;
}
catch (sql::SQLException &e)
{
char aBuf[256];
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "MySQL Error: %s", e.what());
dbg_msg("SQL", aBuf);
dbg_msg("SQL", aBuf);
dbg_msg("SQL", "ERROR: Tables were NOT created");
}
@ -162,9 +175,9 @@ void CSqlScore::Init()
void CSqlScore::LoadScoreThread(void *pUser)
{
lock_wait(gs_SqlLock);
CSqlScoreData *pData = (CSqlScoreData *)pUser;
// Connect to database
if(pData->m_pSqlData->Connect())
{
@ -172,11 +185,11 @@ void CSqlScore::LoadScoreThread(void *pUser)
{
// check strings
pData->m_pSqlData->ClearString(pData->m_aName);
char aBuf[512];
str_format(aBuf, sizeof(aBuf), "SELECT * FROM %s_%s_race WHERE Name='%s';", pData->m_pSqlData->m_pPrefix, pData->m_pSqlData->m_aMap, pData->m_aName);
str_format(aBuf, sizeof(aBuf), "SELECT * FROM %s_%s_race WHERE Name='%s' ORDER BY time ASC LIMIT 1;", pData->m_pSqlData->m_pPrefix, pData->m_pSqlData->m_aMap, pData->m_aName);
pData->m_pSqlData->m_pResults = pData->m_pSqlData->m_pStatement->executeQuery(aBuf);
if(pData->m_pSqlData->m_pResults->next())
{
@ -192,25 +205,25 @@ void CSqlScore::LoadScoreThread(void *pUser)
}
}
}
dbg_msg("SQL", "Getting best time done");
// delete statement and results
delete pData->m_pSqlData->m_pStatement;
delete pData->m_pSqlData->m_pResults;
}
catch (sql::SQLException &e)
{
char aBuf[256];
{
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "MySQL Error: %s", e.what());
dbg_msg("SQL", aBuf);
dbg_msg("SQL", "ERROR: Could not update account");
}
// disconnect from database
pData->m_pSqlData->Disconnect();
}
delete pData;
lock_release(gs_SqlLock);
@ -222,7 +235,7 @@ void CSqlScore::LoadScore(int ClientID)
Tmp->m_ClientID = ClientID;
str_copy(Tmp->m_aName, Server()->ClientName(ClientID), sizeof(Tmp->m_aName));
Tmp->m_pSqlData = this;
void *LoadThread = thread_create(LoadScoreThread, Tmp);
#if defined(CONF_FAMILY_UNIX)
pthread_detach((pthread_t)LoadThread);
@ -232,9 +245,9 @@ void CSqlScore::LoadScore(int ClientID)
void CSqlScore::SaveScoreThread(void *pUser)
{
lock_wait(gs_SqlLock);
CSqlScoreData *pData = (CSqlScoreData *)pUser;
// Connect to database
if(pData->m_pSqlData->Connect())
{
@ -242,61 +255,30 @@ void CSqlScore::SaveScoreThread(void *pUser)
{
// check strings
pData->m_pSqlData->ClearString(pData->m_aName);
char aBuf[768];
// fisrt check for the name
str_format(aBuf, sizeof(aBuf), "SELECT * FROM %s_%s_race WHERE Name='%s';", pData->m_pSqlData->m_pPrefix, pData->m_pSqlData->m_aMap, pData->m_aName);
pData->m_pSqlData->m_pResults = pData->m_pSqlData->m_pStatement->executeQuery(aBuf);
// if the name is found...
if(pData->m_pSqlData->m_pResults->next())
{
// update time
if(g_Config.m_SvCheckpointSave)
str_format(aBuf, sizeof(aBuf), "UPDATE %s_%s_race SET Time='%.2f', cp1='%.2f', cp2='%.2f', cp3='%.2f', cp4='%.2f', cp5='%.2f', cp6='%.2f', cp7='%.2f', cp8='%.2f', cp9='%.2f', cp10='%.2f', cp11='%.2f', cp12='%.2f', cp13='%.2f', cp14='%.2f', cp15='%.2f', cp16='%.2f', cp17='%.2f', cp18='%.2f', cp19='%.2f', cp20='%.2f', cp21='%.2f', cp22='%.2f', cp23='%.2f', cp24='%.2f', cp25='%.2f' WHERE Name='%s';", pData->m_pSqlData->m_pPrefix, pData->m_pSqlData->m_aMap, pData->m_Time, pData->m_aCpCurrent[0], pData->m_aCpCurrent[1], pData->m_aCpCurrent[2], pData->m_aCpCurrent[3], pData->m_aCpCurrent[4], pData->m_aCpCurrent[5], pData->m_aCpCurrent[6], pData->m_aCpCurrent[7], pData->m_aCpCurrent[8], pData->m_aCpCurrent[9], pData->m_aCpCurrent[10], pData->m_aCpCurrent[11], pData->m_aCpCurrent[12], pData->m_aCpCurrent[13], pData->m_aCpCurrent[14], pData->m_aCpCurrent[15], pData->m_aCpCurrent[16], pData->m_aCpCurrent[17], pData->m_aCpCurrent[18], pData->m_aCpCurrent[19], pData->m_aCpCurrent[20], pData->m_aCpCurrent[21], pData->m_aCpCurrent[22], pData->m_aCpCurrent[23], pData->m_aCpCurrent[24], pData->m_aName);
else
str_format(aBuf, sizeof(aBuf), "UPDATE %s_%s_race SET Time='%.2f' WHERE Name='%s';", pData->m_pSqlData->m_pPrefix, pData->m_pSqlData->m_aMap, pData->m_Time, pData->m_aName);
pData->m_pSqlData->m_pStatement->execute(aBuf);
dbg_msg("SQL", "Updating time done");
// delete results statement
delete pData->m_pSqlData->m_pResults;
delete pData->m_pSqlData->m_pStatement;
// disconnect from database
pData->m_pSqlData->Disconnect();
delete pData;
lock_release(gs_SqlLock);
return;
}
// if no entry found... create a new one
str_format(aBuf, sizeof(aBuf), "INSERT IGNORE INTO %s_%s_race(Name, Time, cp1, cp2, cp3, cp4, cp5, cp6, cp7, cp8, cp9, cp10, cp11, cp12, cp13, cp14, cp15, cp16, cp17, cp18, cp19, cp20, cp21, cp22, cp23, cp24, cp25) VALUES ('%s', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f', '%.2f');", pData->m_pSqlData->m_pPrefix, pData->m_pSqlData->m_aMap, pData->m_aName, pData->m_Time, pData->m_aCpCurrent[0], pData->m_aCpCurrent[1], pData->m_aCpCurrent[2], pData->m_aCpCurrent[3], pData->m_aCpCurrent[4], pData->m_aCpCurrent[5], pData->m_aCpCurrent[6], pData->m_aCpCurrent[7], pData->m_aCpCurrent[8], pData->m_aCpCurrent[9], pData->m_aCpCurrent[10], pData->m_aCpCurrent[11], pData->m_aCpCurrent[12], pData->m_aCpCurrent[13], pData->m_aCpCurrent[14], pData->m_aCpCurrent[15], pData->m_aCpCurrent[16], pData->m_aCpCurrent[17], pData->m_aCpCurrent[18], pData->m_aCpCurrent[19], pData->m_aCpCurrent[20], pData->m_aCpCurrent[21], pData->m_aCpCurrent[22], pData->m_aCpCurrent[23], pData->m_aCpCurrent[24]);
pData->m_pSqlData->m_pStatement->execute(aBuf);
dbg_msg("SQL", "Updating time done");
// delete results statement
delete pData->m_pSqlData->m_pResults;
delete pData->m_pSqlData->m_pStatement;
}
catch (sql::SQLException &e)
{
char aBuf[256];
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "MySQL Error: %s", e.what());
dbg_msg("SQL", aBuf);
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);
@ -311,7 +293,7 @@ void CSqlScore::SaveScore(int ClientID, float Time, CCharacter *pChar)
for(int i = 0; i < NUM_CHECKPOINTS; i++)
Tmp->m_aCpCurrent[i] = pChar->m_CpCurrent[i];
Tmp->m_pSqlData = this;
void *SaveThread = thread_create(SaveScoreThread, Tmp);
#if defined(CONF_FAMILY_UNIX)
pthread_detach((pthread_t)SaveThread);
@ -321,9 +303,9 @@ void CSqlScore::SaveScore(int ClientID, float Time, CCharacter *pChar)
void CSqlScore::ShowRankThread(void *pUser)
{
lock_wait(gs_SqlLock);
CSqlScoreData *pData = (CSqlScoreData *)pUser;
// Connect to database
if(pData->m_pSqlData->Connect())
{
@ -333,19 +315,27 @@ void CSqlScore::ShowRankThread(void *pUser)
char originalName[MAX_NAME_LENGTH];
strcpy(originalName,pData->m_aName);
pData->m_pSqlData->ClearString(pData->m_aName);
// check sort methode
char aBuf[512];
pData->m_pSqlData->m_pStatement->execute("SET @rownum := 0;");
str_format(aBuf, sizeof(aBuf), "SELECT Rank, Name, Time "
str_format(aBuf, sizeof(aBuf), "SELECT Rank, one_rank.Name, one_rank.Time, UNIX_TIMESTAMP(CURRENT_TIMESTAMP)-UNIX_TIMESTAMP(r.Timestamp) as Ago, UNIX_TIMESTAMP(r.Timestamp) as stamp "
"FROM ("
"SELECT @rownum := @rownum + 1 AS RANK, Name, Time FROM %s_%s_race ORDER BY Time ASC"
") as Query "
"WHERE Name = '%s';", pData->m_pSqlData->m_pPrefix, pData->m_pSqlData->m_aMap,pData->m_aName);
"SELECT * FROM ("
"SELECT @rownum := @rownum + 1 AS RANK, Name, Time "
"FROM ("
"SELECT Name, min(Time) as Time "
"FROM %s_%s_race "
"Group By Name) as all_top_times "
"ORDER BY Time ASC) as all_ranks "
"WHERE all_ranks.Name = '%s') as one_rank "
"LEFT JOIN %s_%s_race as r "
"ON one_rank.Name = r.Name && one_rank.Time = r.Time "
";", 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);
if(pData->m_pSqlData->m_pResults->rowsCount() != 1)
{
str_format(aBuf, sizeof(aBuf), "%s is not ranked", originalName);
@ -353,43 +343,115 @@ void CSqlScore::ShowRankThread(void *pUser)
}
else
{
pData->m_pSqlData->m_pResults->next();
float Time = (float)pData->m_pSqlData->m_pResults->getDouble("Time");
int Rank = (float)pData->m_pSqlData->m_pResults->getInt("Rank");
pData->m_pSqlData->m_pResults->next();
int since = (int)pData->m_pSqlData->m_pResults->getInt("Ago");
char agoString[40];
agoTimeToString(since,agoString);
float Time = (float)pData->m_pSqlData->m_pResults->getDouble("Time");
int Rank = (int)pData->m_pSqlData->m_pResults->getInt("Rank");
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)", Rank, pData->m_pSqlData->m_pResults->getString("Name").c_str(), (int)(Time/60), Time-((int)Time/60*60));
str_format(aBuf, sizeof(aBuf), "%d. %s Time: %d minute(s) %5.2f second(s)", Rank, pData->m_pSqlData->m_pResults->getString("Name").c_str(), (int)(Time/60), Time-((int)Time/60*60), agoString);
if(pData->m_pSqlData->m_pResults->getInt("stamp") != 0){
pData->m_pSqlData->GameServer()->SendChatTarget(-1, aBuf);
str_format(aBuf, sizeof(aBuf), "Finished: %s ago", agoString);
}
if(pData->m_Search)
strcat(aBuf, pData->m_aRequestingPlayer);
pData->m_pSqlData->GameServer()->SendChatTarget(-1, aBuf);
}
dbg_msg("SQL", "Showing rank done");
// delete results and statement
delete pData->m_pSqlData->m_pResults;
delete pData->m_pSqlData->m_pResults;
delete pData->m_pSqlData->m_pStatement;
}
catch (sql::SQLException &e)
{
char aBuf[256];
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "MySQL Error: %s", e.what());
dbg_msg("SQL", aBuf);
dbg_msg("SQL", aBuf);
dbg_msg("SQL", "ERROR: Could not show 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::agoTimeToString(int agoTime, char agoString[]){
char aBuf[20];
int times[7] = {
60 * 60 * 24 * 365 ,
60 * 60 * 24 * 30 ,
60 * 60 * 24 * 7,
60 * 60 * 24 ,
60 * 60 ,
60 ,
1
};
char names[7][6] = {
"year",
"month",
"week",
"day",
"hour",
"min",
"sec"
};
int seconds = 0;
char name[6];
int count = 0;
int i = 0;
// finding biggest match
for(i = 0; i<7; i++){
seconds = times[i];
strcpy(name,names[i]);
count = floor(agoTime/seconds);
if(count != 0){
break;
}
}
if(count == 1){
str_format(aBuf, sizeof(aBuf), "%d %s", 1 , name);
}else{
str_format(aBuf, sizeof(aBuf), "%d %ss", count , name);
}
strcat(agoString,aBuf);
if (i + 1 < 7) {
// getting second piece now
int seconds2 = times[i+1];
char name2[6];
strcpy(name2,names[i+1]);
// add second piece if it's greater than 0
int count2 = floor((agoTime - (seconds * count)) / seconds2);
if (count2 != 0) {
if(count2 == 1){
str_format(aBuf, sizeof(aBuf), " and %d %s", 1 , name2);
}else{
str_format(aBuf, sizeof(aBuf), " and %d %ss", count2 , name2);
}
strcat(agoString,aBuf);
}
}
}
void CSqlScore::ShowRank(int ClientID, const char* pName, bool Search)
{
CSqlScoreData *Tmp = new CSqlScoreData();
@ -398,7 +460,7 @@ void CSqlScore::ShowRank(int ClientID, const char* pName, bool Search)
Tmp->m_Search = Search;
str_format(Tmp->m_aRequestingPlayer, sizeof(Tmp->m_aRequestingPlayer), " (%s)", Server()->ClientName(ClientID));
Tmp->m_pSqlData = this;
void *RankThread = thread_create(ShowRankThread, Tmp);
#if defined(CONF_FAMILY_UNIX)
pthread_detach((pthread_t)RankThread);
@ -408,9 +470,9 @@ void CSqlScore::ShowRank(int ClientID, const char* pName, bool Search)
void CSqlScore::ShowTop5Thread(void *pUser)
{
lock_wait(gs_SqlLock);
CSqlScoreData *pData = (CSqlScoreData *)pUser;
// Connect to database
if(pData->m_pSqlData->Connect())
{
@ -418,41 +480,41 @@ void CSqlScore::ShowTop5Thread(void *pUser)
{
// check sort methode
char aBuf[512];
str_format(aBuf, sizeof(aBuf), "SELECT Name, Time FROM %s_%s_race ORDER BY `Time` ASC LIMIT %d, 5;", pData->m_pSqlData->m_pPrefix, pData->m_pSqlData->m_aMap, pData->m_Num-1);
str_format(aBuf, sizeof(aBuf), "SELECT Name, min(Time) as Time FROM %s_%s_race Group By Name ORDER BY `Time` ASC LIMIT %d, 5;", pData->m_pSqlData->m_pPrefix, pData->m_pSqlData->m_aMap, pData->m_Num-1);
pData->m_pSqlData->m_pResults = pData->m_pSqlData->m_pStatement->executeQuery(aBuf);
// show top5
pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, "----------- Top 5 -----------");
int Rank = pData->m_Num;
float Time = 0;
while(pData->m_pSqlData->m_pResults->next())
{
Time = (float)pData->m_pSqlData->m_pResults->getDouble("Time");
str_format(aBuf, sizeof(aBuf), "%d. %s Time: %d minute(s) %.2f second(s)", Rank, pData->m_pSqlData->m_pResults->getString("Name").c_str(), (int)(Time/60), Time-((int)Time/60*60));
str_format(aBuf, sizeof(aBuf), "%d. %s Time: %d minute(s) %.2f second(s)", Rank, pData->m_pSqlData->m_pResults->getString("Name").c_str(), (int)(Time/60), Time-((int)Time/60*60));
pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, aBuf);
Rank++;
}
pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, "------------------------------");
dbg_msg("SQL", "Showing top5 done");
// delete results and statement
delete pData->m_pSqlData->m_pResults;
delete pData->m_pSqlData->m_pStatement;
}
catch (sql::SQLException &e)
{
char aBuf[256];
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "MySQL Error: %s", e.what());
dbg_msg("SQL", aBuf);
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);
@ -464,7 +526,7 @@ void CSqlScore::ShowTop5(int ClientID, int Debut)
Tmp->m_Num = Debut;
Tmp->m_ClientID = ClientID;
Tmp->m_pSqlData = this;
void *Top5Thread = thread_create(ShowTop5Thread, Tmp);
#if defined(CONF_FAMILY_UNIX)
pthread_detach((pthread_t)Top5Thread);
@ -477,7 +539,7 @@ void CSqlScore::ClearString(char *pString)
{
char newString[MAX_NAME_LENGTH*2-1];
int pos = 0;
for(int i=0;i<str_length(pString);i++) {
if(pString[i] == '\\') {
newString[pos++] = '\\';
@ -492,15 +554,15 @@ void CSqlScore::ClearString(char *pString)
newString[pos++] = pString[i];
}
}
newString[pos] = '\0';
strcpy(pString,newString);
}
void CSqlScore::NormalizeMapname(char *pString) {
std::string validChars("abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789_");
for(int i=0;i<str_length(pString);i++) {
if(validChars.find(pString[i]) == std::string::npos) {
pString[i] = '_';

View file

@ -15,12 +15,12 @@ class CSqlScore : public IScore
{
CGameContext *m_pGameServer;
IServer *m_pServer;
sql::Driver *m_pDriver;
sql::Connection *m_pConnection;
sql::Statement *m_pStatement;
sql::ResultSet *m_pResults;
// copy of config vars
const char* m_pDatabase;
const char* m_pPrefix;
@ -29,34 +29,35 @@ class CSqlScore : public IScore
const char* m_pIp;
char m_aMap[64];
int m_Port;
CGameContext *GameServer() { return m_pGameServer; }
IServer *Server() { return m_pServer; }
static void LoadScoreThread(void *pUser);
static void SaveScoreThread(void *pUser);
static void ShowRankThread(void *pUser);
static void ShowTop5Thread(void *pUser);
void Init();
bool Connect();
void Disconnect();
// anti SQL injection
void ClearString(char *pString);
void NormalizeMapname(char *pString);
public:
CSqlScore(CGameContext *pGameServer);
~CSqlScore();
virtual void LoadScore(int ClientID);
virtual void SaveScore(int ClientID, float Time, CCharacter *pChar);
virtual void ShowRank(int ClientID, const char* pName, bool Search=false);
virtual void ShowTop5(int ClientID, int Debut=1);
static void agoTimeToString(int agoTime, char agoStrign[]);
};
struct CSqlScoreData