mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-19 14:38:18 +00:00
Add /map (for votes) and /mapinfo (instead of /mappoints)
This commit is contained in:
parent
434b2bec52
commit
a5f3de6827
|
@ -504,6 +504,37 @@ void CGameContext::ConDND(IConsole::IResult *pResult, void *pUserData)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CGameContext::ConMap(IConsole::IResult *pResult, void *pUserData)
|
||||||
|
{
|
||||||
|
CGameContext *pSelf = (CGameContext *) pUserData;
|
||||||
|
if (!CheckClientID(pResult->m_ClientID))
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (pResult->NumArguments() <= 0)
|
||||||
|
{
|
||||||
|
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "map", "Example: /map adr3 to call vote for Adrenaline 3");
|
||||||
|
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "map", "This means that the map name must start with 'a' and contain the characters 'd', 'r' and '3' in that order");
|
||||||
|
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;
|
||||||
|
|
||||||
|
pSelf->Score()->MapVote(pResult->m_ClientID, pResult->GetString(0));
|
||||||
|
|
||||||
|
#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::ConMapPoints(IConsole::IResult *pResult, void *pUserData)
|
void CGameContext::ConMapPoints(IConsole::IResult *pResult, void *pUserData)
|
||||||
{
|
{
|
||||||
CGameContext *pSelf = (CGameContext *) pUserData;
|
CGameContext *pSelf = (CGameContext *) pUserData;
|
||||||
|
|
|
@ -20,7 +20,8 @@ CHAT_COMMAND("converse", "r", CFGFLAG_CHAT|CFGFLAG_SERVER, ConConverse, this, "C
|
||||||
CHAT_COMMAND("pause", "", CFGFLAG_CHAT|CFGFLAG_SERVER, ConTogglePause, this, "Toggles pause (if not activated on the server, it toggles spec)")
|
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("spec", "", CFGFLAG_CHAT|CFGFLAG_SERVER, ConToggleSpec, this, "Toggles spec")
|
||||||
CHAT_COMMAND("dnd", "", CFGFLAG_CHAT|CFGFLAG_SERVER, ConDND, this, "Toggle Do Not Disturb (no chat and server messages)")
|
CHAT_COMMAND("dnd", "", CFGFLAG_CHAT|CFGFLAG_SERVER, ConDND, this, "Toggle Do Not Disturb (no chat and server messages)")
|
||||||
CHAT_COMMAND("mappoints", "?r", CFGFLAG_CHAT|CFGFLAG_SERVER, ConMapPoints, this, "Show how man points the map with name r gives (current map by default)")
|
CHAT_COMMAND("mapinfo", "?r", CFGFLAG_CHAT|CFGFLAG_SERVER, ConMapPoints, this, "Show info about the map with name r gives (current map by default)")
|
||||||
|
CHAT_COMMAND("map", "?r", CFGFLAG_CHAT|CFGFLAG_SERVER, ConMap, this, "Vote a map by name")
|
||||||
CHAT_COMMAND("rankteam", "?r", CFGFLAG_CHAT|CFGFLAG_SERVER, ConTeamRank, this, "Shows the team rank of player with name r (your team rank by default)")
|
CHAT_COMMAND("rankteam", "?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("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("rules", "", CFGFLAG_CHAT|CFGFLAG_SERVER, ConRules, this, "Shows the server rules")
|
||||||
|
|
|
@ -245,6 +245,22 @@ void CGameContext::CreateSoundGlobal(int Sound, int Target)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CGameContext::CallVote(int ClientID, const char *aDesc, const char *aCmd, const char *pReason, const char *aChatmsg)
|
||||||
|
{
|
||||||
|
// check if a vote is already running
|
||||||
|
if(m_VoteCloseTime)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int64 Now = Server()->Tick();
|
||||||
|
CPlayer *pPlayer = m_apPlayers[ClientID];
|
||||||
|
SendChat(-1, CGameContext::CHAT_ALL, aChatmsg);
|
||||||
|
StartVote(aDesc, aCmd, pReason);
|
||||||
|
pPlayer->m_Vote = 1;
|
||||||
|
pPlayer->m_VotePos = m_VotePos = 1;
|
||||||
|
m_VoteCreator = ClientID;
|
||||||
|
pPlayer->m_LastVoteCall = Now;
|
||||||
|
}
|
||||||
|
|
||||||
void CGameContext::SendChatTarget(int To, const char *pText)
|
void CGameContext::SendChatTarget(int To, const char *pText)
|
||||||
{
|
{
|
||||||
CNetMsg_Sv_Chat Msg;
|
CNetMsg_Sv_Chat Msg;
|
||||||
|
@ -354,10 +370,6 @@ void CGameContext::SendBroadcast(const char *pText, int ClientID)
|
||||||
//
|
//
|
||||||
void CGameContext::StartVote(const char *pDesc, const char *pCommand, const char *pReason)
|
void CGameContext::StartVote(const char *pDesc, const char *pCommand, const char *pReason)
|
||||||
{
|
{
|
||||||
// check if a vote is already running
|
|
||||||
if(m_VoteCloseTime)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// reset votes
|
// reset votes
|
||||||
m_VoteEnforce = VOTE_ENFORCE_UNKNOWN;
|
m_VoteEnforce = VOTE_ENFORCE_UNKNOWN;
|
||||||
m_VoteEnforcer = -1;
|
m_VoteEnforcer = -1;
|
||||||
|
@ -1135,14 +1147,7 @@ void CGameContext::OnMessage(int MsgID, CUnpacker *pUnpacker, int ClientID)
|
||||||
}
|
}
|
||||||
|
|
||||||
if(aCmd[0] && str_comp(aCmd,"info"))
|
if(aCmd[0] && str_comp(aCmd,"info"))
|
||||||
{
|
CallVote(ClientID, aDesc, aCmd, pReason, aChatmsg);
|
||||||
SendChat(-1, CGameContext::CHAT_ALL, aChatmsg);
|
|
||||||
StartVote(aDesc, aCmd, pReason);
|
|
||||||
pPlayer->m_Vote = 1;
|
|
||||||
pPlayer->m_VotePos = m_VotePos = 1;
|
|
||||||
m_VoteCreator = ClientID;
|
|
||||||
pPlayer->m_LastVoteCall = Now;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else if(MsgID == NETMSGTYPE_CL_VOTE)
|
else if(MsgID == NETMSGTYPE_CL_VOTE)
|
||||||
{
|
{
|
||||||
|
|
|
@ -148,6 +148,7 @@ public:
|
||||||
};
|
};
|
||||||
|
|
||||||
// network
|
// network
|
||||||
|
void CallVote(int ClientID, const char *aDesc, const char *aCmd, const char *pReason, const char *aChatmsg);
|
||||||
void SendChatTarget(int To, const char *pText);
|
void SendChatTarget(int To, const char *pText);
|
||||||
void SendChat(int ClientID, int Team, const char *pText, int SpamProtectionClientID = -1);
|
void SendChat(int ClientID, int Team, const char *pText, int SpamProtectionClientID = -1);
|
||||||
void SendEmoticon(int ClientID, int Emoticon);
|
void SendEmoticon(int ClientID, int Emoticon);
|
||||||
|
@ -251,6 +252,7 @@ private:
|
||||||
static void ConUTF8(IConsole::IResult *pResult, void *pUserData);
|
static void ConUTF8(IConsole::IResult *pResult, void *pUserData);
|
||||||
static void ConDND(IConsole::IResult *pResult, void *pUserData);
|
static void ConDND(IConsole::IResult *pResult, void *pUserData);
|
||||||
static void ConMapPoints(IConsole::IResult *pResult, void *pUserData);
|
static void ConMapPoints(IConsole::IResult *pResult, void *pUserData);
|
||||||
|
static void ConMap(IConsole::IResult *pResult, void *pUserData);
|
||||||
static void ConTeamRank(IConsole::IResult *pResult, void *pUserData);
|
static void ConTeamRank(IConsole::IResult *pResult, void *pUserData);
|
||||||
static void ConRank(IConsole::IResult *pResult, void *pUserData);
|
static void ConRank(IConsole::IResult *pResult, void *pUserData);
|
||||||
static void ConBroadTime(IConsole::IResult *pResult, void *pUserData);
|
static void ConBroadTime(IConsole::IResult *pResult, void *pUserData);
|
||||||
|
|
|
@ -44,6 +44,7 @@ public:
|
||||||
CPlayerData *PlayerData(int ID) { return &m_aPlayerData[ID]; }
|
CPlayerData *PlayerData(int ID) { return &m_aPlayerData[ID]; }
|
||||||
|
|
||||||
virtual void MapPoints(int ClientID, const char* MapName) = 0;
|
virtual void MapPoints(int ClientID, const char* MapName) = 0;
|
||||||
|
virtual void MapVote(int ClientID, const char* MapName) = 0;
|
||||||
virtual void LoadScore(int ClientID) = 0;
|
virtual void LoadScore(int ClientID) = 0;
|
||||||
virtual void SaveScore(int ClientID, float Time, float CpTime[NUM_CHECKPOINTS]) = 0;
|
virtual void SaveScore(int ClientID, float Time, float CpTime[NUM_CHECKPOINTS]) = 0;
|
||||||
|
|
||||||
|
|
|
@ -59,6 +59,11 @@ void CFileScore::MapPoints(int ClientID, const char* MapName)
|
||||||
// TODO: implement
|
// TODO: implement
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CFileScore::MapVote(int ClientID, const char* MapName)
|
||||||
|
{
|
||||||
|
// TODO: implement
|
||||||
|
}
|
||||||
|
|
||||||
void CFileScore::SaveScoreThread(void *pUser)
|
void CFileScore::SaveScoreThread(void *pUser)
|
||||||
{
|
{
|
||||||
CFileScore *pSelf = (CFileScore *) pUser;
|
CFileScore *pSelf = (CFileScore *) pUser;
|
||||||
|
|
|
@ -64,6 +64,7 @@ public:
|
||||||
|
|
||||||
virtual void LoadScore(int ClientID);
|
virtual void LoadScore(int ClientID);
|
||||||
virtual void MapPoints(int ClientID, const char* MapName);
|
virtual void MapPoints(int ClientID, const char* MapName);
|
||||||
|
virtual void MapVote(int ClientID, const char* MapName);
|
||||||
virtual void SaveScore(int ClientID, float Time,
|
virtual void SaveScore(int ClientID, float Time,
|
||||||
float CpTime[NUM_CHECKPOINTS]);
|
float CpTime[NUM_CHECKPOINTS]);
|
||||||
virtual void SaveTeamScore(int* ClientIDs, unsigned int Size, float Time);
|
virtual void SaveTeamScore(int* ClientIDs, unsigned int Size, float Time);
|
||||||
|
|
|
@ -394,6 +394,74 @@ void CSqlScore::SaveTeamScoreThread(void *pUser)
|
||||||
lock_release(gs_SqlLock);
|
lock_release(gs_SqlLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CSqlScore::MapVote(int ClientID, const char* MapName)
|
||||||
|
{
|
||||||
|
CSqlMapData *Tmp = new CSqlMapData();
|
||||||
|
Tmp->m_ClientID = ClientID;
|
||||||
|
str_copy(Tmp->m_aMap, MapName, 128);
|
||||||
|
Tmp->m_pSqlData = this;
|
||||||
|
|
||||||
|
void *VoteThread = thread_create(MapVoteThread, Tmp);
|
||||||
|
#if defined(CONF_FAMILY_UNIX)
|
||||||
|
pthread_detach((pthread_t)VoteThread);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
void CSqlScore::MapVoteThread(void *pUser)
|
||||||
|
{
|
||||||
|
lock_wait(gs_SqlLock);
|
||||||
|
|
||||||
|
CSqlMapData *pData = (CSqlMapData *)pUser;
|
||||||
|
|
||||||
|
// Connect to database
|
||||||
|
if(pData->m_pSqlData->Connect())
|
||||||
|
{
|
||||||
|
char originalMap[128];
|
||||||
|
strcpy(originalMap,pData->m_aMap);
|
||||||
|
pData->m_pSqlData->ClearString(pData->m_aMap);
|
||||||
|
pData->m_pSqlData->FuzzyString(pData->m_aMap);
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
char aBuf[768];
|
||||||
|
str_format(aBuf, sizeof(aBuf), "SELECT Map, Server FROM %s_maps WHERE Map LIKE '%s' COLLATE utf8_general_ci ORDER BY LENGTH(Map), Map LIMIT 1;", pData->m_pSqlData->m_pPrefix, pData->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), "No map like \"%s\" found.", originalMap);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
pData->m_pSqlData->m_pResults->next();
|
||||||
|
char aMap[128];
|
||||||
|
strcpy(aMap, pData->m_pSqlData->m_pResults->getString("Map").c_str());
|
||||||
|
char aServer[32];
|
||||||
|
strcpy(aServer, pData->m_pSqlData->m_pResults->getString("Server").c_str());
|
||||||
|
char aCmd[256];
|
||||||
|
str_format(aCmd, sizeof(aCmd), "sv_reset_file types/%s/flexreset.cfg; change_map %s", aServer, aMap);
|
||||||
|
char aChatmsg[512];
|
||||||
|
str_format(aChatmsg, sizeof(aChatmsg), "'%s' called vote to change server option '%s' (%s)", pData->m_pSqlData->GameServer()->Server()->ClientName(pData->m_ClientID), aMap, "/map");
|
||||||
|
pData->m_pSqlData->GameServer()->CallVote(pData->m_ClientID, aMap, aCmd, "/map", aChatmsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
delete pData->m_pSqlData->m_pResults;
|
||||||
|
}
|
||||||
|
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");
|
||||||
|
}
|
||||||
|
|
||||||
|
pData->m_pSqlData->Disconnect();
|
||||||
|
}
|
||||||
|
|
||||||
|
delete pData;
|
||||||
|
lock_release(gs_SqlLock);
|
||||||
|
}
|
||||||
|
|
||||||
void CSqlScore::MapPoints(int ClientID, const char* MapName)
|
void CSqlScore::MapPoints(int ClientID, const char* MapName)
|
||||||
{
|
{
|
||||||
CSqlMapData *Tmp = new CSqlMapData();
|
CSqlMapData *Tmp = new CSqlMapData();
|
||||||
|
@ -401,9 +469,9 @@ void CSqlScore::MapPoints(int ClientID, const char* MapName)
|
||||||
str_copy(Tmp->m_aMap, MapName, 128);
|
str_copy(Tmp->m_aMap, MapName, 128);
|
||||||
Tmp->m_pSqlData = this;
|
Tmp->m_pSqlData = this;
|
||||||
|
|
||||||
void *PointsThread = thread_create(MapPointsThread, Tmp);
|
void *InfoThread = thread_create(MapPointsThread, Tmp);
|
||||||
#if defined(CONF_FAMILY_UNIX)
|
#if defined(CONF_FAMILY_UNIX)
|
||||||
pthread_detach((pthread_t)PointsThread);
|
pthread_detach((pthread_t)InfoThread);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -419,22 +487,28 @@ void CSqlScore::MapPointsThread(void *pUser)
|
||||||
char originalMap[128];
|
char originalMap[128];
|
||||||
strcpy(originalMap,pData->m_aMap);
|
strcpy(originalMap,pData->m_aMap);
|
||||||
pData->m_pSqlData->ClearString(pData->m_aMap);
|
pData->m_pSqlData->ClearString(pData->m_aMap);
|
||||||
|
pData->m_pSqlData->FuzzyString(pData->m_aMap);
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
char aBuf[768];
|
char aBuf[768];
|
||||||
str_format(aBuf, sizeof(aBuf), "SELECT Points FROM %s_maps WHERE Map ='%s'", pData->m_pSqlData->m_pPrefix, pData->m_aMap);
|
str_format(aBuf, sizeof(aBuf), "SELECT Map, Server, Points FROM %s_maps WHERE Map LIKE '%s' COLLATE utf8_general_ci ORDER BY LENGTH(Map), Map LIMIT 1;", pData->m_pSqlData->m_pPrefix, pData->m_aMap);
|
||||||
pData->m_pSqlData->m_pResults = pData->m_pSqlData->m_pStatement->executeQuery(aBuf);
|
pData->m_pSqlData->m_pResults = pData->m_pSqlData->m_pStatement->executeQuery(aBuf);
|
||||||
|
|
||||||
if(pData->m_pSqlData->m_pResults->rowsCount() != 1)
|
if(pData->m_pSqlData->m_pResults->rowsCount() != 1)
|
||||||
{
|
{
|
||||||
str_format(aBuf, sizeof(aBuf), "No map called \"%s\" found.", originalMap);
|
str_format(aBuf, sizeof(aBuf), "No map like \"%s\" found.", originalMap);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
pData->m_pSqlData->m_pResults->next();
|
pData->m_pSqlData->m_pResults->next();
|
||||||
int points = (int)pData->m_pSqlData->m_pResults->getInt("Points");
|
int points = (int)pData->m_pSqlData->m_pResults->getInt("Points");
|
||||||
str_format(aBuf, sizeof(aBuf), "Finishing \"%s\" will give you %d points.", originalMap, points);
|
char aMap[128];
|
||||||
|
strcpy(aMap, pData->m_pSqlData->m_pResults->getString("Map").c_str());
|
||||||
|
char aServer[32];
|
||||||
|
strcpy(aServer, pData->m_pSqlData->m_pResults->getString("Server").c_str());
|
||||||
|
aServer[0] = toupper(aServer[0]);
|
||||||
|
str_format(aBuf, sizeof(aBuf), "\"%s\" on %s (%d points)", aMap, aServer, points);
|
||||||
}
|
}
|
||||||
|
|
||||||
pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, aBuf);
|
pData->m_pSqlData->GameServer()->SendChatTarget(pData->m_ClientID, aBuf);
|
||||||
|
@ -1055,8 +1129,25 @@ void CSqlScore::ShowTimes(int ClientID, const char* pName, int Debut)
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
// anti SQL injection
|
void CSqlScore::FuzzyString(char *pString)
|
||||||
|
{
|
||||||
|
char newString[32*4-1];
|
||||||
|
int pos = 0;
|
||||||
|
|
||||||
|
for(int i=0;i<64;i++)
|
||||||
|
{
|
||||||
|
if(!pString[i])
|
||||||
|
break;
|
||||||
|
|
||||||
|
newString[pos++] = pString[i];
|
||||||
|
newString[pos++] = '%';
|
||||||
|
}
|
||||||
|
|
||||||
|
newString[pos] = '\0';
|
||||||
|
strcpy(pString, newString);
|
||||||
|
}
|
||||||
|
|
||||||
|
// anti SQL injection
|
||||||
void CSqlScore::ClearString(char *pString)
|
void CSqlScore::ClearString(char *pString)
|
||||||
{
|
{
|
||||||
char newString[32*2-1];
|
char newString[32*2-1];
|
||||||
|
|
|
@ -41,6 +41,7 @@ class CSqlScore: public IScore
|
||||||
}
|
}
|
||||||
|
|
||||||
static void MapPointsThread(void *pUser);
|
static void MapPointsThread(void *pUser);
|
||||||
|
static void MapVoteThread(void *pUser);
|
||||||
static void LoadScoreThread(void *pUser);
|
static void LoadScoreThread(void *pUser);
|
||||||
static void SaveScoreThread(void *pUser);
|
static void SaveScoreThread(void *pUser);
|
||||||
static void SaveTeamScoreThread(void *pUser);
|
static void SaveTeamScoreThread(void *pUser);
|
||||||
|
@ -57,6 +58,7 @@ class CSqlScore: public IScore
|
||||||
bool Connect();
|
bool Connect();
|
||||||
void Disconnect();
|
void Disconnect();
|
||||||
|
|
||||||
|
void FuzzyString(char *pString);
|
||||||
// anti SQL injection
|
// anti SQL injection
|
||||||
void ClearString(char *pString);
|
void ClearString(char *pString);
|
||||||
|
|
||||||
|
@ -69,6 +71,7 @@ public:
|
||||||
|
|
||||||
virtual void LoadScore(int ClientID);
|
virtual void LoadScore(int ClientID);
|
||||||
virtual void MapPoints(int ClientID, const char* MapName);
|
virtual void MapPoints(int ClientID, const char* MapName);
|
||||||
|
virtual void MapVote(int ClientID, const char* MapName);
|
||||||
virtual void SaveScore(int ClientID, float Time,
|
virtual void SaveScore(int ClientID, float Time,
|
||||||
float CpTime[NUM_CHECKPOINTS]);
|
float CpTime[NUM_CHECKPOINTS]);
|
||||||
virtual void SaveTeamScore(int* aClientIDs, unsigned int Size, float Time);
|
virtual void SaveTeamScore(int* aClientIDs, unsigned int Size, float Time);
|
||||||
|
|
Loading…
Reference in a new issue