Introduce ddnet-info.json

- Single json file containing all information for the client
- Fetched from https://info.ddnet.tw/info?name=deen
- Replaces versionsrv, news, ddnet-maps.json and ddnet-ranks.json
- Servers are sorted by most popular ones for respective player
- Always stays < 100 ms response time, compared to occasional 50 s for
  old ddnet-ranks.json
This commit is contained in:
def 2017-09-03 17:36:51 +02:00
parent 27b7549bba
commit 89ed22e8d8
17 changed files with 206 additions and 796 deletions

View file

@ -399,8 +399,6 @@ set_glob(ENGINE_SHARED GLOB src/engine/shared
linereader.cpp linereader.cpp
linereader.h linereader.h
map.cpp map.cpp
mapchecker.cpp
mapchecker.h
masterserver.cpp masterserver.cpp
memheap.cpp memheap.cpp
memheap.h memheap.h
@ -793,26 +791,21 @@ list(APPEND TARGETS_LINK ${TARGET_SERVER})
######################################################################## ########################################################################
set_glob(MASTERSRV_SRC GLOB src/mastersrv mastersrv.cpp mastersrv.h) set_glob(MASTERSRV_SRC GLOB src/mastersrv mastersrv.cpp mastersrv.h)
set_glob(VERSIONSRV_SRC GLOB src/versionsrv mapversions.h versionsrv.cpp versionsrv.h)
set_glob(TWPING_SRC GLOB src/twping twping.cpp) set_glob(TWPING_SRC GLOB src/twping twping.cpp)
set(TARGET_MASTERSRV mastersrv) set(TARGET_MASTERSRV mastersrv)
set(TARGET_VERSIONSRV versionsrv)
set(TARGET_TWPING twping) set(TARGET_TWPING twping)
add_executable(${TARGET_MASTERSRV} EXCLUDE_FROM_ALL ${MASTERSRV_SRC} $<TARGET_OBJECTS:engine-shared> ${DEPS}) add_executable(${TARGET_MASTERSRV} EXCLUDE_FROM_ALL ${MASTERSRV_SRC} $<TARGET_OBJECTS:engine-shared> ${DEPS})
add_executable(${TARGET_VERSIONSRV} EXCLUDE_FROM_ALL ${VERSIONSRV_SRC} $<TARGET_OBJECTS:engine-shared> ${DEPS})
add_executable(${TARGET_TWPING} EXCLUDE_FROM_ALL ${TWPING_SRC} $<TARGET_OBJECTS:engine-shared> ${DEPS}) add_executable(${TARGET_TWPING} EXCLUDE_FROM_ALL ${TWPING_SRC} $<TARGET_OBJECTS:engine-shared> ${DEPS})
add_custom_target(generate_nethash DEPENDS src/game/generated/nethash.cpp) add_custom_target(generate_nethash DEPENDS src/game/generated/nethash.cpp)
add_dependencies(${TARGET_VERSIONSRV} generate_nethash)
target_link_libraries(${TARGET_MASTERSRV} ${LIBS}) target_link_libraries(${TARGET_MASTERSRV} ${LIBS})
target_link_libraries(${TARGET_VERSIONSRV} ${LIBS})
target_link_libraries(${TARGET_TWPING} ${LIBS}) target_link_libraries(${TARGET_TWPING} ${LIBS})
list(APPEND TARGETS_OWN ${TARGET_MASTERSRV} ${TARGET_TWPING} ${TARGET_VERSIONSRV}) list(APPEND TARGETS_OWN ${TARGET_MASTERSRV} ${TARGET_TWPING})
list(APPEND TARGETS_LINK ${TARGET_MASTERSRV} ${TARGET_TWPING} ${TARGET_VERSIONSRV}) list(APPEND TARGETS_LINK ${TARGET_MASTERSRV} ${TARGET_TWPING})
set(TARGETS_TOOLS) set(TARGETS_TOOLS)
set_glob(TOOLS GLOB src/tools set_glob(TOOLS GLOB src/tools

View file

@ -348,7 +348,6 @@ function build(settings)
client = Compile(client_settings, Collect("src/engine/client/*.cpp")) client = Compile(client_settings, Collect("src/engine/client/*.cpp"))
server = Compile(server_settings, Collect("src/engine/server/*.cpp")) server = Compile(server_settings, Collect("src/engine/server/*.cpp"))
versionserver = Compile(settings, Collect("src/versionsrv/*.cpp"))
masterserver = Compile(settings, Collect("src/mastersrv/*.cpp")) masterserver = Compile(settings, Collect("src/mastersrv/*.cpp"))
twping = Compile(settings, Collect("src/twping/*.cpp")) twping = Compile(settings, Collect("src/twping/*.cpp"))
game_shared = Compile(settings, Collect("src/game/*.cpp"), nethash, network_source) game_shared = Compile(settings, Collect("src/game/*.cpp"), nethash, network_source)
@ -390,9 +389,6 @@ function build(settings)
serverlaunch = Link(launcher_settings, "serverlaunch", server_osxlaunch) serverlaunch = Link(launcher_settings, "serverlaunch", server_osxlaunch)
end end
versionserver_exe = Link(server_settings, "versionsrv", versionserver,
engine, zlib, libwebsockets, md5, game_shared)
masterserver_exe = Link(server_settings, "mastersrv", masterserver, masterserver_exe = Link(server_settings, "mastersrv", masterserver,
engine, zlib, libwebsockets, md5, game_shared) engine, zlib, libwebsockets, md5, game_shared)

View file

@ -7,7 +7,6 @@
#include "message.h" #include "message.h"
#include <engine/friends.h> #include <engine/friends.h>
#include <engine/shared/config.h> #include <engine/shared/config.h>
#include <versionsrv/versionsrv.h>
enum enum
{ {
@ -40,7 +39,7 @@ protected:
int m_GameTickSpeed; int m_GameTickSpeed;
public: public:
char m_aNews[NEWS_SIZE]; char m_aNews[3000];
int64 m_ReconnectTime; int64 m_ReconnectTime;
class CSnapItem class CSnapItem
@ -135,8 +134,6 @@ public:
// server info // server info
virtual void GetServerInfo(class CServerInfo *pServerInfo) = 0; virtual void GetServerInfo(class CServerInfo *pServerInfo) = 0;
virtual void CheckVersionUpdate() = 0;
virtual int GetPredictionTime() = 0; virtual int GetPredictionTime() = 0;
// snapshot interface // snapshot interface
@ -189,8 +186,7 @@ public:
virtual void DemoSliceEnd() = 0; virtual void DemoSliceEnd() = 0;
virtual void DemoSlice(const char *pDstPath, CLIENTFUNC_FILTER pfnFilter, void *pUser) = 0; virtual void DemoSlice(const char *pDstPath, CLIENTFUNC_FILTER pfnFilter, void *pUser) = 0;
virtual void RequestDDNetSrvList() = 0; virtual void RequestDDNetInfo() = 0;
virtual void RequestDDNetRanks() = 0;
virtual bool EditorHasUnsavedData() = 0; virtual bool EditorHasUnsavedData() = 0;
virtual void GenerateTimeoutSeed() = 0; virtual void GenerateTimeoutSeed() = 0;

View file

@ -41,7 +41,6 @@
#include <engine/shared/datafile.h> #include <engine/shared/datafile.h>
#include <engine/shared/demo.h> #include <engine/shared/demo.h>
#include <engine/shared/filecollection.h> #include <engine/shared/filecollection.h>
#include <engine/shared/mapchecker.h>
#include <engine/shared/network.h> #include <engine/shared/network.h>
#include <engine/shared/packer.h> #include <engine/shared/packer.h>
#include <engine/shared/protocol.h> #include <engine/shared/protocol.h>
@ -55,7 +54,6 @@
#include <game/version.h> #include <game/version.h>
#include <mastersrv/mastersrv.h> #include <mastersrv/mastersrv.h>
#include <versionsrv/versionsrv.h>
#include <engine/client/serverbrowser.h> #include <engine/client/serverbrowser.h>
@ -302,7 +300,7 @@ CClient::CClient() : m_DemoPlayer(&m_SnapshotDelta)
// version-checking // version-checking
m_aVersionStr[0] = '0'; m_aVersionStr[0] = '0';
m_aVersionStr[1] = 0; m_aVersionStr[1] = '\0';
// pinging // pinging
m_PingStartTime = 0; m_PingStartTime = 0;
@ -320,7 +318,9 @@ CClient::CClient() : m_DemoPlayer(&m_SnapshotDelta)
m_MapdownloadCrc = 0; m_MapdownloadCrc = 0;
m_MapdownloadAmount = -1; m_MapdownloadAmount = -1;
m_MapdownloadTotalsize = -1; m_MapdownloadTotalsize = -1;
m_pDDNetRanksTask = NULL;
m_pDDNetInfoTask = NULL;
m_aNews[0] = '\0';
m_CurrentServerInfoRequestTime = -1; m_CurrentServerInfoRequestTime = -1;
@ -345,7 +345,6 @@ CClient::CClient() : m_DemoPlayer(&m_SnapshotDelta)
if (g_Config.m_ClDummy == 0) if (g_Config.m_ClDummy == 0)
m_LastDummyConnectTime = 0; m_LastDummyConnectTime = 0;
m_DDNetSrvListTokenSet = false;
m_ReconnectTime = 0; m_ReconnectTime = 0;
m_GenerateTimeoutSeed = true; m_GenerateTimeoutSeed = true;
@ -1133,128 +1132,6 @@ int CClient::PlayerScoreNameComp(const void *a, const void *b)
void CClient::ProcessConnlessPacket(CNetChunk *pPacket) void CClient::ProcessConnlessPacket(CNetChunk *pPacket)
{ {
// version server
if(m_VersionInfo.m_State == CVersionInfo::STATE_READY && net_addr_comp(&pPacket->m_Address, &m_VersionInfo.m_VersionServeraddr.m_Addr) == 0)
{
// version info
if(pPacket->m_DataSize == (int)(sizeof(VERSIONSRV_VERSION) + sizeof(GAME_RELEASE_VERSION)) &&
mem_comp(pPacket->m_pData, VERSIONSRV_VERSION, sizeof(VERSIONSRV_VERSION)) == 0)
{
char *pVersionData = (char*)pPacket->m_pData + sizeof(VERSIONSRV_VERSION);
int aCurVersion[] = {0,0,0}, aNewVersion[] = {0,0,0};
sscanf(pVersionData, "%d.%d.%d", aNewVersion, aNewVersion+1, aNewVersion+2);
sscanf(GAME_RELEASE_VERSION, "%d.%d.%d", aCurVersion, aCurVersion+1, aCurVersion+2);
bool VersionMatch = mem_comp(aCurVersion, aNewVersion, sizeof aCurVersion) >= 0;
char aVersion[sizeof(GAME_RELEASE_VERSION)];
str_copy(aVersion, pVersionData, sizeof(aVersion));
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "version does %s (%s)",
VersionMatch ? "match" : "NOT match",
aVersion);
m_pConsole->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "client/version", aBuf);
// 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;
mem_zero(&Packet, sizeof(Packet));
Packet.m_ClientID = -1;
Packet.m_Address = m_VersionInfo.m_VersionServeraddr.m_Addr;
Packet.m_pData = VERSIONSRV_GETNEWS;
Packet.m_DataSize = sizeof(VERSIONSRV_GETNEWS);
Packet.m_Flags = NETSENDFLAG_CONNLESS;
m_NetClient[g_Config.m_ClDummy].Send(&Packet);
// request the map version list now
mem_zero(&Packet, sizeof(Packet));
Packet.m_ClientID = -1;
Packet.m_Address = m_VersionInfo.m_VersionServeraddr.m_Addr;
Packet.m_pData = VERSIONSRV_GETMAPLIST;
Packet.m_DataSize = sizeof(VERSIONSRV_GETMAPLIST);
Packet.m_Flags = NETSENDFLAG_CONNLESS;
m_NetClient[g_Config.m_ClDummy].Send(&Packet);
}
// news
if(pPacket->m_DataSize == (int)(sizeof(VERSIONSRV_NEWS) + NEWS_SIZE) &&
mem_comp(pPacket->m_pData, VERSIONSRV_NEWS, sizeof(VERSIONSRV_NEWS)) == 0)
{
if(mem_comp(m_aNews, (char*)pPacket->m_pData + sizeof(VERSIONSRV_NEWS), NEWS_SIZE))
g_Config.m_UiPage = CMenus::PAGE_NEWS;
mem_copy(m_aNews, (char*)pPacket->m_pData + sizeof(VERSIONSRV_NEWS), NEWS_SIZE);
IOHANDLE NewsFile = m_pStorage->OpenFile("ddnet-news.txt", IOFLAG_WRITE, IStorage::TYPE_SAVE);
if(NewsFile)
{
io_write(NewsFile, m_aNews, sizeof(m_aNews));
io_close(NewsFile);
}
}
// ddnet server list
// Packet: VERSIONSRV_DDNETLIST + char[4] Token + int16 comp_length + int16 plain_length + char[comp_length]
if(pPacket->m_DataSize >= (int)(sizeof(VERSIONSRV_DDNETLIST) + 8) &&
mem_comp(pPacket->m_pData, VERSIONSRV_DDNETLIST, sizeof(VERSIONSRV_DDNETLIST)) == 0 &&
mem_comp((char*)pPacket->m_pData+sizeof(VERSIONSRV_DDNETLIST), m_aDDNetSrvListToken, 4) == 0)
{
// reset random token
m_DDNetSrvListTokenSet = false;
int CompLength = *(short*)((char*)pPacket->m_pData+(sizeof(VERSIONSRV_DDNETLIST)+4));
int PlainLength = *(short*)((char*)pPacket->m_pData+(sizeof(VERSIONSRV_DDNETLIST)+6));
if (pPacket->m_DataSize == (int)(sizeof(VERSIONSRV_DDNETLIST) + 8 + CompLength))
{
char aBuf[16384];
uLongf DstLen = sizeof(aBuf);
const char *pComp = (char*)pPacket->m_pData+sizeof(VERSIONSRV_DDNETLIST)+8;
// do decompression of serverlist
if(uncompress((Bytef*)aBuf, &DstLen, (Bytef*)pComp, CompLength) == Z_OK && (int)DstLen == PlainLength)
{
aBuf[DstLen] = '\0';
bool ListChanged = true;
IOHANDLE File = m_pStorage->OpenFile("ddnet-servers.json", IOFLAG_READ, IStorage::TYPE_SAVE);
if(File)
{
char aBuf2[16384];
io_read(File, aBuf2, sizeof(aBuf2));
io_close(File);
if (str_comp(aBuf, aBuf2) == 0)
ListChanged = false;
}
// decompression successful, write plain file
if(ListChanged)
{
IOHANDLE File = m_pStorage->OpenFile("ddnet-servers.json", IOFLAG_WRITE, IStorage::TYPE_SAVE);
if(File)
{
io_write(File, aBuf, PlainLength);
io_close(File);
}
if(g_Config.m_UiPage == CMenus::PAGE_DDNET)
m_ServerBrowser.Refresh(IServerBrowser::TYPE_DDNET);
}
}
}
}
// map version list
if(pPacket->m_DataSize >= (int)sizeof(VERSIONSRV_MAPLIST) &&
mem_comp(pPacket->m_pData, VERSIONSRV_MAPLIST, sizeof(VERSIONSRV_MAPLIST)) == 0)
{
int Size = pPacket->m_DataSize-sizeof(VERSIONSRV_MAPLIST);
int Num = Size/sizeof(CMapVersion);
m_MapChecker.AddMaplist((CMapVersion *)((char*)pPacket->m_pData+sizeof(VERSIONSRV_MAPLIST)), Num);
}
}
//server count from master server //server count from master server
if(pPacket->m_DataSize == (int)sizeof(SERVERBROWSE_COUNT) + 2 && mem_comp(pPacket->m_pData, SERVERBROWSE_COUNT, sizeof(SERVERBROWSE_COUNT)) == 0) if(pPacket->m_DataSize == (int)sizeof(SERVERBROWSE_COUNT) + 2 && mem_comp(pPacket->m_pData, SERVERBROWSE_COUNT, sizeof(SERVERBROWSE_COUNT)) == 0)
{ {
@ -1584,10 +1461,6 @@ void CClient::ProcessServerPacket(CNetChunk *pPacket)
if(m_DummyConnected) if(m_DummyConnected)
DummyDisconnect(0); DummyDisconnect(0);
// check for valid standard map
if(!m_MapChecker.IsMapValid(pMap, MapCrc, MapSize))
pError = "invalid standard map";
for(int i = 0; pMap[i]; i++) // protect the player from nasty map names for(int i = 0; pMap[i]; i++) // protect the player from nasty map names
{ {
if(pMap[i] == '/' || pMap[i] == '\\') if(pMap[i] == '/' || pMap[i] == '\\')
@ -2257,21 +2130,55 @@ void CClient::FinishMapDownload()
} }
} }
void CClient::ResetDDNetRanks() void CClient::ResetDDNetInfo()
{ {
if(m_pDDNetRanksTask) if(m_pDDNetInfoTask)
{ {
m_pDDNetRanksTask->Abort(); m_pDDNetInfoTask->Abort();
delete m_pDDNetRanksTask; delete m_pDDNetInfoTask;
m_pDDNetRanksTask = NULL; m_pDDNetInfoTask = NULL;
} }
} }
void CClient::FinishDDNetRanks() void CClient::FinishDDNetInfo()
{ {
ResetDDNetRanks(); ResetDDNetInfo();
m_pStorage->RenameFile("ddnet-ranks.json.tmp", "ddnet-ranks.json", IStorage::TYPE_SAVE); m_pStorage->RenameFile("ddnet-info.json.tmp", "ddnet-info.json", IStorage::TYPE_SAVE);
m_ServerBrowser.LoadDDNetRanks(); LoadDDNetInfo();
}
void CClient::LoadDDNetInfo()
{
const json_value *pDDNetInfo = m_ServerBrowser.LoadDDNetInfo();
if(!pDDNetInfo)
return;
const json_value *pVersion = json_object_get(pDDNetInfo, "version");
if(pVersion && pVersion->type == json_string)
{
const char *pVersionString = json_string_get(pVersion);
if(str_comp(pVersionString, GAME_RELEASE_VERSION))
{
str_copy(m_aVersionStr, pVersionString, sizeof(m_aVersionStr));
}
else
{
m_aVersionStr[0] = '0';
m_aVersionStr[1] = '\0';
}
}
const json_value *pNews = json_object_get(pDDNetInfo, "news");
if(pNews && pNews->type == json_string)
{
const char *pNewsString = json_string_get(pNews);
if(m_aNews[0] && str_comp(m_aNews, pNewsString))
g_Config.m_UiPage = CMenus::PAGE_NEWS;
str_copy(m_aNews, pNewsString, sizeof(m_aNews));
}
} }
void CClient::PumpNetwork() void CClient::PumpNetwork()
@ -2584,19 +2491,19 @@ void CClient::Update()
} }
} }
if(m_pDDNetRanksTask) if(m_pDDNetInfoTask)
{ {
if(m_pDDNetRanksTask->State() == CFetchTask::STATE_DONE) if(m_pDDNetInfoTask->State() == CFetchTask::STATE_DONE)
FinishDDNetRanks(); FinishDDNetInfo();
else if(m_pDDNetRanksTask->State() == CFetchTask::STATE_ERROR) else if(m_pDDNetInfoTask->State() == CFetchTask::STATE_ERROR)
{ {
dbg_msg("ddnet-ranks", "download failed"); dbg_msg("ddnet-info", "download failed");
ResetDDNetRanks(); ResetDDNetInfo();
} }
else if(m_pDDNetRanksTask->State() == CFetchTask::STATE_ABORTED) else if(m_pDDNetInfoTask->State() == CFetchTask::STATE_ABORTED)
{ {
delete m_pDDNetRanksTask; delete m_pDDNetInfoTask;
m_pDDNetRanksTask = NULL; m_pDDNetInfoTask = NULL;
} }
} }
@ -2618,40 +2525,6 @@ void CClient::Update()
} }
} }
void CClient::VersionUpdate()
{
if(m_VersionInfo.m_State == CVersionInfo::STATE_INIT)
{
Engine()->HostLookup(&m_VersionInfo.m_VersionServeraddr, "version.ddnet.tw", m_NetClient[0].NetType());
m_VersionInfo.m_State = CVersionInfo::STATE_START;
}
else if(m_VersionInfo.m_State == CVersionInfo::STATE_START)
{
if(m_VersionInfo.m_VersionServeraddr.m_Job.Status() == CJob::STATE_DONE)
{
CNetChunk Packet;
mem_zero(&Packet, sizeof(Packet));
m_VersionInfo.m_VersionServeraddr.m_Addr.port = VERSIONSRV_PORT;
Packet.m_ClientID = -1;
Packet.m_Address = m_VersionInfo.m_VersionServeraddr.m_Addr;
Packet.m_pData = VERSIONSRV_GETVERSION;
Packet.m_DataSize = sizeof(VERSIONSRV_GETVERSION);
Packet.m_Flags = NETSENDFLAG_CONNLESS;
m_NetClient[0].Send(&Packet);
m_VersionInfo.m_State = CVersionInfo::STATE_READY;
}
}
}
void CClient::CheckVersionUpdate()
{
m_VersionInfo.m_State = CVersionInfo::STATE_START;
}
void CClient::RegisterInterfaces() void CClient::RegisterInterfaces()
{ {
Kernel()->RegisterInterface(static_cast<IDemoRecorder*>(&m_DemoRecorder[RECORDER_MANUAL]), false); Kernel()->RegisterInterface(static_cast<IDemoRecorder*>(&m_DemoRecorder[RECORDER_MANUAL]), false);
@ -2694,13 +2567,6 @@ void CClient::InitInterfaces()
m_Friends.Init(); m_Friends.Init();
m_Foes.Init(true); m_Foes.Init(true);
IOHANDLE newsFile = m_pStorage->OpenFile("ddnet-news.txt", IOFLAG_READ, IStorage::TYPE_SAVE);
if (newsFile)
{
io_read(newsFile, m_aNews, NEWS_SIZE);
io_close(newsFile);
}
} }
void CClient::Run() void CClient::Run()
@ -2821,8 +2687,10 @@ void CClient::Run()
m_Fifo.Init(m_pConsole, g_Config.m_ClInputFifo, CFGFLAG_CLIENT); m_Fifo.Init(m_pConsole, g_Config.m_ClInputFifo, CFGFLAG_CLIENT);
#endif #endif
RequestDDNetSrvList(); // loads the existing ddnet-info.json file if it exists
RequestDDNetRanks(); LoadDDNetInfo();
// but still request the new one from server
RequestDDNetInfo();
bool LastD = false; bool LastD = false;
bool LastQ = false; bool LastQ = false;
@ -2835,9 +2703,6 @@ void CClient::Run()
{ {
set_new_tick(); set_new_tick();
//
VersionUpdate();
// handle pending connects // handle pending connects
if(m_aCmdConnect[0]) if(m_aCmdConnect[0])
{ {
@ -3754,38 +3619,16 @@ bool CClient::RaceRecordIsRecording()
return m_DemoRecorder[RECORDER_RACE].IsRecording(); return m_DemoRecorder[RECORDER_RACE].IsRecording();
} }
void CClient::RequestDDNetSrvList() void CClient::RequestDDNetInfo()
{
// request ddnet server list
// generate new token
for (int i = 0; i < 4; i++)
m_aDDNetSrvListToken[i] = rand()&0xff;
m_DDNetSrvListTokenSet = true;
char aData[sizeof(VERSIONSRV_GETDDNETLIST)+4];
mem_copy(aData, VERSIONSRV_GETDDNETLIST, sizeof(VERSIONSRV_GETDDNETLIST));
mem_copy(aData+sizeof(VERSIONSRV_GETDDNETLIST), m_aDDNetSrvListToken, 4); // add token
CNetChunk Packet;
mem_zero(&Packet, sizeof(Packet));
Packet.m_ClientID = -1;
Packet.m_Address = m_VersionInfo.m_VersionServeraddr.m_Addr;
Packet.m_pData = aData;
Packet.m_DataSize = sizeof(VERSIONSRV_GETDDNETLIST)+4;
Packet.m_Flags = NETSENDFLAG_CONNLESS;
m_NetClient[g_Config.m_ClDummy].Send(&Packet);
}
void CClient::RequestDDNetRanks()
{ {
char aUrl[256]; char aUrl[256];
char aEscaped[128]; char aEscaped[128];
Fetcher()->Escape(aEscaped, sizeof(aEscaped), g_Config.m_PlayerName); Fetcher()->Escape(aEscaped, sizeof(aEscaped), g_Config.m_PlayerName);
str_format(aUrl, sizeof(aUrl), "https://ddnet.tw/players/?json=%s", aEscaped); str_format(aUrl, sizeof(aUrl), "https://info.ddnet.tw/info?name=%s", aEscaped);
m_pDDNetRanksTask = new CFetchTask(true, /*UseDDNetCA*/ true); m_pDDNetInfoTask = new CFetchTask(true, /*UseDDNetCA*/ true);
Fetcher()->QueueAdd(m_pDDNetRanksTask, aUrl, "ddnet-ranks.json.tmp", IStorage::TYPE_SAVE); Fetcher()->QueueAdd(m_pDDNetInfoTask, aUrl, "ddnet-info.json.tmp", IStorage::TYPE_SAVE);
} }
int CClient::GetPredictionTime() int CClient::GetPredictionTime()

View file

@ -80,7 +80,6 @@ class CClient : public IClient, public CDemoPlayer::IListener
class CUpdater m_Updater; class CUpdater m_Updater;
class CFriends m_Friends; class CFriends m_Friends;
class CFriends m_Foes; class CFriends m_Foes;
class CMapChecker m_MapChecker;
char m_aServerAddressStr[256]; char m_aServerAddressStr[256];
@ -135,7 +134,8 @@ class CClient : public IClient, public CDemoPlayer::IListener
int m_MapdownloadCrc; int m_MapdownloadCrc;
int m_MapdownloadAmount; int m_MapdownloadAmount;
int m_MapdownloadTotalsize; int m_MapdownloadTotalsize;
CFetchTask *m_pDDNetRanksTask;
CFetchTask *m_pDDNetInfoTask;
// time // time
CSmoothTime m_GameTime[2]; CSmoothTime m_GameTime[2];
@ -195,9 +195,6 @@ class CClient : public IClient, public CDemoPlayer::IListener
void GraphicsThread(); void GraphicsThread();
vec3 GetColorV3(int v); vec3 GetColorV3(int v);
char m_aDDNetSrvListToken[4];
bool m_DDNetSrvListTokenSet;
#if defined(CONF_FAMILY_UNIX) #if defined(CONF_FAMILY_UNIX)
CFifo m_Fifo; CFifo m_Fifo;
#endif #endif
@ -244,8 +241,6 @@ public:
virtual bool InputExists(int Tick); virtual bool InputExists(int Tick);
const char *LatestVersion(); const char *LatestVersion();
void VersionUpdate();
void CheckVersionUpdate();
// ------ state handling ----- // ------ state handling -----
void SetState(int s); void SetState(int s);
@ -299,8 +294,11 @@ public:
void ResetMapDownload(); void ResetMapDownload();
void FinishMapDownload(); void FinishMapDownload();
void ResetDDNetRanks();
void FinishDDNetRanks(); void RequestDDNetInfo();
void ResetDDNetInfo();
void FinishDDNetInfo();
void LoadDDNetInfo();
virtual CFetchTask *MapDownloadTask() { return m_pMapdownloadTask; } virtual CFetchTask *MapDownloadTask() { return m_pMapdownloadTask; }
virtual const char *MapDownloadName() { return m_aMapdownloadName; } virtual const char *MapDownloadName() { return m_aMapdownloadName; }
@ -394,8 +392,6 @@ public:
virtual void DemoSliceEnd(); virtual void DemoSliceEnd();
virtual void DemoSlice(const char *pDstPath, CLIENTFUNC_FILTER pfnFilter, void *pUser); virtual void DemoSlice(const char *pDstPath, CLIENTFUNC_FILTER pfnFilter, void *pUser);
void RequestDDNetSrvList();
void RequestDDNetRanks();
bool EditorHasUnsavedData() { return m_pEditor->HasUnsavedData(); } bool EditorHasUnsavedData() { return m_pEditor->HasUnsavedData(); }
virtual IFriends* Foes() {return &m_Foes; } virtual IFriends* Foes() {return &m_Foes; }

View file

@ -63,7 +63,13 @@ CServerBrowser::CServerBrowser()
m_BroadcastTime = 0; m_BroadcastTime = 0;
m_BroadcastExtraToken = -1; m_BroadcastExtraToken = -1;
m_pDDNetRanks = 0; m_pDDNetInfo = 0;
}
CServerBrowser::~CServerBrowser()
{
if(m_pDDNetInfo)
json_value_free(m_pDDNetInfo);
} }
void CServerBrowser::SetBaseInfo(class CNetClient *pClient, const char *pNetVersion) void CServerBrowser::SetBaseInfo(class CNetClient *pClient, const char *pNetVersion)
@ -550,7 +556,6 @@ void CServerBrowser::Refresh(int Type)
// next token // next token
m_CurrentToken = (m_CurrentToken+1)&0xff; m_CurrentToken = (m_CurrentToken+1)&0xff;
//
m_ServerlistType = Type; m_ServerlistType = Type;
if(Type == IServerBrowser::TYPE_LAN) if(Type == IServerBrowser::TYPE_LAN)
@ -593,9 +598,6 @@ void CServerBrowser::Refresh(int Type)
} }
else if(Type == IServerBrowser::TYPE_DDNET) else if(Type == IServerBrowser::TYPE_DDNET)
{ {
LoadDDNetServers();
LoadDDNetRanks();
// remove unknown elements of exclude list // remove unknown elements of exclude list
DDNetCountryFilterClean(); DDNetCountryFilterClean();
DDNetTypeFilterClean(); DDNetTypeFilterClean();
@ -926,31 +928,23 @@ void CServerBrowser::RemoveFavorite(const NETADDR &Addr)
void CServerBrowser::LoadDDNetServers() void CServerBrowser::LoadDDNetServers()
{ {
if (!m_pDDNetInfo)
return;
// parse JSON
const json_value *pServers = json_object_get(m_pDDNetInfo, "servers");
if (!pServers || pServers->type != json_array)
return;
// reset servers / countries // reset servers / countries
m_NumDDNetCountries = 0; m_NumDDNetCountries = 0;
m_NumDDNetTypes = 0; m_NumDDNetTypes = 0;
// load ddnet server list for (int i = 0; i < json_array_length(pServers) && m_NumDDNetCountries < MAX_DDNET_COUNTRIES; i++)
IStorage *pStorage = Kernel()->RequestInterface<IStorage>();
IOHANDLE File = pStorage->OpenFile("ddnet-servers.json", IOFLAG_READ, IStorage::TYPE_ALL);
if(!File)
return;
char aBuf[4096*4];
mem_zero(aBuf, sizeof(aBuf));
io_read(File, aBuf, sizeof(aBuf));
io_close(File);
// parse JSON
json_value *pCountries = json_parse(aBuf, sizeof(aBuf));
if (pCountries && pCountries->type == json_array)
{
for (int i = 0; i < json_array_length(pCountries) && m_NumDDNetCountries < MAX_DDNET_COUNTRIES; i++)
{ {
// pSrv - { name, flagId, servers } // pSrv - { name, flagId, servers }
const json_value *pSrv = json_array_get(pCountries, i); const json_value *pSrv = json_array_get(pServers, i);
const json_value *pTypes = json_object_get(pSrv, "servers"); const json_value *pTypes = json_object_get(pSrv, "servers");
const json_value *pName = json_object_get(pSrv, "name"); const json_value *pName = json_object_get(pSrv, "name");
const json_value *pFlagID = json_object_get(pSrv, "flagId"); const json_value *pFlagID = json_object_get(pSrv, "flagId");
@ -975,6 +969,12 @@ void CServerBrowser::LoadDDNetServers()
const char *pType = pTypes->u.object.values[t].name; const char *pType = pTypes->u.object.values[t].name;
const json_value *pAddrs = pTypes->u.object.values[t].value; const json_value *pAddrs = pTypes->u.object.values[t].value;
if (pAddrs->type != json_array)
{
dbg_msg("client_srvbrowse", "invalid attributes");
continue;
}
// add type // add type
if(json_array_length(pAddrs) > 0 && m_NumDDNetTypes < MAX_DDNET_TYPES) if(json_array_length(pAddrs) > 0 && m_NumDDNetTypes < MAX_DDNET_TYPES)
{ {
@ -995,6 +995,11 @@ void CServerBrowser::LoadDDNetServers()
for (int g = 0; g < json_array_length(pAddrs); g++, pCntr->m_NumServers++) for (int g = 0; g < json_array_length(pAddrs); g++, pCntr->m_NumServers++)
{ {
const json_value *pAddr = json_array_get(pAddrs, g); const json_value *pAddr = json_array_get(pAddrs, g);
if (pAddr->type != json_string)
{
dbg_msg("client_srvbrowse", "invalid attributes");
continue;
}
const char *pStr = json_string_get(pAddr); const char *pStr = json_string_get(pAddr);
net_addr_from_str(&pCntr->m_aServers[pCntr->m_NumServers], pStr); net_addr_from_str(&pCntr->m_aServers[pCntr->m_NumServers], pStr);
str_copy(pCntr->m_aTypes[pCntr->m_NumServers], pType, sizeof(pCntr->m_aTypes[pCntr->m_NumServers])); str_copy(pCntr->m_aTypes[pCntr->m_NumServers], pType, sizeof(pCntr->m_aTypes[pCntr->m_NumServers]));
@ -1003,17 +1008,46 @@ void CServerBrowser::LoadDDNetServers()
m_NumDDNetCountries++; m_NumDDNetCountries++;
} }
}
if (pCountries)
json_value_free(pCountries);
} }
void CServerBrowser::LoadDDNetRanks() void CServerBrowser::LoadDDNetRanks()
{ {
// load ddnet ranks list for(int i = 0; i < m_NumServers; i++)
{
if(m_ppServerlist[i]->m_Info.m_aMap[0])
m_ppServerlist[i]->m_Info.m_HasRank = HasRank(m_ppServerlist[i]->m_Info.m_aMap);
}
}
int CServerBrowser::HasRank(const char *pMap)
{
if(m_ServerlistType != IServerBrowser::TYPE_DDNET || !m_pDDNetInfo)
return -1;
const json_value *pDDNetRanks = json_object_get(m_pDDNetInfo, "maps");
if(!pDDNetRanks || pDDNetRanks->type != json_array)
return -1;
for (int i = 0; i < json_array_length(pDDNetRanks); i++)
{
const json_value *pJson = json_array_get(pDDNetRanks, i);
if(!pJson || pJson->type != json_string)
continue;
const char *pStr = json_string_get(pJson);
if(str_comp(pMap, pStr) == 0)
return 1;
}
return 0;
}
void CServerBrowser::LoadDDNetInfoJson()
{
IStorage *pStorage = Kernel()->RequestInterface<IStorage>(); IStorage *pStorage = Kernel()->RequestInterface<IStorage>();
IOHANDLE File = pStorage->OpenFile("ddnet-ranks.json", IOFLAG_READ, IStorage::TYPE_ALL); IOHANDLE File = pStorage->OpenFile("ddnet-info.json", IOFLAG_READ, IStorage::TYPE_ALL);
if(!File) if(!File)
return; return;
@ -1031,34 +1065,31 @@ void CServerBrowser::LoadDDNetRanks()
io_read(File, pBuf, Length); io_read(File, pBuf, Length);
io_close(File); io_close(File);
m_pDDNetRanks = json_parse(pBuf, Length); if(m_pDDNetInfo)
json_value_free(m_pDDNetInfo);
m_pDDNetInfo = json_parse(pBuf, Length);
mem_free(pBuf); mem_free(pBuf);
for(int i = 0; i < m_NumServers; i++) if(m_pDDNetInfo->type != json_object)
{ {
if(m_ppServerlist[i]->m_Info.m_aMap[0]) json_value_free(m_pDDNetInfo);
m_ppServerlist[i]->m_Info.m_HasRank = HasRank(m_ppServerlist[i]->m_Info.m_aMap); m_pDDNetInfo = 0;
} }
} }
int CServerBrowser::HasRank(const char *pMap) const json_value *CServerBrowser::LoadDDNetInfo()
{ {
if(m_ServerlistType != IServerBrowser::TYPE_DDNET) LoadDDNetInfoJson();
return -1; LoadDDNetServers();
if(!m_pDDNetRanks) if(m_NumServers == 0)
return -1; Refresh(m_ServerlistType);
else
LoadDDNetRanks();
for (int i = 0; i < json_array_length(m_pDDNetRanks); i++) return m_pDDNetInfo;
{
const json_value *pJson = json_array_get(m_pDDNetRanks, i);
const char *pStr = json_string_get(pJson);
if(str_comp(pMap, pStr) == 0)
return 1;
}
return 0;
} }
bool CServerBrowser::IsRefreshing() const bool CServerBrowser::IsRefreshing() const

View file

@ -4,6 +4,7 @@
#define ENGINE_CLIENT_SERVERBROWSER_H #define ENGINE_CLIENT_SERVERBROWSER_H
#include <engine/serverbrowser.h> #include <engine/serverbrowser.h>
#include <engine/shared/memheap.h>
#include <engine/external/json-parser/json.h> #include <engine/external/json-parser/json.h>
class CServerBrowser : public IServerBrowser class CServerBrowser : public IServerBrowser
@ -58,6 +59,7 @@ public:
}; };
CServerBrowser(); CServerBrowser();
virtual ~CServerBrowser();
// interface functions // interface functions
void Refresh(int Type); void Refresh(int Type);
@ -74,8 +76,10 @@ public:
void AddFavorite(const NETADDR &Addr); void AddFavorite(const NETADDR &Addr);
void RemoveFavorite(const NETADDR &Addr); void RemoveFavorite(const NETADDR &Addr);
void LoadDDNetServers();
void LoadDDNetRanks(); void LoadDDNetRanks();
void LoadDDNetServers();
void LoadDDNetInfoJson();
const json_value *LoadDDNetInfo();
int HasRank(const char *pMap); int HasRank(const char *pMap);
int NumDDNetCountries() { return m_NumDDNetCountries; }; int NumDDNetCountries() { return m_NumDDNetCountries; };
int GetDDNetCountryFlag(int Index) { return m_aDDNetCountries[Index].m_FlagID; }; int GetDDNetCountryFlag(int Index) { return m_aDDNetCountries[Index].m_FlagID; };
@ -121,7 +125,8 @@ private:
char m_aDDNetTypes[MAX_DDNET_TYPES][32]; char m_aDDNetTypes[MAX_DDNET_TYPES][32];
int m_NumDDNetTypes; int m_NumDDNetTypes;
json_value *m_pDDNetRanks;
json_value *m_pDDNetInfo;
CServerEntry *m_aServerlistIp[256]; // ip hash list CServerEntry *m_aServerlistIp[256]; // ip hash list

View file

@ -20,7 +20,6 @@
#include <engine/shared/demo.h> #include <engine/shared/demo.h>
#include <engine/shared/econ.h> #include <engine/shared/econ.h>
#include <engine/shared/filecollection.h> #include <engine/shared/filecollection.h>
#include <engine/shared/mapchecker.h>
#include <engine/shared/netban.h> #include <engine/shared/netban.h>
#include <engine/shared/network.h> #include <engine/shared/network.h>
#include <engine/shared/packer.h> #include <engine/shared/packer.h>
@ -1628,22 +1627,10 @@ char *CServer::GetMapName()
int CServer::LoadMap(const char *pMapName) int CServer::LoadMap(const char *pMapName)
{ {
//DATAFILE *df;
char aBuf[512]; char aBuf[512];
str_format(aBuf, sizeof(aBuf), "maps/%s.map", pMapName); str_format(aBuf, sizeof(aBuf), "maps/%s.map", pMapName);
GameServer()->OnMapChange(aBuf, sizeof(aBuf)); GameServer()->OnMapChange(aBuf, sizeof(aBuf));
/*df = datafile_load(buf);
if(!df)
return 0;*/
// check for valid standard map
if(!m_MapChecker.ReadAndValidateMap(Storage(), aBuf, IStorage::TYPE_ALL))
{
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "mapchecker", "invalid standard map");
return 0;
}
if(!m_pMap->Load(aBuf)) if(!m_pMap->Load(aBuf))
return 0; return 0;
@ -1671,7 +1658,6 @@ int CServer::LoadMap(const char *pMapName)
Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "server", aBufMsg); Console()->Print(IConsole::OUTPUT_LEVEL_ADDINFO, "server", aBufMsg);
str_copy(m_aCurrentMap, pMapName, sizeof(m_aCurrentMap)); str_copy(m_aCurrentMap, pMapName, sizeof(m_aCurrentMap));
//map_set(df);
// load complete map into memory for download // load complete map into memory for download
{ {
@ -1704,7 +1690,6 @@ int CServer::Run()
g_UuidManager.DebugDump(); g_UuidManager.DebugDump();
} }
//
m_PrintCBIndex = Console()->RegisterPrintCallback(g_Config.m_ConsoleOutputLevel, SendRconLineAuthed, this); m_PrintCBIndex = Console()->RegisterPrintCallback(g_Config.m_ConsoleOutputLevel, SendRconLineAuthed, this);
// load map // load map

View file

@ -14,7 +14,6 @@
#include <engine/server/register.h> #include <engine/server/register.h>
#include <engine/shared/console.h> #include <engine/shared/console.h>
#include <base/math.h> #include <base/math.h>
#include <engine/shared/mapchecker.h>
#include <engine/shared/econ.h> #include <engine/shared/econ.h>
#include <engine/shared/fifo.h> #include <engine/shared/fifo.h>
#include <engine/shared/netban.h> #include <engine/shared/netban.h>
@ -202,7 +201,6 @@ public:
CDemoRecorder m_aDemoRecorder[MAX_CLIENTS+1]; CDemoRecorder m_aDemoRecorder[MAX_CLIENTS+1];
CRegister m_Register; CRegister m_Register;
CMapChecker m_MapChecker;
CAuthManager m_AuthManager; CAuthManager m_AuthManager;
int m_RconRestrict; int m_RconRestrict;

View file

@ -1,107 +0,0 @@
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
/* If you are missing that file, acquire a complete release at teeworlds.com. */
#include <base/math.h>
#include <base/system.h>
#include <engine/storage.h>
#include <versionsrv/versionsrv.h>
#include <versionsrv/mapversions.h>
#include "datafile.h"
#include "memheap.h"
#include "mapchecker.h"
CMapChecker::CMapChecker()
{
Init();
SetDefaults();
}
void CMapChecker::Init()
{
m_Whitelist.Reset();
m_pFirst = 0;
m_RemoveDefaultList = false;
}
void CMapChecker::SetDefaults()
{
AddMaplist(s_aMapVersionList, s_NumMapVersionItems);
m_RemoveDefaultList = true;
}
void CMapChecker::AddMaplist(CMapVersion *pMaplist, int Num)
{
if(m_RemoveDefaultList)
Init();
for(int i = 0; i < Num; ++i)
{
CWhitelistEntry *pEntry = (CWhitelistEntry *)m_Whitelist.Allocate(sizeof(CWhitelistEntry));
pEntry->m_pNext = m_pFirst;
m_pFirst = pEntry;
str_copy(pEntry->m_aMapName, pMaplist[i].m_aName, sizeof(pEntry->m_aMapName));
pEntry->m_MapCrc = (pMaplist[i].m_aCrc[0]<<24) | (pMaplist[i].m_aCrc[1]<<16) | (pMaplist[i].m_aCrc[2]<<8) | pMaplist[i].m_aCrc[3];
pEntry->m_MapSize = (pMaplist[i].m_aSize[0]<<24) | (pMaplist[i].m_aSize[1]<<16) | (pMaplist[i].m_aSize[2]<<8) | pMaplist[i].m_aSize[3];
}
}
bool CMapChecker::IsMapValid(const char *pMapName, unsigned MapCrc, unsigned MapSize)
{
bool StandardMap = false;
for(CWhitelistEntry *pCurrent = m_pFirst; pCurrent; pCurrent = pCurrent->m_pNext)
{
if(str_comp(pCurrent->m_aMapName, pMapName) == 0)
{
StandardMap = true;
if(pCurrent->m_MapCrc == MapCrc && pCurrent->m_MapSize == MapSize)
return true;
}
}
return StandardMap?false:true;
}
bool CMapChecker::ReadAndValidateMap(IStorage *pStorage, const char *pFilename, int StorageType)
{
bool LoadedMapInfo = false;
bool StandardMap = false;
unsigned MapCrc = 0;
unsigned MapSize = 0;
// extract map name
char aMapName[MAX_MAP_LENGTH];
const char *pExtractedName = pFilename;
const char *pEnd = 0;
for(const char *pSrc = pFilename; *pSrc; ++pSrc)
{
if(*pSrc == '/' || *pSrc == '\\')
pExtractedName = pSrc+1;
else if(*pSrc == '.')
pEnd = pSrc;
}
int Length = (int)(pEnd - pExtractedName);
if(Length <= 0 || Length >= MAX_MAP_LENGTH)
return true;
str_copy(aMapName, pExtractedName, min((int)MAX_MAP_LENGTH, (int)(pEnd-pExtractedName+1)));
// check for valid map
for(CWhitelistEntry *pCurrent = m_pFirst; pCurrent; pCurrent = pCurrent->m_pNext)
{
if(str_comp(pCurrent->m_aMapName, aMapName) == 0)
{
StandardMap = true;
if(!LoadedMapInfo)
{
if(!CDataFileReader::GetCrcSize(pStorage, pFilename, StorageType, &MapCrc, &MapSize))
return true;
LoadedMapInfo = true;
}
if(pCurrent->m_MapCrc == MapCrc && pCurrent->m_MapSize == MapSize)
return true;
}
}
return StandardMap?false:true;
}

View file

@ -1,38 +0,0 @@
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
/* If you are missing that file, acquire a complete release at teeworlds.com. */
#ifndef ENGINE_SHARED_MAPCHECKER_H
#define ENGINE_SHARED_MAPCHECKER_H
#include "memheap.h"
class CMapChecker
{
enum
{
MAX_MAP_LENGTH=8,
};
struct CWhitelistEntry
{
char m_aMapName[MAX_MAP_LENGTH];
unsigned m_MapCrc;
unsigned m_MapSize;
CWhitelistEntry *m_pNext;
};
class CHeap m_Whitelist;
CWhitelistEntry *m_pFirst;
bool m_RemoveDefaultList;
void Init();
void SetDefaults();
public:
CMapChecker();
void AddMaplist(struct CMapVersion *pMaplist, int Num);
bool IsMapValid(const char *pMapName, unsigned MapCrc, unsigned MapSize);
bool ReadAndValidateMap(class IStorage *pStorage, const char *pFilename, int StorageType);
};
#endif

View file

@ -31,7 +31,6 @@
#include <game/client/lineinput.h> #include <game/client/lineinput.h>
#include <game/localization.h> #include <game/localization.h>
#include <mastersrv/mastersrv.h> #include <mastersrv/mastersrv.h>
#include <versionsrv/versionsrv.h>
#include "countryflags.h" #include "countryflags.h"
#include "menus.h" #include "menus.h"
@ -696,7 +695,10 @@ int CMenus::RenderMenubar(CUIRect r)
if(DoButton_MenuTab(&s_DDNetButton, Localize("DDNet"), m_ActivePage==PAGE_DDNET, &Button, CUI::CORNER_TR)) if(DoButton_MenuTab(&s_DDNetButton, Localize("DDNet"), m_ActivePage==PAGE_DDNET, &Button, CUI::CORNER_TR))
{ {
if(ServerBrowser()->GetCurrentType() != IServerBrowser::TYPE_DDNET) if(ServerBrowser()->GetCurrentType() != IServerBrowser::TYPE_DDNET)
{
Client()->RequestDDNetInfo();
ServerBrowser()->Refresh(IServerBrowser::TYPE_DDNET); ServerBrowser()->Refresh(IServerBrowser::TYPE_DDNET);
}
NewPage = PAGE_DDNET; NewPage = PAGE_DDNET;
m_DoubleClickIndex = -1; m_DoubleClickIndex = -1;
} }

View file

@ -1397,8 +1397,7 @@ void CMenus::RenderServerbrowser(CUIRect MainView)
else if(g_Config.m_UiPage == PAGE_DDNET) else if(g_Config.m_UiPage == PAGE_DDNET)
{ {
// start a new serverlist request // start a new serverlist request
Client()->RequestDDNetSrvList(); Client()->RequestDDNetInfo();
Client()->RequestDDNetRanks();
ServerBrowser()->Refresh(IServerBrowser::TYPE_DDNET); ServerBrowser()->Refresh(IServerBrowser::TYPE_DDNET);
} }
m_DoubleClickIndex = -1; m_DoubleClickIndex = -1;

View file

@ -2155,7 +2155,7 @@ void CMenus::RenderSettingsDDNet(CUIRect MainView)
g_Config.m_ClHttpMapDownload ^= 1; g_Config.m_ClHttpMapDownload ^= 1;
} }
//Updater // Updater
#if defined(CONF_FAMILY_WINDOWS) || (defined(CONF_PLATFORM_LINUX) && !defined(__ANDROID__)) #if defined(CONF_FAMILY_WINDOWS) || (defined(CONF_PLATFORM_LINUX) && !defined(__ANDROID__))
{ {
Left.HSplitTop(20.0f, &Label, &Left); Left.HSplitTop(20.0f, &Label, &Left);
@ -2163,7 +2163,7 @@ void CMenus::RenderSettingsDDNet(CUIRect MainView)
char aBuf[256]; char aBuf[256];
int State = Updater()->GetCurrentState(); int State = Updater()->GetCurrentState();
//Update Button // Update Button
if(NeedUpdate && State <= IUpdater::CLEAN) if(NeedUpdate && State <= IUpdater::CLEAN)
{ {
str_format(aBuf, sizeof(aBuf), Localize("DDNet %s is available:"), Client()->LatestVersion()); str_format(aBuf, sizeof(aBuf), Localize("DDNet %s is available:"), Client()->LatestVersion());
@ -2188,7 +2188,7 @@ void CMenus::RenderSettingsDDNet(CUIRect MainView)
static int s_ButtonUpdate = 0; static int s_ButtonUpdate = 0;
if(DoButton_Menu(&s_ButtonUpdate, Localize("Check now"), 0, &Button)) if(DoButton_Menu(&s_ButtonUpdate, Localize("Check now"), 0, &Button))
{ {
Client()->CheckVersionUpdate(); Client()->RequestDDNetInfo();
} }
} }
UI()->DoLabelScaled(&Label, aBuf, 14.0f, -1); UI()->DoLabelScaled(&Label, aBuf, 14.0f, -1);

View file

@ -1,22 +0,0 @@
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
/* If you are missing that file, acquire a complete release at teeworlds.com. */
#ifndef VERSIONSRV_MAPVERSIONS_H
#define VERSIONSRV_MAPVERSIONS_H
static CMapVersion s_aMapVersionList[] = {
{"ctf1", {0x06, 0xb5, 0xf1, 0x17}, {0x00, 0x00, 0x12, 0x38}},
{"ctf2", {0x27, 0xbc, 0x5e, 0xac}, {0x00, 0x00, 0x64, 0x1a}},
{"ctf3", {0xa3, 0x73, 0x9d, 0x41}, {0x00, 0x00, 0x17, 0x0f}},
{"ctf4", {0xbe, 0x7c, 0x4d, 0xb9}, {0x00, 0x00, 0x2e, 0xfe}},
{"ctf5", {0xd9, 0x21, 0x29, 0xa0}, {0x00, 0x00, 0x2f, 0x4c}},
{"ctf6", {0x28, 0xc8, 0x43, 0x51}, {0x00, 0x00, 0x69, 0x2f}},
{"ctf7", {0x1d, 0x35, 0x98, 0x72}, {0x00, 0x00, 0x15, 0x87}},
{"dm1", {0xf2, 0x15, 0x9e, 0x6e}, {0x00, 0x00, 0x16, 0xad}},
{"dm2", {0x71, 0x83, 0x98, 0x78}, {0x00, 0x00, 0x21, 0xdf}},
{"dm6", {0x47, 0x4d, 0xa2, 0x35}, {0x00, 0x00, 0x1e, 0x95}},
{"dm7", {0x42, 0x6d, 0xa1, 0x67}, {0x00, 0x00, 0x27, 0x2a}},
{"dm8", {0x85, 0xf1, 0x1e, 0xd6}, {0x00, 0x00, 0x9e, 0xbd}},
{"dm9", {0x42, 0xd4, 0x77, 0x7e}, {0x00, 0x00, 0x20, 0x11}},
};
static const int s_NumMapVersionItems = sizeof(s_aMapVersionList)/sizeof(CMapVersion);
#endif

View file

@ -1,240 +0,0 @@
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
/* If you are missing that file, acquire a complete release at teeworlds.com. */
#include <base/system.h>
#include <engine/shared/network.h>
#include <game/version.h>
#include "versionsrv.h"
#include "mapversions.h"
#include <zlib.h>
enum {
MAX_MAPS_PER_PACKET=48,
MAX_PACKETS=16,
MAX_MAPS=MAX_MAPS_PER_PACKET*MAX_PACKETS,
};
struct CPacketData
{
int m_Size;
struct {
unsigned char m_aHeader[sizeof(VERSIONSRV_MAPLIST)];
CMapVersion m_aMaplist[MAX_MAPS_PER_PACKET];
} m_Data;
};
CPacketData m_aPackets[MAX_PACKETS];
static int m_NumPackets = 0;
unsigned char m_aNews[NEWS_SIZE];
unsigned char m_aServerList[DDNETLIST_SIZE];
int m_ServerListPlainLength = 0;
int m_ServerListCompLength = 0;
bool m_ServerListLoaded = false;
static CNetClient g_NetOp; // main
void BuildPackets()
{
CMapVersion *pCurrent = &s_aMapVersionList[0];
int ServersLeft = s_NumMapVersionItems;
m_NumPackets = 0;
while(ServersLeft && m_NumPackets < MAX_PACKETS)
{
int Chunk = ServersLeft;
if(Chunk > MAX_MAPS_PER_PACKET)
Chunk = MAX_MAPS_PER_PACKET;
ServersLeft -= Chunk;
// copy header
mem_copy(m_aPackets[m_NumPackets].m_Data.m_aHeader, VERSIONSRV_MAPLIST, sizeof(VERSIONSRV_MAPLIST));
// copy map versions
for(int i = 0; i < Chunk; i++)
{
m_aPackets[m_NumPackets].m_Data.m_aMaplist[i] = *pCurrent;
pCurrent++;
}
m_aPackets[m_NumPackets].m_Size = sizeof(VERSIONSRV_MAPLIST) + sizeof(CMapVersion)*Chunk;
m_NumPackets++;
}
}
void ReadNews()
{
IOHANDLE NewsFile = io_open("news", IOFLAG_READ);
if (!NewsFile)
return;
io_read(NewsFile, m_aNews, NEWS_SIZE);
io_close(NewsFile);
}
void ReadServerList()
{
mem_zero(m_aServerList, sizeof(m_aServerList));
IOHANDLE File = io_open("serverlist.json", IOFLAG_READ);
if (!File)
return;
int PlainLength = io_length(File);
char aPlain[16384];
io_read(File, aPlain, sizeof(aPlain));
io_close(File);
// compress
uLongf DstLen = DDNETLIST_SIZE;
if (compress((Bytef*)m_aServerList, &DstLen, (Bytef*)aPlain, PlainLength) == Z_OK)
{
m_ServerListLoaded = true;
m_ServerListPlainLength = PlainLength;
m_ServerListCompLength = DstLen;
}
}
void SendVer(NETADDR *pAddr)
{
CNetChunk p;
unsigned char aData[sizeof(VERSIONSRV_VERSION) + sizeof(GAME_RELEASE_VERSION)];
mem_copy(aData, VERSIONSRV_VERSION, sizeof(VERSIONSRV_VERSION));
mem_copy(aData + sizeof(VERSIONSRV_VERSION), GAME_RELEASE_VERSION, sizeof(GAME_RELEASE_VERSION));
p.m_ClientID = -1;
p.m_Address = *pAddr;
p.m_Flags = NETSENDFLAG_CONNLESS;
p.m_pData = aData;
p.m_DataSize = sizeof(aData);
g_NetOp.Send(&p);
}
void SendNews(NETADDR *pAddr)
{
CNetChunk p;
unsigned char aData[NEWS_SIZE + sizeof(VERSIONSRV_NEWS)];
mem_copy(aData, VERSIONSRV_NEWS, sizeof(VERSIONSRV_NEWS));
mem_copy(aData + sizeof(VERSIONSRV_NEWS), m_aNews, NEWS_SIZE);
p.m_ClientID = -1;
p.m_Address = *pAddr;
p.m_Flags = NETSENDFLAG_CONNLESS;
p.m_pData = aData;
p.m_DataSize = sizeof(aData);
g_NetOp.Send(&p);
}
// Packet: VERSIONSRV_DDNETLIST + char[4] Token + int16 comp_length + int16 plain_length + char[comp_length]
void SendServerList(NETADDR *pAddr, const char *Token)
{
CNetChunk p;
unsigned char aData[16384];
short WordCompLength = m_ServerListCompLength;
short WordPlainLength = m_ServerListPlainLength;
mem_copy(aData, VERSIONSRV_DDNETLIST, sizeof(VERSIONSRV_DDNETLIST));
mem_copy(aData + sizeof(VERSIONSRV_DDNETLIST), Token, 4); // send back token
mem_copy(aData + sizeof(VERSIONSRV_DDNETLIST)+4, &WordCompLength, 2); // compressed length
mem_copy(aData + sizeof(VERSIONSRV_DDNETLIST)+6, &WordPlainLength, 2); // plain length
mem_copy(aData + sizeof(VERSIONSRV_DDNETLIST)+8, m_aServerList, m_ServerListCompLength);
p.m_ClientID = -1;
p.m_Address = *pAddr;
p.m_Flags = NETSENDFLAG_CONNLESS;
p.m_pData = aData;
p.m_DataSize = sizeof(VERSIONSRV_DDNETLIST) + 4 + 2 + 2 + m_ServerListCompLength;
g_NetOp.Send(&p);
}
int main(int argc, char **argv) // ignore_convention
{
NETADDR BindAddr;
dbg_logger_stdout();
net_init();
mem_zero(&BindAddr, sizeof(BindAddr));
BindAddr.type = NETTYPE_ALL;
BindAddr.port = VERSIONSRV_PORT;
if(!g_NetOp.Open(BindAddr, 0))
{
dbg_msg("mastersrv", "couldn't start network");
return -1;
}
BuildPackets();
ReadNews();
ReadServerList();
dbg_msg("versionsrv", "started");
while(1)
{
g_NetOp.Update();
// process packets
CNetChunk Packet;
while(g_NetOp.Recv(&Packet))
{
if(Packet.m_DataSize == sizeof(VERSIONSRV_GETVERSION) &&
mem_comp(Packet.m_pData, VERSIONSRV_GETVERSION, sizeof(VERSIONSRV_GETVERSION)) == 0)
{
SendVer(&Packet.m_Address);
char aAddrStr[NETADDR_MAXSTRSIZE];
net_addr_str(&Packet.m_Address, aAddrStr, sizeof(aAddrStr), false);
dbg_msg("versionsrv", "version request by %s", aAddrStr);
}
if(Packet.m_DataSize == sizeof(VERSIONSRV_GETNEWS) &&
mem_comp(Packet.m_pData, VERSIONSRV_GETNEWS, sizeof(VERSIONSRV_GETNEWS)) == 0)
{
SendNews(&Packet.m_Address);
}
if(Packet.m_DataSize == sizeof(VERSIONSRV_GETMAPLIST) &&
mem_comp(Packet.m_pData, VERSIONSRV_GETMAPLIST, sizeof(VERSIONSRV_GETMAPLIST)) == 0)
{
CNetChunk p;
p.m_ClientID = -1;
p.m_Address = Packet.m_Address;
p.m_Flags = NETSENDFLAG_CONNLESS;
for(int i = 0; i < m_NumPackets; i++)
{
p.m_DataSize = m_aPackets[i].m_Size;
p.m_pData = &m_aPackets[i].m_Data;
g_NetOp.Send(&p);
}
}
if(m_ServerListLoaded &&
Packet.m_DataSize == sizeof(VERSIONSRV_GETDDNETLIST) + 4 &&
mem_comp(Packet.m_pData, VERSIONSRV_GETDDNETLIST, sizeof(VERSIONSRV_GETDDNETLIST)) == 0)
{
char aToken[4];
mem_copy(aToken, (char*)Packet.m_pData+sizeof(VERSIONSRV_GETDDNETLIST), 4);
SendServerList(&Packet.m_Address, aToken);
}
}
// wait for input
net_socket_read_wait(g_NetOp.m_Socket, 1000000);
}
return 0;
}

View file

@ -1,27 +0,0 @@
/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */
/* If you are missing that file, acquire a complete release at teeworlds.com. */
#ifndef VERSIONSRV_VERSIONSRV_H
#define VERSIONSRV_VERSIONSRV_H
static const int VERSIONSRV_PORT = 8302;
static const int NEWS_SIZE = 1380;
static const int DDNETLIST_SIZE = 1380;
struct CMapVersion
{
char m_aName[8];
unsigned char m_aCrc[4];
unsigned char m_aSize[4];
};
static const unsigned char VERSIONSRV_GETVERSION[] = {255, 255, 255, 255, 'v', 'e', 'r', 'g'};
static const unsigned char VERSIONSRV_VERSION[] = {255, 255, 255, 255, 'v', 'e', 'r', 's'};
static const unsigned char VERSIONSRV_GETMAPLIST[] = {255, 255, 255, 255, 'v', 'm', 'l', 'g'};
static const unsigned char VERSIONSRV_MAPLIST[] = {255, 255, 255, 255, 'v', 'm', 'l', 's'};
static const unsigned char VERSIONSRV_GETNEWS[] = {255, 255, 255, 255, 'n', 'e', 'w', 'g'};
static const unsigned char VERSIONSRV_NEWS[] = {255, 255, 255, 255, 'n', 'e', 'w', 's'};
static const unsigned char VERSIONSRV_GETDDNETLIST[] = {255, 255, 255, 255, 'e', 'a', 's', 't'};
static const unsigned char VERSIONSRV_DDNETLIST[] = {255, 255, 255, 255, 't', 's', 'a', 'e'};
#endif