mirror of
https://github.com/ddnet/ddnet.git
synced 2024-11-10 10:08:18 +00:00
Add Autoupdate.
This commit is contained in:
parent
1ea1e68005
commit
233ce262ac
27
src/engine/autoupdate.h
Normal file
27
src/engine/autoupdate.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
#ifndef ENGINE_AUTOUPDATE_H
|
||||
#define ENGINE_AUTOUPDATE_H
|
||||
|
||||
#include "kernel.h"
|
||||
|
||||
class IAutoUpdate : public IInterface
|
||||
{
|
||||
MACRO_INTERFACE("autoupdate", 0)
|
||||
public:
|
||||
enum
|
||||
{
|
||||
IGNORED = -1,
|
||||
CLEAN,
|
||||
GETTING_MANIFEST,
|
||||
GOT_MANIFEST,
|
||||
PARSING_UPDATE,
|
||||
DOWNLOADING,
|
||||
NEED_RESTART,
|
||||
};
|
||||
|
||||
virtual void Update() = 0;
|
||||
virtual void InitiateUpdate() = 0;
|
||||
virtual void IgnoreUpdate() = 0;
|
||||
|
||||
};
|
||||
|
||||
#endif
|
169
src/engine/client/autoupdate.cpp
Normal file
169
src/engine/client/autoupdate.cpp
Normal file
|
@ -0,0 +1,169 @@
|
|||
#include "autoupdate.h"
|
||||
#include <base/system.h>
|
||||
#include <engine/fetcher.h>
|
||||
#include <engine/storage.h>
|
||||
#include <engine/client.h>
|
||||
#include <engine/external/json-parser/json.h>
|
||||
#include <game/version.h>
|
||||
|
||||
using std::string;
|
||||
using std::vector;
|
||||
|
||||
#if defined(CONF_FAMILY_WINDOWS)
|
||||
#define PLAT_EXEC_NAME "DDNet.exe"
|
||||
#elif defined(CONF_FAMILY_UNIX)
|
||||
#define PLAT_EXEC_NAME "DDNet"
|
||||
#endif
|
||||
|
||||
CAutoUpdate::CAutoUpdate()
|
||||
{
|
||||
m_pClient = NULL;
|
||||
m_pStorage = NULL;
|
||||
m_pFetcher = NULL;
|
||||
m_State = CLEAN;
|
||||
m_Percent = 0;
|
||||
}
|
||||
|
||||
void CAutoUpdate::Init()
|
||||
{
|
||||
m_pClient = Kernel()->RequestInterface<IClient>();
|
||||
m_pStorage = Kernel()->RequestInterface<IStorage>();
|
||||
m_pFetcher = Kernel()->RequestInterface<IFetcher>();
|
||||
}
|
||||
|
||||
void CAutoUpdate::ProgressCallback(const char *pDest, void *pUser, double DlTotal, double DlCurr, double UlTotal, double UlCurr)
|
||||
{
|
||||
CAutoUpdate *pUpdate = (CAutoUpdate *)pUser;
|
||||
str_copy(pUpdate->m_Status, pDest, sizeof(m_Status));
|
||||
pUpdate->m_Percent = (100*DlCurr)/(DlTotal ? DlTotal : 1);
|
||||
}
|
||||
|
||||
void CAutoUpdate::CompletionCallback(const char *pDest, void *pUser)
|
||||
{
|
||||
CAutoUpdate *pUpdate = (CAutoUpdate *)pUser;
|
||||
if(!str_comp(pDest, "update.json")){
|
||||
pUpdate->m_State = GOT_MANIFEST;
|
||||
}
|
||||
else if(!str_comp(pDest, pUpdate->m_aLastFile)){
|
||||
if(pUpdate->m_ClientUpdate)
|
||||
pUpdate->ReplaceExecutable();
|
||||
pUpdate->m_State = NEED_RESTART;
|
||||
}
|
||||
}
|
||||
|
||||
void CAutoUpdate::FetchFile(const char *pFile, const char *pDestPath)
|
||||
{
|
||||
char aBuf[256];
|
||||
str_format(aBuf, sizeof(aBuf), "https://learath2.info/%s", pFile);
|
||||
if(!pDestPath)
|
||||
pDestPath = pFile;
|
||||
m_pFetcher->QueueAdd(aBuf, pDestPath, &CAutoUpdate::CompletionCallback, &CAutoUpdate::ProgressCallback, this);
|
||||
}
|
||||
|
||||
void CAutoUpdate::Update()
|
||||
{
|
||||
switch(m_State){
|
||||
case GOT_MANIFEST:
|
||||
PerformUpdate();
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void CAutoUpdate::AddNewFile(const char *pFile)
|
||||
{
|
||||
for(vector<string>::iterator it = m_AddedFiles.begin(); it < m_AddedFiles.end(); ++it)
|
||||
if(!str_comp(it->c_str(), pFile))
|
||||
return;
|
||||
m_AddedFiles.push_back(string(pFile));
|
||||
}
|
||||
|
||||
void CAutoUpdate::AddRemovedFile(const char *pFile)
|
||||
{
|
||||
//First remove from to be downloaded list
|
||||
for(vector<string>::iterator it = m_AddedFiles.begin(); it < m_AddedFiles.end(); ++it){
|
||||
if(!str_comp(it->c_str(), pFile)){
|
||||
m_AddedFiles.erase(it);
|
||||
break;
|
||||
}
|
||||
}
|
||||
m_RemovedFiles.push_back(string(pFile));
|
||||
}
|
||||
|
||||
void CAutoUpdate::ReplaceExecutable()
|
||||
{
|
||||
dbg_msg("autoupdate", "Replacing" PLAT_EXEC_NAME);
|
||||
m_pStorage->RenameFile(PLAT_EXEC_NAME, "DDNet.old", 2);
|
||||
m_pStorage->RenameFile("DDNet.tmp", PLAT_EXEC_NAME, 2);
|
||||
}
|
||||
|
||||
void CAutoUpdate::ParseUpdate()
|
||||
{
|
||||
IOHANDLE File = m_pStorage->OpenFile("update.json", IOFLAG_READ, IStorage::TYPE_ALL);
|
||||
if(File){
|
||||
char aBuf[4096*4];
|
||||
mem_zero(aBuf, sizeof (aBuf));
|
||||
io_read(File, aBuf, sizeof(aBuf));
|
||||
io_close(File);
|
||||
|
||||
json_value *pVersions = json_parse(aBuf);
|
||||
|
||||
if(pVersions && pVersions->type == json_array){
|
||||
for(int i = 0; i < json_array_length(pVersions); i++){
|
||||
const json_value *pTemp;
|
||||
const json_value *pCurrent = json_array_get(pVersions, i);
|
||||
if(str_comp(json_string_get(json_object_get(pCurrent, "version")), GAME_RELEASE_VERSION)){
|
||||
if(json_boolean_get(json_object_get(pCurrent, "client")))
|
||||
m_ClientUpdate = true;
|
||||
if(json_boolean_get(json_object_get(pCurrent, "server")))
|
||||
m_ServerUpdate = true;
|
||||
if((pTemp = json_object_get(pCurrent, "download"))->type == json_array){
|
||||
for(int j = 0; j < json_array_length(pTemp); j++)
|
||||
AddNewFile(json_string_get(json_array_get(pTemp, j)));
|
||||
}
|
||||
if((pTemp = json_object_get(pCurrent, "remove"))->type == json_array){
|
||||
for(int j = 0; j < json_array_length(pTemp); j++)
|
||||
AddRemovedFile(json_string_get(json_array_get(pTemp, j)));
|
||||
}
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CAutoUpdate::InitiateUpdate()
|
||||
{
|
||||
m_State = GETTING_MANIFEST;
|
||||
FetchFile("update.json");
|
||||
}
|
||||
|
||||
void CAutoUpdate::IgnoreUpdate()
|
||||
{
|
||||
m_State = IGNORED;
|
||||
}
|
||||
|
||||
void CAutoUpdate::PerformUpdate()
|
||||
{
|
||||
m_State = PARSING_UPDATE;
|
||||
dbg_msg("autoupdate", "Parsing update.json");
|
||||
ParseUpdate();
|
||||
m_State = DOWNLOADING;
|
||||
|
||||
if(m_ClientUpdate)
|
||||
str_copy(m_aLastFile, "DDNet.tmp", sizeof(m_aLastFile));
|
||||
else
|
||||
str_copy(m_aLastFile, m_AddedFiles.front().c_str(), sizeof(m_aLastFile));
|
||||
|
||||
while(!m_AddedFiles.empty()){
|
||||
FetchFile(m_AddedFiles.back().c_str());
|
||||
m_AddedFiles.pop_back();
|
||||
}
|
||||
while(!m_RemovedFiles.empty()){
|
||||
m_pStorage->RemoveFile(m_RemovedFiles.back().c_str(), IStorage::TYPE_SAVE);
|
||||
m_RemovedFiles.pop_back();
|
||||
}
|
||||
if(m_ClientUpdate)
|
||||
FetchFile(PLAT_EXEC_NAME, "DDNet.tmp");
|
||||
}
|
46
src/engine/client/autoupdate.h
Normal file
46
src/engine/client/autoupdate.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
#ifndef ENGINE_CLIENT_AUTOUPDATE_H
|
||||
#define ENGINE_CLIENT_AUTOUPDATE_H
|
||||
|
||||
#include <engine/autoupdate.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
class CAutoUpdate : public IAutoUpdate
|
||||
{
|
||||
class IClient *m_pClient;
|
||||
class IStorage *m_pStorage;
|
||||
class IFetcher *m_pFetcher;
|
||||
|
||||
int m_State;
|
||||
char m_Status[256];
|
||||
int m_Percent;
|
||||
char m_aLastFile[256];
|
||||
|
||||
bool m_ClientUpdate;
|
||||
bool m_ServerUpdate;
|
||||
|
||||
std::vector<std::string> m_AddedFiles;
|
||||
std::vector<std::string> m_RemovedFiles;
|
||||
|
||||
void AddNewFile(const char *pFile);
|
||||
void AddRemovedFile(const char *pFile);
|
||||
void FetchFile(const char *pFile, const char *pDestPath = 0);
|
||||
|
||||
void ParseUpdate();
|
||||
void PerformUpdate();
|
||||
void ReplaceExecutable();
|
||||
|
||||
public:
|
||||
CAutoUpdate();
|
||||
static void ProgressCallback(const char *pDest, void *pUser, double DlTotal, double DlCurr, double UlTotal, double UlCurr);
|
||||
static void CompletionCallback(const char *pDest, void *pUser);
|
||||
|
||||
|
||||
virtual void InitiateUpdate();
|
||||
void IgnoreUpdate();
|
||||
void Init();
|
||||
virtual void Update();
|
||||
void Restart();
|
||||
};
|
||||
|
||||
#endif
|
|
@ -59,6 +59,7 @@
|
|||
#include "friends.h"
|
||||
#include "serverbrowser.h"
|
||||
#include "fetcher.h"
|
||||
#include "autoupdate.h"
|
||||
#include "client.h"
|
||||
|
||||
#include <zlib.h>
|
||||
|
@ -1165,9 +1166,7 @@ void CClient::ProcessConnlessPacket(CNetChunk *pPacket)
|
|||
|
||||
// assume version is out of date when version-data doesn't match
|
||||
if(!VersionMatch)
|
||||
{
|
||||
str_copy(m_aVersionStr, aVersion, sizeof(m_aVersionStr));
|
||||
}
|
||||
|
||||
// request the news
|
||||
CNetChunk Packet;
|
||||
|
@ -2474,6 +2473,7 @@ void CClient::RegisterInterfaces()
|
|||
Kernel()->RegisterInterface(static_cast<IDemoPlayer*>(&m_DemoPlayer));
|
||||
Kernel()->RegisterInterface(static_cast<IServerBrowser*>(&m_ServerBrowser));
|
||||
Kernel()->RegisterInterface(static_cast<IFetcher*>(&m_Fetcher));
|
||||
Kernel()->RegisterInterface(static_cast<IAutoUpdate*>(&m_AutoUpdate));
|
||||
Kernel()->RegisterInterface(static_cast<IFriends*>(&m_Friends));
|
||||
}
|
||||
|
||||
|
@ -2489,6 +2489,7 @@ void CClient::InitInterfaces()
|
|||
m_pMap = Kernel()->RequestInterface<IEngineMap>();
|
||||
m_pMasterServer = Kernel()->RequestInterface<IEngineMasterServer>();
|
||||
m_pFetcher = Kernel()->RequestInterface<IFetcher>();
|
||||
m_pAutoUpdate = Kernel()->RequestInterface<IAutoUpdate>();
|
||||
m_pStorage = Kernel()->RequestInterface<IStorage>();
|
||||
|
||||
m_DemoEditor.Init(m_pGameClient->NetVersion(), &m_SnapshotDelta, m_pConsole, m_pStorage);
|
||||
|
@ -2496,6 +2497,7 @@ void CClient::InitInterfaces()
|
|||
m_ServerBrowser.SetBaseInfo(&m_NetClient[2], m_pGameClient->NetVersion());
|
||||
|
||||
m_Fetcher.Init();
|
||||
m_AutoUpdate.Init();
|
||||
|
||||
m_Friends.Init();
|
||||
|
||||
|
@ -2632,6 +2634,8 @@ void CClient::Run()
|
|||
if(Input()->Update())
|
||||
break; // SDL_QUIT
|
||||
|
||||
AutoUpdate()->Update();
|
||||
|
||||
// update sound
|
||||
Sound()->Update();
|
||||
|
||||
|
|
|
@ -64,6 +64,7 @@ class CClient : public IClient, public CDemoPlayer::IListner
|
|||
IConsole *m_pConsole;
|
||||
IStorage *m_pStorage;
|
||||
IFetcher *m_pFetcher;
|
||||
IAutoUpdate *m_pAutoUpdate;
|
||||
IEngineMasterServer *m_pMasterServer;
|
||||
|
||||
enum
|
||||
|
@ -78,6 +79,7 @@ class CClient : public IClient, public CDemoPlayer::IListner
|
|||
class CDemoEditor m_DemoEditor;
|
||||
class CServerBrowser m_ServerBrowser;
|
||||
class CFetcher m_Fetcher;
|
||||
class CAutoUpdate m_AutoUpdate;
|
||||
class CFriends m_Friends;
|
||||
class CMapChecker m_MapChecker;
|
||||
|
||||
|
@ -202,6 +204,7 @@ public:
|
|||
IEngineMasterServer *MasterServer() { return m_pMasterServer; }
|
||||
IStorage *Storage() { return m_pStorage; }
|
||||
IFetcher *Fetcher() { return m_pFetcher; }
|
||||
IAutoUpdate *AutoUpdate() { return m_pAutoUpdate; }
|
||||
|
||||
CClient();
|
||||
|
||||
|
|
|
@ -28,6 +28,7 @@ protected:
|
|||
class IServerBrowser *ServerBrowser() const { return m_pClient->ServerBrowser(); }
|
||||
class CLayers *Layers() const { return m_pClient->Layers(); }
|
||||
class CCollision *Collision() const { return m_pClient->Collision(); }
|
||||
class IAutoUpdate *AutoUpdate() const { return m_pClient->AutoUpdate(); }
|
||||
public:
|
||||
virtual ~CComponent() {}
|
||||
class CGameClient *GameClient() const { return m_pClient; }
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <engine/storage.h>
|
||||
#include <engine/sound.h>
|
||||
#include <engine/serverbrowser.h>
|
||||
#include <engine/autoupdate.h>
|
||||
#include <engine/shared/demo.h>
|
||||
#include <engine/shared/config.h>
|
||||
|
||||
|
@ -123,6 +124,7 @@ void CGameClient::OnConsoleInit()
|
|||
m_pServerBrowser = Kernel()->RequestInterface<IServerBrowser>();
|
||||
m_pEditor = Kernel()->RequestInterface<IEditor>();
|
||||
m_pFriends = Kernel()->RequestInterface<IFriends>();
|
||||
m_pAutoUpdate = Kernel()->RequestInterface<IAutoUpdate>();
|
||||
|
||||
// setup pointers
|
||||
m_pBinds = &::gs_Binds;
|
||||
|
|
|
@ -95,6 +95,7 @@ class CGameClient : public IGameClient
|
|||
class IServerBrowser *m_pServerBrowser;
|
||||
class IEditor *m_pEditor;
|
||||
class IFriends *m_pFriends;
|
||||
class IAutoUpdate *m_pAutoUpdate;
|
||||
|
||||
CLayers m_Layers;
|
||||
class CCollision m_Collision;
|
||||
|
@ -135,6 +136,7 @@ public:
|
|||
class CCollision *Collision() { return &m_Collision; };
|
||||
class IEditor *Editor() { return m_pEditor; }
|
||||
class IFriends *Friends() { return m_pFriends; }
|
||||
class IAutoUpdate *AutoUpdate() { return m_pAutoUpdate; }
|
||||
|
||||
int NetobjNumCorrections() { return m_NetObjHandler.NumObjCorrections(); }
|
||||
const char *NetobjCorrectedOn() { return m_NetObjHandler.CorrectedObjOn(); }
|
||||
|
|
Loading…
Reference in a new issue