Overhauled job system

The engine now takes `std::shared_ptr<IJob>`, this will ensure the
appropriate lifetime of the given parameters, it also allows for proper
destruction. Remove the now obsolete `IFetcher` interface and `CFetcher`
class.

Also adds some locks to `CUpdater`, previously it didn't have any locks
at all.
This commit is contained in:
heinrich5991 2017-11-23 15:47:38 +01:00
parent add0b88976
commit 94acac91a0
19 changed files with 379 additions and 387 deletions

View file

@ -1506,7 +1506,7 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket)
char aEscaped[128];
str_format(aFilename, sizeof(aFilename), "%s_%08x.map", pMap, MapCrc);
Fetcher()->Escape(aEscaped, sizeof(aEscaped), aFilename);
EscapeUrl(aEscaped, sizeof(aEscaped), aFilename);
str_format(aUrl, sizeof(aUrl), "%s/", g_Config.m_ClDDNetMapDownloadUrl);
// We only trust our own custom-selected CAs for our own servers.
@ -1518,7 +1518,8 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket)
str_append(aUrl, aEscaped, sizeof(aUrl));
m_pMapdownloadTask = Fetcher()->FetchFile(aUrl, m_aMapdownloadFilename, IStorage::TYPE_SAVE, UseDDNetCA, true);
m_pMapdownloadTask = std::make_shared<CFetchTask>(Storage(), aUrl, m_aMapdownloadFilename, IStorage::TYPE_SAVE, UseDDNetCA, true);
Engine()->AddJob(m_pMapdownloadTask);
}
else
SendMapRequest();
@ -2089,7 +2090,6 @@ void CClient::ResetMapDownload()
if(m_pMapdownloadTask)
{
m_pMapdownloadTask->Abort();
m_pMapdownloadTask->Destroy();
m_pMapdownloadTask = NULL;
}
m_MapdownloadFile = 0;
@ -2135,7 +2135,6 @@ void CClient::ResetDDNetInfo()
if(m_pDDNetInfoTask)
{
m_pDDNetInfoTask->Abort();
m_pDDNetInfoTask->Destroy();
m_pDDNetInfoTask = NULL;
}
}
@ -2476,33 +2475,31 @@ void CClient::Update()
if(m_pMapdownloadTask)
{
if(m_pMapdownloadTask->State() == IFetchTask::STATE_DONE)
if(m_pMapdownloadTask->State() == CFetchTask::STATE_DONE)
FinishMapDownload();
else if(m_pMapdownloadTask->State() == IFetchTask::STATE_ERROR)
else if(m_pMapdownloadTask->State() == CFetchTask::STATE_ERROR)
{
dbg_msg("webdl", "http failed, falling back to gameserver");
ResetMapDownload();
SendMapRequest();
}
else if(m_pMapdownloadTask->State() == IFetchTask::STATE_ABORTED)
else if(m_pMapdownloadTask->State() == CFetchTask::STATE_ABORTED)
{
m_pMapdownloadTask->Destroy();
m_pMapdownloadTask = NULL;
}
}
if(m_pDDNetInfoTask)
{
if(m_pDDNetInfoTask->State() == IFetchTask::STATE_DONE)
if(m_pDDNetInfoTask->State() == CFetchTask::STATE_DONE)
FinishDDNetInfo();
else if(m_pDDNetInfoTask->State() == IFetchTask::STATE_ERROR)
else if(m_pDDNetInfoTask->State() == CFetchTask::STATE_ERROR)
{
dbg_msg("ddnet-info", "download failed");
ResetDDNetInfo();
}
else if(m_pDDNetInfoTask->State() == IFetchTask::STATE_ABORTED)
else if(m_pDDNetInfoTask->State() == CFetchTask::STATE_ABORTED)
{
m_pDDNetInfoTask->Destroy();
m_pDDNetInfoTask = NULL;
}
}
@ -2532,7 +2529,6 @@ void CClient::RegisterInterfaces()
Kernel()->RegisterInterface(static_cast<IGhostRecorder*>(&m_GhostRecorder), false);
Kernel()->RegisterInterface(static_cast<IGhostLoader*>(&m_GhostLoader), false);
Kernel()->RegisterInterface(static_cast<IServerBrowser*>(&m_ServerBrowser), false);
Kernel()->RegisterInterface(static_cast<IFetcher*>(&m_Fetcher), false);
#if !defined(CONF_PLATFORM_MACOSX) && !defined(__ANDROID__)
Kernel()->RegisterInterface(static_cast<IUpdater*>(&m_Updater), false);
#endif
@ -2551,7 +2547,6 @@ void CClient::InitInterfaces()
m_pInput = Kernel()->RequestInterface<IEngineInput>();
m_pMap = Kernel()->RequestInterface<IEngineMap>();
m_pMasterServer = Kernel()->RequestInterface<IEngineMasterServer>();
m_pFetcher = Kernel()->RequestInterface<IFetcher>();
#if !defined(CONF_PLATFORM_MACOSX) && !defined(__ANDROID__)
m_pUpdater = Kernel()->RequestInterface<IUpdater>();
#endif
@ -2561,7 +2556,7 @@ void CClient::InitInterfaces()
m_ServerBrowser.SetBaseInfo(&m_NetClient[2], m_pGameClient->NetVersion());
m_Fetcher.Init();
FetcherInit();
#if !defined(CONF_PLATFORM_MACOSX) && !defined(__ANDROID__)
m_Updater.Init();
@ -3632,15 +3627,13 @@ void CClient::RequestDDNetInfo()
if(g_Config.m_BrIndicateFinished)
{
char aEscaped[128];
Fetcher()->Escape(aEscaped, sizeof(aEscaped), g_Config.m_PlayerName);
EscapeUrl(aEscaped, sizeof(aEscaped), g_Config.m_PlayerName);
str_append(aUrl, "?name=", sizeof(aUrl));
str_append(aUrl, aEscaped, sizeof(aUrl));
}
if(m_pDDNetInfoTask)
m_pDDNetInfoTask->Destroy();
m_pDDNetInfoTask = Fetcher()->FetchFile(aUrl, "ddnet-info.json.tmp", IStorage::TYPE_SAVE, true, true);
m_pDDNetInfoTask = std::make_shared<CFetchTask>(Storage(), aUrl, "ddnet-info.json.tmp", IStorage::TYPE_SAVE, true, true);
Engine()->AddJob(m_pDDNetInfoTask);
}
int CClient::GetPredictionTime()

View file

@ -3,6 +3,10 @@
#ifndef ENGINE_CLIENT_CLIENT_H
#define ENGINE_CLIENT_CLIENT_H
#include <memory>
#include "fetcher.h"
class CGraph
{
public:
@ -61,7 +65,6 @@ class CClient : public IClient, public CDemoPlayer::IListener
IEngineMap *m_pMap;
IConsole *m_pConsole;
IStorage *m_pStorage;
IFetcher *m_pFetcher;
IUpdater *m_pUpdater;
IEngineMasterServer *m_pMasterServer;
@ -78,7 +81,6 @@ class CClient : public IClient, public CDemoPlayer::IListener
class CGhostRecorder m_GhostRecorder;
class CGhostLoader m_GhostLoader;
class CServerBrowser m_ServerBrowser;
class CFetcher m_Fetcher;
class CUpdater m_Updater;
class CFriends m_Friends;
class CFriends m_Foes;
@ -128,7 +130,7 @@ class CClient : public IClient, public CDemoPlayer::IListener
char m_aCmdConnect[256];
// map download
IFetchTask *m_pMapdownloadTask;
std::shared_ptr<CFetchTask> m_pMapdownloadTask;
char m_aMapdownloadFilename[256];
char m_aMapdownloadName[256];
IOHANDLE m_MapdownloadFile;
@ -137,7 +139,7 @@ class CClient : public IClient, public CDemoPlayer::IListener
int m_MapdownloadAmount;
int m_MapdownloadTotalsize;
IFetchTask *m_pDDNetInfoTask;
std::shared_ptr<CFetchTask> m_pDDNetInfoTask;
// time
CSmoothTime m_GameTime[2];
@ -209,7 +211,6 @@ public:
IGameClient *GameClient() { return m_pGameClient; }
IEngineMasterServer *MasterServer() { return m_pMasterServer; }
IStorage *Storage() { return m_pStorage; }
IFetcher *Fetcher() { return m_pFetcher; }
IUpdater *Updater() { return m_pUpdater; }
CClient();
@ -302,7 +303,6 @@ public:
void FinishDDNetInfo();
void LoadDDNetInfo();
virtual IFetchTask *MapDownloadTask() { return m_pMapdownloadTask; }
virtual const char *MapDownloadName() { return m_aMapdownloadName; }
virtual int MapDownloadAmount() { return !m_pMapdownloadTask ? m_MapdownloadAmount : (int)m_pMapdownloadTask->Current(); }
virtual int MapDownloadTotalsize() { return !m_pMapdownloadTask ? m_MapdownloadTotalsize : (int)m_pMapdownloadTask->Size(); }

View file

@ -10,136 +10,55 @@
#include "fetcher.h"
class CFetchTask : public IFetchTask
double CFetchTask::Current() const { return m_Current; }
double CFetchTask::Size() const { return m_Size; }
int CFetchTask::Progress() const { return m_Progress; }
int CFetchTask::State() const { return m_State; }
const char *CFetchTask::Dest() const { return m_aDest; }
void CFetchTask::Abort() { m_Abort = true; };
CFetchTask::CFetchTask(IStorage *pStorage, const char *pUrl, const char *pDest, int StorageType, bool UseDDNetCA, bool CanTimeout) :
m_pStorage(pStorage),
m_StorageType(StorageType),
m_UseDDNetCA(UseDDNetCA),
m_CanTimeout(CanTimeout),
m_Size(0),
m_Progress(0),
m_State(CFetchTask::STATE_QUEUED),
m_Abort(false)
{
friend class CFetcher;
class CFetcher *m_pFetcher;
CURL *m_pHandle;
void *m_pUser;
char m_aUrl[256];
char m_aDest[128];
int m_StorageType;
bool m_UseDDNetCA;
bool m_CanTimeout;
PROGFUNC m_pfnProgressCallback;
COMPFUNC m_pfnCompCallback;
double m_Size;
double m_Current;
int m_Progress;
int m_State;
LOCK m_Lock;
bool m_Abort;
bool m_Destroy;
bool m_PastCB;
public:
virtual double Current() { return m_Current; }
virtual double Size() { return m_Size; }
virtual int Progress() { return m_Progress; }
virtual int State() { return m_State; }
virtual const char *Dest() { return m_aDest; }
virtual void Abort() { m_Abort = true; };
virtual void Destroy();
};
void CFetchTask::Destroy()
{
lock_wait(m_Lock);
if(m_PastCB)
{
lock_destroy(m_Lock);
delete this;
}
else
{
m_Abort = true;
m_Destroy = true;
lock_unlock(m_Lock);
}
str_copy(m_aUrl, pUrl, sizeof(m_aUrl));
str_copy(m_aDest, pDest, sizeof(m_aDest));
}
bool CFetcher::Init()
bool FetcherInit()
{
m_pStorage = Kernel()->RequestInterface<IStorage>();
m_pEngine = Kernel()->RequestInterface<IEngine>();
if(curl_global_init(CURL_GLOBAL_DEFAULT))
return false;
return true;
return !curl_global_init(CURL_GLOBAL_DEFAULT);
}
void CFetcher::Escape(char *pBuf, size_t size, const char *pStr)
void EscapeUrl(char *pBuf, int Size, const char *pStr)
{
char *pEsc = curl_easy_escape(0, pStr, 0);
str_copy(pBuf, pEsc, size);
str_copy(pBuf, pEsc, Size);
curl_free(pEsc);
}
void CFetcher::DestroyCallback(CJob *pJob, void *pUser)
void CFetchTask::Run()
{
CFetchTask *pTask = (CFetchTask *)pUser;
delete pJob;
lock_wait(pTask->m_Lock);
if(pTask->m_Destroy)
CURL *pHandle = curl_easy_init();
if(!pHandle)
{
lock_destroy(pTask->m_Lock);
delete pTask;
m_State = STATE_ERROR;
return;
}
else
{
pTask->m_PastCB = true;
}
lock_unlock(pTask->m_Lock);
}
IFetchTask *CFetcher::FetchFile(const char *pUrl, const char *pDest, int StorageType, bool UseDDNetCA, bool CanTimeout, void *pUser, COMPFUNC pfnCompCb, PROGFUNC pfnProgCb)
{
CFetchTask *pTask = new CFetchTask;
pTask->m_pFetcher = this;
str_copy(pTask->m_aUrl, pUrl, sizeof(pTask->m_aUrl));
str_copy(pTask->m_aDest, pDest, sizeof(pTask->m_aDest));
pTask->m_StorageType = StorageType;
pTask->m_pUser = pUser;
pTask->m_pfnCompCallback = pfnCompCb;
pTask->m_pfnProgressCallback = pfnProgCb;
pTask->m_UseDDNetCA = UseDDNetCA;
pTask->m_CanTimeout = CanTimeout;
pTask->m_Lock = lock_create();
pTask->m_Abort = false;
pTask->m_Destroy = false;
pTask->m_PastCB = false;
pTask->m_Size = pTask->m_Progress = 0;
pTask->m_State = IFetchTask::STATE_QUEUED;
CJob *pJob = new CJob;
m_pEngine->AddJob(pJob, FetcherThread, pTask, DestroyCallback);
return pTask;
}
int CFetcher::FetcherThread(void *pUser)
{
CFetchTask *pTask = (CFetchTask *)pUser;
pTask->m_pHandle = curl_easy_init();
if(!pTask->m_pHandle)
return 1;
char aPath[512];
if(pTask->m_StorageType == -2)
pTask->m_pFetcher->m_pStorage->GetBinaryPath(pTask->m_aDest, aPath, sizeof(aPath));
if(m_StorageType == -2)
m_pStorage->GetBinaryPath(m_aDest, aPath, sizeof(aPath));
else
pTask->m_pFetcher->m_pStorage->GetCompletePath(pTask->m_StorageType, pTask->m_aDest, aPath, sizeof(aPath));
m_pStorage->GetCompletePath(m_StorageType, m_aDest, aPath, sizeof(aPath));
if(fs_makedir_rec_for(aPath) < 0)
dbg_msg("fetcher", "i/o error, cannot create folder for: %s", aPath);
@ -148,80 +67,76 @@ int CFetcher::FetcherThread(void *pUser)
if(!File)
{
dbg_msg("fetcher", "i/o error, cannot open file: %s", pTask->m_aDest);
pTask->m_State = IFetchTask::STATE_ERROR;
return 1;
dbg_msg("fetcher", "i/o error, cannot open file: %s", m_aDest);
m_State = CFetchTask::STATE_ERROR;
return;
}
char aErr[CURL_ERROR_SIZE];
curl_easy_setopt(pTask->m_pHandle, CURLOPT_ERRORBUFFER, aErr);
curl_easy_setopt(pHandle, CURLOPT_ERRORBUFFER, aErr);
//curl_easy_setopt(pTask->m_pHandle, CURLOPT_VERBOSE, 1L);
if(pTask->m_CanTimeout)
//curl_easy_setopt(pHandle, CURLOPT_VERBOSE, 1L);
if(m_CanTimeout)
{
curl_easy_setopt(pTask->m_pHandle, CURLOPT_CONNECTTIMEOUT_MS, (long)g_Config.m_ClHTTPConnectTimeoutMs);
curl_easy_setopt(pTask->m_pHandle, CURLOPT_LOW_SPEED_LIMIT, (long)g_Config.m_ClHTTPLowSpeedLimit);
curl_easy_setopt(pTask->m_pHandle, CURLOPT_LOW_SPEED_TIME, (long)g_Config.m_ClHTTPLowSpeedTime);
curl_easy_setopt(pHandle, CURLOPT_CONNECTTIMEOUT_MS, (long)g_Config.m_ClHTTPConnectTimeoutMs);
curl_easy_setopt(pHandle, CURLOPT_LOW_SPEED_LIMIT, (long)g_Config.m_ClHTTPLowSpeedLimit);
curl_easy_setopt(pHandle, CURLOPT_LOW_SPEED_TIME, (long)g_Config.m_ClHTTPLowSpeedTime);
}
else
{
curl_easy_setopt(pTask->m_pHandle, CURLOPT_CONNECTTIMEOUT_MS, 0);
curl_easy_setopt(pTask->m_pHandle, CURLOPT_LOW_SPEED_LIMIT, 0);
curl_easy_setopt(pTask->m_pHandle, CURLOPT_LOW_SPEED_TIME, 0);
curl_easy_setopt(pHandle, CURLOPT_CONNECTTIMEOUT_MS, 0);
curl_easy_setopt(pHandle, CURLOPT_LOW_SPEED_LIMIT, 0);
curl_easy_setopt(pHandle, CURLOPT_LOW_SPEED_TIME, 0);
}
curl_easy_setopt(pTask->m_pHandle, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(pTask->m_pHandle, CURLOPT_MAXREDIRS, 4L);
curl_easy_setopt(pTask->m_pHandle, CURLOPT_FAILONERROR, 1L);
if(pTask->m_UseDDNetCA)
curl_easy_setopt(pHandle, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(pHandle, CURLOPT_MAXREDIRS, 4L);
curl_easy_setopt(pHandle, CURLOPT_FAILONERROR, 1L);
if(m_UseDDNetCA)
{
char aCAFile[512];
pTask->m_pFetcher->m_pStorage->GetBinaryPath("data/ca-ddnet.pem", aCAFile, sizeof aCAFile);
curl_easy_setopt(pTask->m_pHandle, CURLOPT_CAINFO, aCAFile);
m_pStorage->GetBinaryPath("data/ca-ddnet.pem", aCAFile, sizeof aCAFile);
curl_easy_setopt(pHandle, CURLOPT_CAINFO, aCAFile);
}
curl_easy_setopt(pTask->m_pHandle, CURLOPT_URL, pTask->m_aUrl);
curl_easy_setopt(pTask->m_pHandle, CURLOPT_WRITEDATA, File);
curl_easy_setopt(pTask->m_pHandle, CURLOPT_WRITEFUNCTION, &CFetcher::WriteToFile);
curl_easy_setopt(pTask->m_pHandle, CURLOPT_NOPROGRESS, 0);
curl_easy_setopt(pTask->m_pHandle, CURLOPT_PROGRESSDATA, pTask);
curl_easy_setopt(pTask->m_pHandle, CURLOPT_PROGRESSFUNCTION, &CFetcher::ProgressCallback);
curl_easy_setopt(pTask->m_pHandle, CURLOPT_NOSIGNAL, 1L);
curl_easy_setopt(pTask->m_pHandle, CURLOPT_USERAGENT, "DDNet " GAME_RELEASE_VERSION " (" CONF_PLATFORM_STRING "; " CONF_ARCH_STRING ")");
curl_easy_setopt(pHandle, CURLOPT_URL, m_aUrl);
curl_easy_setopt(pHandle, CURLOPT_WRITEDATA, File);
curl_easy_setopt(pHandle, CURLOPT_WRITEFUNCTION, WriteCallback);
curl_easy_setopt(pHandle, CURLOPT_NOPROGRESS, 0);
curl_easy_setopt(pHandle, CURLOPT_PROGRESSDATA, this);
curl_easy_setopt(pHandle, CURLOPT_PROGRESSFUNCTION, ProgressCallback);
curl_easy_setopt(pHandle, CURLOPT_NOSIGNAL, 1L);
curl_easy_setopt(pHandle, CURLOPT_USERAGENT, "DDNet " GAME_RELEASE_VERSION " (" CONF_PLATFORM_STRING "; " CONF_ARCH_STRING ")");
dbg_msg("fetcher", "downloading %s", pTask->m_aDest);
pTask->m_State = IFetchTask::STATE_RUNNING;
int ret = curl_easy_perform(pTask->m_pHandle);
dbg_msg("fetcher", "downloading %s", m_aDest);
m_State = CFetchTask::STATE_RUNNING;
int Ret = curl_easy_perform(pHandle);
io_close(File);
if(ret != CURLE_OK)
if(Ret != CURLE_OK)
{
dbg_msg("fetcher", "task failed. libcurl error: %s", aErr);
pTask->m_State = (ret == CURLE_ABORTED_BY_CALLBACK) ? IFetchTask::STATE_ABORTED : IFetchTask::STATE_ERROR;
m_State = (Ret == CURLE_ABORTED_BY_CALLBACK) ? CFetchTask::STATE_ABORTED : CFetchTask::STATE_ERROR;
}
else
{
dbg_msg("fetcher", "task done %s", pTask->m_aDest);
pTask->m_State = IFetchTask::STATE_DONE;
dbg_msg("fetcher", "task done %s", m_aDest);
m_State = CFetchTask::STATE_DONE;
}
curl_easy_cleanup(pTask->m_pHandle);
curl_easy_cleanup(pHandle);
if(pTask->m_pfnCompCallback)
pTask->m_pfnCompCallback(pTask, pTask->m_pUser);
return(ret != CURLE_OK) ? 1 : 0;
OnCompletion();
}
size_t CFetcher::WriteToFile(char *pData, size_t size, size_t nmemb, void *pFile)
size_t CFetchTask::WriteCallback(char *pData, size_t Size, size_t Number, void *pFile)
{
return io_write((IOHANDLE)pFile, pData, size*nmemb);
return io_write((IOHANDLE)pFile, pData, Size * Number);
}
int CFetcher::ProgressCallback(void *pUser, double DlTotal, double DlCurr, double UlTotal, double UlCurr)
int CFetchTask::ProgressCallback(void *pUser, double DlTotal, double DlCurr, double UlTotal, double UlCurr)
{
CFetchTask *pTask = (CFetchTask *)pUser;
pTask->m_Current = DlCurr;
pTask->m_Size = DlTotal;
pTask->m_Progress = (100 * DlCurr) / (DlTotal ? DlTotal : 1);
if(pTask->m_pfnProgressCallback)
pTask->m_pfnProgressCallback(pTask, pTask->m_pUser);
pTask->OnProgress();
return pTask->m_Abort ? -1 : 0;
}

View file

@ -1,24 +1,56 @@
#ifndef ENGINE_CLIENT_FETCHER_H
#define ENGINE_CLIENT_FETCHER_H
#include <engine/fetcher.h>
#include <engine/shared/jobs.h>
#include <engine/storage.h>
#include <engine/kernel.h>
class CFetcher : public IFetcher
class CFetchTask : public IJob
{
private:
class IEngine *m_pEngine;
class IStorage *m_pStorage;
IStorage *m_pStorage;
char m_aUrl[256];
char m_aDest[128];
int m_StorageType;
bool m_UseDDNetCA;
bool m_CanTimeout;
double m_Size;
double m_Current;
int m_Progress;
int m_State;
std::atomic<bool> m_Abort;
virtual void OnProgress() { }
virtual void OnCompletion() { }
static int ProgressCallback(void *pUser, double DlTotal, double DlCurr, double UlTotal, double UlCurr);
static size_t WriteCallback(char *pData, size_t Size, size_t Number, void *pFile);
void Run();
public:
virtual bool Init();
enum
{
STATE_ERROR = -1,
STATE_QUEUED,
STATE_RUNNING,
STATE_DONE,
STATE_ABORTED,
};
virtual IFetchTask *FetchFile(const char *pUrl, const char *pDest, int StorageType = -2, bool UseDDNetCA = false, bool CanTimeout = true, void *pUser = 0, COMPFUNC pfnCompCb = 0, PROGFUNC pfnProgCb = 0);
virtual void Escape(char *pBud, size_t size, const char *pStr);
CFetchTask(IStorage *pStorage, const char *pUrl, const char *pDest, int StorageType = -2, bool UseDDNetCA = false, bool CanTimeout = true);
static void DestroyCallback(CJob *pJob, void *pUser);
static int FetcherThread(void *pUser);
static size_t WriteToFile(char *pData, size_t size, size_t nmemb, void *pFile);
static int ProgressCallback(void *pUser, double DlTotal, double DlCurr, double UlTotal, double UlCurr);
double Current() const;
double Size() const;
int Progress() const;
int State() const;
const char *Dest() const;
void Abort();
};
bool FetcherInit();
void EscapeUrl(char *pBud, int Size, const char *pStr);
#endif

View file

@ -1,6 +1,6 @@
#include "updater.h"
#include <base/system.h>
#include <engine/fetcher.h>
#include <engine/engine.h>
#include <engine/storage.h>
#include <engine/client.h>
#include <engine/external/json-parser/json.h>
@ -11,63 +11,128 @@
using std::string;
using std::map;
class CUpdaterFetchTask : public CFetchTask
{
char m_aBuf[256];
char m_aBuf2[256];
CUpdater *m_pUpdater;
void OnCompletion();
void OnProgress();
public:
CUpdaterFetchTask(CUpdater *pUpdater, const char *pFile, const char *pDestPath);
};
static const char *GetUpdaterUrl(char *pBuf, int BufSize, const char *pFile)
{
str_format(pBuf, BufSize, "https://update4.ddnet.tw/%s", pFile);
return pBuf;
}
static const char *GetUpdaterDestPath(char *pBuf, int BufSize, const char *pFile, const char *pDestPath)
{
if(!pDestPath)
{
pDestPath = pFile;
}
str_format(pBuf, BufSize, "update/%s", pDestPath);
return pBuf;
}
CUpdaterFetchTask::CUpdaterFetchTask(CUpdater *pUpdater, const char *pFile, const char *pDestPath) :
CFetchTask(pUpdater->m_pStorage, GetUpdaterUrl(m_aBuf, sizeof(m_aBuf), pFile), GetUpdaterDestPath(m_aBuf2, sizeof(m_aBuf), pFile, pDestPath), -2, true, false),
m_pUpdater(pUpdater)
{
}
void CUpdaterFetchTask::OnProgress()
{
lock_wait(m_pUpdater->m_Lock);
str_copy(m_pUpdater->m_aStatus, Dest(), sizeof(m_pUpdater->m_aStatus));
m_pUpdater->m_Percent = Progress();
lock_unlock(m_pUpdater->m_Lock);
}
void CUpdaterFetchTask::OnCompletion()
{
const char *b = 0;
for(const char *a = Dest(); *a; a++)
if(*a == '/')
b = a + 1;
b = b ? b : Dest();
if(!str_comp(b, "update.json"))
{
if(State() == CFetchTask::STATE_DONE)
m_pUpdater->SetCurrentState(IUpdater::GOT_MANIFEST);
else if(State() == CFetchTask::STATE_ERROR)
m_pUpdater->SetCurrentState(IUpdater::FAIL);
}
else if(!str_comp(b, m_pUpdater->m_aLastFile))
{
if(State() == CFetchTask::STATE_DONE)
m_pUpdater->SetCurrentState(IUpdater::MOVE_FILES);
else if(State() == CFetchTask::STATE_ERROR)
m_pUpdater->SetCurrentState(IUpdater::FAIL);
}
}
CUpdater::CUpdater()
{
m_pClient = NULL;
m_pStorage = NULL;
m_pFetcher = NULL;
m_pEngine = NULL;
m_State = CLEAN;
m_Percent = 0;
m_Lock = lock_create();
}
void CUpdater::Init()
{
m_pClient = Kernel()->RequestInterface<IClient>();
m_pStorage = Kernel()->RequestInterface<IStorage>();
m_pFetcher = Kernel()->RequestInterface<IFetcher>();
m_pEngine = Kernel()->RequestInterface<IEngine>();
m_IsWinXP = os_is_winxp_or_lower();
}
void CUpdater::ProgressCallback(IFetchTask *pTask, void *pUser)
CUpdater::~CUpdater()
{
CUpdater *pUpdate = (CUpdater *)pUser;
str_copy(pUpdate->m_Status, pTask->Dest(), sizeof(pUpdate->m_Status));
pUpdate->m_Percent = pTask->Progress();
lock_destroy(m_Lock);
}
void CUpdater::CompletionCallback(IFetchTask *pTask, void *pUser)
void CUpdater::SetCurrentState(int NewState)
{
CUpdater *pUpdate = (CUpdater *)pUser;
const char *b = 0;
for(const char *a = pTask->Dest(); *a; a++)
if(*a == '/')
b = a + 1;
b = b ? b : pTask->Dest();
if(!str_comp(b, "update.json"))
{
if(pTask->State() == IFetchTask::STATE_DONE)
pUpdate->m_State = GOT_MANIFEST;
else if(pTask->State() == IFetchTask::STATE_ERROR)
pUpdate->m_State = FAIL;
}
else if(!str_comp(b, pUpdate->m_aLastFile))
{
if(pTask->State() == IFetchTask::STATE_DONE)
pUpdate->m_State = MOVE_FILES;
else if(pTask->State() == IFetchTask::STATE_ERROR)
pUpdate->m_State = FAIL;
}
pTask->Destroy();
lock_wait(m_Lock);
m_State = NewState;
lock_unlock(m_Lock);
}
int CUpdater::GetCurrentState()
{
lock_wait(m_Lock);
int Result = m_State;
lock_unlock(m_Lock);
return Result;
}
void CUpdater::GetCurrentFile(char *pBuf, int BufSize)
{
lock_wait(m_Lock);
str_copy(pBuf, m_aStatus, BufSize);
lock_unlock(m_Lock);
}
int CUpdater::GetCurrentPercent()
{
lock_wait(m_Lock);
int Result = m_Percent;
lock_unlock(m_Lock);
return Result;
}
void CUpdater::FetchFile(const char *pFile, const char *pDestPath)
{
char aBuf[256], aPath[256];
str_format(aBuf, sizeof(aBuf), "https://update4.ddnet.tw/%s", pFile);
if(!pDestPath)
pDestPath = pFile;
str_format(aPath, sizeof(aPath), "update/%s", pDestPath);
m_pFetcher->FetchFile(aBuf, aPath, -2, true, false, this, &CUpdater::CompletionCallback, &CUpdater::ProgressCallback);
m_pEngine->AddJob(std::make_shared<CUpdaterFetchTask>(this, pFile, pDestPath));
}
void CUpdater::MoveFile(const char *pFile)
@ -93,10 +158,10 @@ void CUpdater::Update()
{
switch(m_State)
{
case GOT_MANIFEST:
case IUpdater::GOT_MANIFEST:
PerformUpdate();
break;
case MOVE_FILES:
case IUpdater::MOVE_FILES:
CommitUpdate();
break;
default:
@ -104,9 +169,9 @@ void CUpdater::Update()
}
}
void CUpdater::AddFileJob(const char *pFile, bool job)
void CUpdater::AddFileJob(const char *pFile, bool Job)
{
m_FileJobs[string(pFile)] = job;
m_FileJobs[string(pFile)] = Job;
}
void CUpdater::ReplaceClient()

View file

@ -2,7 +2,7 @@
#define ENGINE_CLIENT_UPDATER_H
#include <engine/updater.h>
#include <engine/fetcher.h>
#include "fetcher.h"
#include <map>
#include <string>
@ -34,14 +34,18 @@
class CUpdater : public IUpdater
{
friend class CUpdaterFetchTask;
class IClient *m_pClient;
class IStorage *m_pStorage;
class IFetcher *m_pFetcher;
class IEngine *m_pEngine;
bool m_IsWinXP;
LOCK m_Lock;
int m_State;
char m_Status[256];
char m_aStatus[256];
int m_Percent;
char m_aLastFile[256];
@ -50,7 +54,7 @@ class CUpdater : public IUpdater
std::map<std::string, bool> m_FileJobs;
void AddFileJob(const char *pFile, bool job);
void AddFileJob(const char *pFile, bool Job);
void FetchFile(const char *pFile, const char *pDestPath = 0);
void MoveFile(const char *pFile);
@ -61,14 +65,15 @@ class CUpdater : public IUpdater
void ReplaceClient();
void ReplaceServer();
void SetCurrentState(int NewState);
public:
CUpdater();
static void ProgressCallback(IFetchTask *pTask, void *pUser);
static void CompletionCallback(IFetchTask *pTask, void *pUser);
~CUpdater();
int GetCurrentState() { return m_State; };
char *GetCurrentFile() { return m_Status; };
int GetCurrentPercent() { return m_Percent; };
int GetCurrentState();
void GetCurrentFile(char *pBuf, int BufSize);
int GetCurrentPercent();
virtual void InitiateUpdate();
void Init();

View file

@ -6,10 +6,16 @@
#include "kernel.h"
#include <engine/shared/jobs.h>
class CHostLookup
class CHostLookup : public IJob
{
private:
virtual void Run();
public:
CJob m_Job;
CHostLookup();
CHostLookup(const char *pHostname, int Nettype);
int m_Result;
char m_aHostname[128];
int m_Nettype;
NETADDR m_Addr;
@ -25,8 +31,7 @@ protected:
public:
virtual void Init() = 0;
virtual void InitLogfile() = 0;
virtual void HostLookup(CHostLookup *pLookup, const char *pHostname, int Nettype) = 0;
virtual void AddJob(CJob *pJob, JOBFUNC pfnFunc, void *pData, CBFUNC pfnDestroy = 0) = 0;
virtual void AddJob(std::shared_ptr<IJob> pJob) = 0;
};
extern IEngine *CreateEngine(const char *pAppname, bool Silent);

View file

@ -1,44 +0,0 @@
#ifndef ENGINE_FETCHER_H
#define ENGINE_FETCHER_H
#include <engine/shared/jobs.h>
#include "kernel.h"
#include "stddef.h"
class IFetchTask
{
public:
enum
{
STATE_ERROR = -1,
STATE_QUEUED,
STATE_RUNNING,
STATE_DONE,
STATE_ABORTED,
};
virtual ~IFetchTask() {};
virtual double Current() = 0;
virtual double Size() = 0;
virtual int Progress() = 0;
virtual int State() = 0;
virtual const char *Dest() = 0;
virtual void Abort() = 0;
virtual void Destroy() = 0;
};
typedef void (*PROGFUNC)(IFetchTask *pTask, void *pUser);
typedef void (*COMPFUNC)(IFetchTask *pDest, void *pUser);
class IFetcher : public IInterface
{
MACRO_INTERFACE("fetcher", 0)
public:
virtual bool Init() = 0;
virtual IFetchTask *FetchFile(const char *pUrl, const char *pDest, int StorageType = -2, bool UseDDNetCA = false, bool CanTimeout = true, void *pUser = 0, COMPFUNC pfnCompCb = 0, PROGFUNC pfnProgCb = 0) = 0;
virtual void Escape(char *pBud, size_t size, const char *pStr) = 0;
};
#endif

View file

@ -820,20 +820,24 @@ void CServer::InitDnsbl(int ClientID)
NETADDR Addr = *m_NetServer.ClientAddr(ClientID);
//TODO: support ipv6
if (Addr.type != NETTYPE_IPV4)
if(Addr.type != NETTYPE_IPV4)
return;
// build dnsbl host lookup
char aBuf[256];
if (g_Config.m_SvDnsblKey[0] == '\0')
if(g_Config.m_SvDnsblKey[0] == '\0')
{
// without key
str_format(aBuf, sizeof(aBuf), "%d.%d.%d.%d.%s", Addr.ip[3], Addr.ip[2], Addr.ip[1], Addr.ip[0], g_Config.m_SvDnsblHost);
}
else
{
// with key
str_format(aBuf, sizeof(aBuf), "%s.%d.%d.%d.%d.%s", g_Config.m_SvDnsblKey, Addr.ip[3], Addr.ip[2], Addr.ip[1], Addr.ip[0], g_Config.m_SvDnsblHost);
}
IEngine *pEngine = Kernel()->RequestInterface<IEngine>();
pEngine->HostLookup(&m_aClients[ClientID].m_DnsblLookup, aBuf, NETTYPE_IPV4);
pEngine->AddJob(m_aClients[ClientID].m_pDnsblLookup = std::make_shared<CHostLookup>(aBuf, NETTYPE_IPV4));
}
int CServer::DelClientCallback(int ClientID, const char *pReason, void *pUser)
@ -1843,10 +1847,10 @@ int CServer::Run()
InitDnsbl(ClientID);
}
else if (m_aClients[ClientID].m_DnsblState == CClient::DNSBL_STATE_PENDING &&
m_aClients[ClientID].m_DnsblLookup.m_Job.Status() == CJob::STATE_DONE)
m_aClients[ClientID].m_pDnsblLookup->Status() == IJob::STATE_DONE)
{
if (m_aClients[ClientID].m_DnsblLookup.m_Job.Result() != 0)
if (m_aClients[ClientID].m_pDnsblLookup->m_Result != 0)
{
// entry not found -> whitelisted
m_aClients[ClientID].m_DnsblState = CClient::DNSBL_STATE_WHITELISTED;

View file

@ -164,7 +164,7 @@ public:
// DNSBL
int m_DnsblState;
CHostLookup m_DnsblLookup;
std::shared_ptr<CHostLookup> m_pDnsblLookup;
};
CClient m_aClients[MAX_CLIENTS];

View file

@ -9,11 +9,20 @@
#include <engine/shared/config.h>
#include <engine/shared/network.h>
static int HostLookupThread(void *pUser)
CHostLookup::CHostLookup()
{
CHostLookup *pLookup = (CHostLookup *)pUser;
return net_host_lookup(pLookup->m_aHostname, &pLookup->m_Addr, pLookup->m_Nettype);
}
CHostLookup::CHostLookup(const char *pHostname, int Nettype)
{
str_copy(m_aHostname, pHostname, sizeof(m_aHostname));
m_Nettype = Nettype;
}
void CHostLookup::Run()
{
m_Result = net_host_lookup(m_aHostname, &m_Addr, m_Nettype);
}
class CEngine : public IEngine
@ -99,18 +108,11 @@ public:
dbg_logger_file(g_Config.m_Logfile);
}
void HostLookup(CHostLookup *pLookup, const char *pHostname, int Nettype)
{
str_copy(pLookup->m_aHostname, pHostname, sizeof(pLookup->m_aHostname));
pLookup->m_Nettype = Nettype;
AddJob(&pLookup->m_Job, HostLookupThread, pLookup);
}
void AddJob(CJob *pJob, JOBFUNC pfnFunc, void *pData, CBFUNC pfnDestroy = 0)
void AddJob(std::shared_ptr<IJob> pJob)
{
if(g_Config.m_Debug)
dbg_msg("engine", "job added");
m_JobPool.Add(pJob, pfnFunc, pData, pfnDestroy);
m_JobPool.Add(pJob);
}
};

View file

@ -3,6 +3,31 @@
#include <base/system.h>
#include "jobs.h"
IJob::IJob() :
m_Status(STATE_PENDING)
{
}
IJob::IJob(const IJob &Other) :
m_Status(STATE_PENDING)
{
}
IJob &IJob::operator=(const IJob &Other)
{
m_Status = STATE_PENDING;
return *this;
}
IJob::~IJob()
{
}
int IJob::Status()
{
return m_Status.load();
}
CJobPool::CJobPool()
{
// empty the pool
@ -31,7 +56,7 @@ void CJobPool::WorkerThread(void *pUser)
while(!pPool->m_Shutdown)
{
CJob *pJob = 0;
std::shared_ptr<IJob> pJob = 0;
// fetch job from queue
sphore_wait(&pPool->m_Semaphore);
@ -40,9 +65,7 @@ void CJobPool::WorkerThread(void *pUser)
{
pJob = pPool->m_pFirstJob;
pPool->m_pFirstJob = pPool->m_pFirstJob->m_pNext;
if(pPool->m_pFirstJob)
pPool->m_pFirstJob->m_pPrev = 0;
else
if(!pPool->m_pFirstJob)
pPool->m_pLastJob = 0;
}
lock_unlock(pPool->m_Lock);
@ -50,11 +73,9 @@ void CJobPool::WorkerThread(void *pUser)
// do the job if we have one
if(pJob)
{
pJob->m_Status = CJob::STATE_RUNNING;
pJob->m_Result = pJob->m_pfnFunc(pJob->m_pFuncData);
pJob->m_Status = CJob::STATE_DONE;
if(pJob->m_pfnDestroy)
pJob->m_pfnDestroy(pJob, pJob->m_pFuncData);
pJob->m_Status = IJob::STATE_RUNNING;
pJob->Run();
pJob->m_Status = IJob::STATE_DONE;
}
}
@ -69,17 +90,11 @@ int CJobPool::Init(int NumThreads)
return 0;
}
int CJobPool::Add(CJob *pJob, JOBFUNC pfnFunc, void *pData, CBFUNC pfnDestroy)
int CJobPool::Add(std::shared_ptr<IJob> pJob)
{
mem_zero(pJob, sizeof(CJob));
pJob->m_pfnFunc = pfnFunc;
pJob->m_pFuncData = pData;
pJob->m_pfnDestroy = pfnDestroy;
lock_wait(m_Lock);
// add job to queue
pJob->m_pPrev = m_pLastJob;
if(m_pLastJob)
m_pLastJob->m_pNext = pJob;
m_pLastJob = pJob;

View file

@ -2,31 +2,29 @@
/* If you are missing that file, acquire a complete release at teeworlds.com. */
#ifndef ENGINE_SHARED_JOBS_H
#define ENGINE_SHARED_JOBS_H
class CJob;
#include <atomic>
#include <memory>
class IJob;
class CJobPool;
typedef int (*JOBFUNC)(void *pData);
typedef void (*CBFUNC)(CJob *pJob, void *pData);
class CJob
class IJob
{
friend class CJobPool;
friend CJobPool;
CJob *m_pPrev;
CJob *m_pNext;
private:
std::shared_ptr<IJob> m_pNext;
volatile int m_Status;
volatile int m_Result;
std::atomic<int> m_Status;
virtual void Run() = 0;
JOBFUNC m_pfnFunc;
CBFUNC m_pfnDestroy;
void *m_pFuncData;
public:
CJob()
{
m_Status = STATE_DONE;
m_pFuncData = 0;
}
IJob();
IJob(const IJob &Other);
IJob &operator=(const IJob &Other);
virtual ~IJob();
int Status();
enum
{
@ -34,9 +32,6 @@ public:
STATE_RUNNING,
STATE_DONE
};
int Status() const { return m_Status; }
int Result() const { return m_Result; }
};
class CJobPool
@ -51,8 +46,8 @@ class CJobPool
LOCK m_Lock;
SEMAPHORE m_Semaphore;
CJob *m_pFirstJob;
CJob *m_pLastJob;
std::shared_ptr<IJob> m_pFirstJob;
std::shared_ptr<IJob> m_pLastJob;
static void WorkerThread(void *pUser);
@ -61,6 +56,6 @@ public:
~CJobPool();
int Init(int NumThreads);
int Add(CJob *pJob, JOBFUNC pfnFunc, void *pData, CBFUNC pfnDestroy = 0);
int Add(std::shared_ptr<IJob> pJob);
};
#endif

View file

@ -20,7 +20,7 @@ public:
NETADDR m_Addr;
bool m_Valid;
int m_Count;
CHostLookup m_Lookup;
std::shared_ptr<CHostLookup> m_pLookup;
};
enum
@ -53,11 +53,10 @@ public:
// add lookup jobs
for(int i = 0; i < MAX_MASTERSERVERS; i++)
{
m_pEngine->HostLookup(&m_aMasterServers[i].m_Lookup, m_aMasterServers[i].m_aHostname, Nettype);
*m_aMasterServers[i].m_pLookup = CHostLookup(m_aMasterServers[i].m_aHostname, Nettype);
m_pEngine->AddJob(m_aMasterServers[i].m_pLookup);
m_aMasterServers[i].m_Valid = false;
m_aMasterServers[i].m_Count = 0;
//dbg_msg("MasterServer", "Lookup id: %d, name: %s, nettype: %d", i, m_aMasterServers[i].m_aHostname, Nettype);
}
m_State = STATE_UPDATE;
@ -73,23 +72,19 @@ public:
for(int i = 0; i < MAX_MASTERSERVERS; i++)
{
if(m_aMasterServers[i].m_Lookup.m_Job.Status() != CJob::STATE_DONE)
if(m_aMasterServers[i].m_pLookup->Status() != IJob::STATE_DONE)
m_State = STATE_UPDATE;
else
{
if(m_aMasterServers[i].m_Lookup.m_Job.Result() == 0)
if(m_aMasterServers[i].m_pLookup->m_Result == 0)
{
m_aMasterServers[i].m_Addr = m_aMasterServers[i].m_Lookup.m_Addr;
m_aMasterServers[i].m_Addr = m_aMasterServers[i].m_pLookup->m_Addr;
m_aMasterServers[i].m_Addr.port = 8300;
m_aMasterServers[i].m_Valid = true;
//dbg_msg("MasterServer", "Set server %d, name: %s with addr-port: %d addr-ip %s addr-type %d", i, m_aMasterServers[i].m_aHostname, m_aMasterServers[i].m_Addr.port, m_aMasterServers[i].m_Addr.ip, m_aMasterServers[i].m_Addr.type);
}
else
{
m_aMasterServers[i].m_Valid = false;
// dbg_msg("MasterServer", "Dropped %d, name: %s with addr-port: %d addr-ip %s addr-type %d", i, m_aMasterServers[i].m_aHostname);
}
}
}

View file

@ -23,7 +23,7 @@ public:
virtual void InitiateUpdate() = 0;
virtual int GetCurrentState() = 0;
virtual char *GetCurrentFile() = 0;
virtual void GetCurrentFile(char *pBuf, int BufSize) = 0;
virtual int GetCurrentPercent() = 0;
};

View file

@ -1321,9 +1321,15 @@ void CMenus::RenderServerbrowser(CUIRect MainView)
TextRender()->TextColor(1.0f, 0.4f, 0.4f, 1.0f);
}
else if(State == IUpdater::CLEAN)
{
str_format(aBuf, sizeof(aBuf), Localize("Current version: %s"), GAME_VERSION);
}
else if(State >= IUpdater::GETTING_MANIFEST && State < IUpdater::NEED_RESTART)
str_format(aBuf, sizeof(aBuf), "Downloading %s:", Updater()->GetCurrentFile());
{
char aCurrentFile[64];
Updater()->GetCurrentFile(aCurrentFile, sizeof(aCurrentFile));
str_format(aBuf, sizeof(aBuf), "Downloading %s:", aCurrentFile);
}
else if(State == IUpdater::FAIL)
{
str_format(aBuf, sizeof(aBuf), "Failed to download a file! Restart client to retry...");

View file

@ -13,29 +13,25 @@
#include "sounds.h"
struct CUserData
CSoundLoading::CSoundLoading(CGameClient *pGameClient, bool Render) :
m_pGameClient(pGameClient),
m_Render(Render)
{
CGameClient *m_pGameClient;
bool m_Render;
} g_UserData;
}
static int LoadSoundsThread(void *pUser)
void CSoundLoading::Run()
{
CUserData *pData = static_cast<CUserData *>(pUser);
for(int s = 0; s < g_pData->m_NumSounds; s++)
{
for(int i = 0; i < g_pData->m_aSounds[s].m_NumSounds; i++)
{
int Id = pData->m_pGameClient->Sound()->LoadWV(g_pData->m_aSounds[s].m_aSounds[i].m_pFilename);
int Id = m_pGameClient->Sound()->LoadWV(g_pData->m_aSounds[s].m_aSounds[i].m_pFilename);
g_pData->m_aSounds[s].m_aSounds[i].m_Id = Id;
}
if(pData->m_Render)
pData->m_pGameClient->m_pMenus->RenderLoading();
if(m_Render)
m_pGameClient->m_pMenus->RenderLoading();
}
return 0;
}
int CSounds::GetSampleId(int SetId)
@ -79,16 +75,13 @@ void CSounds::OnInit()
// load sounds
if(g_Config.m_ClThreadsoundloading)
{
g_UserData.m_pGameClient = m_pClient;
g_UserData.m_Render = false;
m_pClient->Engine()->AddJob(&m_SoundJob, LoadSoundsThread, &g_UserData);
m_pSoundJob = std::make_shared<CSoundLoading>(m_pClient, false);
m_pClient->Engine()->AddJob(m_pSoundJob);
m_WaitForSoundJob = true;
}
else
{
g_UserData.m_pGameClient = m_pClient;
g_UserData.m_Render = true;
LoadSoundsThread(&g_UserData);
CSoundLoading(m_pClient, true).Run();
m_WaitForSoundJob = false;
}
}
@ -113,7 +106,7 @@ void CSounds::OnRender()
// check for sound initialisation
if(m_WaitForSoundJob)
{
if(m_SoundJob.Status() == CJob::STATE_DONE)
if(m_pSoundJob->Status() == IJob::STATE_DONE)
m_WaitForSoundJob = false;
else
return;

View file

@ -2,9 +2,20 @@
/* If you are missing that file, acquire a complete release at teeworlds.com. */
#ifndef GAME_CLIENT_COMPONENTS_SOUNDS_H
#define GAME_CLIENT_COMPONENTS_SOUNDS_H
#include <engine/engine.h>
#include <engine/sound.h>
#include <game/client/component.h>
class CSoundLoading : public IJob
{
CGameClient *m_pGameClient;
bool m_Render;
public:
CSoundLoading(CGameClient *pGameClient, bool Render);
void Run();
};
class CSounds : public CComponent
{
enum
@ -18,7 +29,7 @@ class CSounds : public CComponent
} m_aQueue[QUEUE_SIZE];
int m_QueuePos;
int64 m_QueueWaitTime;
class CJob m_SoundJob;
std::shared_ptr<CSoundLoading> m_pSoundJob;
bool m_WaitForSoundJob;
int GetSampleId(int SetId);

View file

@ -43,13 +43,13 @@ public:
CPlayerData *PlayerData(int ID) { return &m_aPlayerData[ID]; }
virtual void MapInfo(int ClientID, const char* MapName) = 0;
virtual void MapVote(int ClientID, const char* MapName) = 0;
virtual void MapInfo(int ClientID, const char *pMapName) = 0;
virtual void MapVote(int ClientID, const char *pMapName) = 0;
virtual void CheckBirthday(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 aCpTime[NUM_CHECKPOINTS]) = 0;
virtual void SaveTeamScore(int* ClientIDs, unsigned int Size, float Time) = 0;
virtual void SaveTeamScore(int *pClientIDs, 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;
@ -60,8 +60,8 @@ public:
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;
virtual void RandomMap(int ClientID, int stars) = 0;
virtual void RandomUnfinishedMap(int ClientID, int stars) = 0;
virtual void RandomMap(int ClientID, int Stars) = 0;
virtual void RandomUnfinishedMap(int ClientID, int Stars) = 0;
virtual void SaveTeam(int Team, const char *pCode, int ClientID, const char *pServer) = 0;
virtual void LoadTeam(const char *pCode, int ClientID) = 0;