From a583633cde8f6d257fff99221d4b063ae435379e Mon Sep 17 00:00:00 2001 From: oy Date: Sun, 27 Mar 2011 18:00:54 +0200 Subject: added renaming of srvbrowse so it matches with the interface filename by Choupom --- src/engine/client/client.cpp | 2 +- src/engine/client/serverbrowser.cpp | 734 ++++++++++++++++++++++++++++++++++++ src/engine/client/serverbrowser.h | 117 ++++++ src/engine/client/srvbrowse.cpp | 734 ------------------------------------ src/engine/client/srvbrowse.h | 117 ------ 5 files changed, 852 insertions(+), 852 deletions(-) create mode 100644 src/engine/client/serverbrowser.cpp create mode 100644 src/engine/client/serverbrowser.h delete mode 100644 src/engine/client/srvbrowse.cpp delete mode 100644 src/engine/client/srvbrowse.h (limited to 'src/engine') diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index 3131afc1..297828dc 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -37,7 +37,7 @@ #include #include "friends.h" -#include "srvbrowse.h" +#include "serverbrowser.h" #include "client.h" #if defined(CONF_FAMILY_WINDOWS) diff --git a/src/engine/client/serverbrowser.cpp b/src/engine/client/serverbrowser.cpp new file mode 100644 index 00000000..d4efe975 --- /dev/null +++ b/src/engine/client/serverbrowser.cpp @@ -0,0 +1,734 @@ +/* (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 // sort + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "serverbrowser.h" + +class SortWrap +{ + typedef bool (CServerBrowser::*SortFunc)(int, int) const; + SortFunc m_pfnSort; + CServerBrowser *m_pThis; +public: + SortWrap(CServerBrowser *t, SortFunc f) : m_pfnSort(f), m_pThis(t) {} + bool operator()(int a, int b) { return (m_pThis->*m_pfnSort)(a, b); } +}; + +CServerBrowser::CServerBrowser() +{ + m_pMasterServer = 0; + m_ppServerlist = 0; + m_pSortedServerlist = 0; + + m_NumFavoriteServers = 0; + + mem_zero(m_aServerlistIp, sizeof(m_aServerlistIp)); + + m_pFirstReqServer = 0; // request list + m_pLastReqServer = 0; + m_NumRequests = 0; + + m_NeedRefresh = 0; + + m_NumSortedServers = 0; + m_NumSortedServersCapacity = 0; + m_NumServers = 0; + m_NumServerCapacity = 0; + + m_Sorthash = 0; + m_aFilterString[0] = 0; + m_aFilterGametypeString[0] = 0; + + // the token is to keep server refresh separated from each other + m_CurrentToken = 1; + + m_ServerlistType = 0; + m_BroadcastTime = 0; +} + +void CServerBrowser::SetBaseInfo(class CNetClient *pClient, const char *pNetVersion) +{ + m_pNetClient = pClient; + str_copy(m_aNetVersion, pNetVersion, sizeof(m_aNetVersion)); + m_pMasterServer = Kernel()->RequestInterface(); + m_pConsole = Kernel()->RequestInterface(); + m_pFriends = Kernel()->RequestInterface(); + IConfig *pConfig = Kernel()->RequestInterface(); + if(pConfig) + pConfig->RegisterCallback(ConfigSaveCallback, this); +} + +const CServerInfo *CServerBrowser::SortedGet(int Index) const +{ + if(Index < 0 || Index >= m_NumSortedServers) + return 0; + return &m_ppServerlist[m_pSortedServerlist[Index]]->m_Info; +} + + +bool CServerBrowser::SortCompareName(int Index1, int Index2) const +{ + CServerEntry *a = m_ppServerlist[Index1]; + CServerEntry *b = m_ppServerlist[Index2]; + // make sure empty entries are listed last + return (a->m_GotInfo && b->m_GotInfo) || (!a->m_GotInfo && !b->m_GotInfo) ? str_comp(a->m_Info.m_aName, b->m_Info.m_aName) < 0 : + a->m_GotInfo ? true : false; +} + +bool CServerBrowser::SortCompareMap(int Index1, int Index2) const +{ + CServerEntry *a = m_ppServerlist[Index1]; + CServerEntry *b = m_ppServerlist[Index2]; + return str_comp(a->m_Info.m_aMap, b->m_Info.m_aMap) < 0; +} + +bool CServerBrowser::SortComparePing(int Index1, int Index2) const +{ + CServerEntry *a = m_ppServerlist[Index1]; + CServerEntry *b = m_ppServerlist[Index2]; + return a->m_Info.m_Latency < b->m_Info.m_Latency; +} + +bool CServerBrowser::SortCompareGametype(int Index1, int Index2) const +{ + CServerEntry *a = m_ppServerlist[Index1]; + CServerEntry *b = m_ppServerlist[Index2]; + return str_comp(a->m_Info.m_aGameType, b->m_Info.m_aGameType) < 0; +} + +bool CServerBrowser::SortCompareNumPlayers(int Index1, int Index2) const +{ + CServerEntry *a = m_ppServerlist[Index1]; + CServerEntry *b = m_ppServerlist[Index2]; + return a->m_Info.m_NumPlayers < b->m_Info.m_NumPlayers; +} + +bool CServerBrowser::SortCompareNumClients(int Index1, int Index2) const +{ + CServerEntry *a = m_ppServerlist[Index1]; + CServerEntry *b = m_ppServerlist[Index2]; + return a->m_Info.m_NumClients < b->m_Info.m_NumClients; +} + +void CServerBrowser::Filter() +{ + int i = 0, p = 0; + m_NumSortedServers = 0; + + // allocate the sorted list + if(m_NumSortedServersCapacity < m_NumServers) + { + if(m_pSortedServerlist) + mem_free(m_pSortedServerlist); + m_NumSortedServersCapacity = m_NumServers; + m_pSortedServerlist = (int *)mem_alloc(m_NumSortedServersCapacity*sizeof(int), 1); + } + + // filter the servers + for(i = 0; i < m_NumServers; i++) + { + int Filtered = 0; + bool FoundFriend = false; + + if(g_Config.m_BrFilterFriends) + { + for(p = 0; p < m_ppServerlist[i]->m_Info.m_NumClients; p++) + { + if(m_pFriends->IsFriend(m_ppServerlist[i]->m_Info.m_aClients[p].m_aName, m_ppServerlist[i]->m_Info.m_aClients[p].m_aClan)) + { + FoundFriend = true; + break; + } + } + } + + if(!FoundFriend) + { + if(g_Config.m_BrFilterEmpty && ((g_Config.m_BrFilterSpectators && m_ppServerlist[i]->m_Info.m_NumPlayers == 0) || m_ppServerlist[i]->m_Info.m_NumClients == 0)) + Filtered = 1; + else if(g_Config.m_BrFilterFull && ((g_Config.m_BrFilterSpectators && m_ppServerlist[i]->m_Info.m_NumPlayers == m_ppServerlist[i]->m_Info.m_MaxPlayers) || + m_ppServerlist[i]->m_Info.m_NumClients == m_ppServerlist[i]->m_Info.m_MaxClients)) + Filtered = 1; + else if(g_Config.m_BrFilterPw && m_ppServerlist[i]->m_Info.m_Flags&SERVER_FLAG_PASSWORD) + Filtered = 1; + else if(g_Config.m_BrFilterPure && + (str_comp(m_ppServerlist[i]->m_Info.m_aGameType, "DM") != 0 && + str_comp(m_ppServerlist[i]->m_Info.m_aGameType, "TDM") != 0 && + str_comp(m_ppServerlist[i]->m_Info.m_aGameType, "CTF") != 0)) + { + Filtered = 1; + } + else if(g_Config.m_BrFilterPureMap && + !(str_comp(m_ppServerlist[i]->m_Info.m_aMap, "dm1") == 0 || + str_comp(m_ppServerlist[i]->m_Info.m_aMap, "dm2") == 0 || + str_comp(m_ppServerlist[i]->m_Info.m_aMap, "dm6") == 0 || + str_comp(m_ppServerlist[i]->m_Info.m_aMap, "dm7") == 0 || + str_comp(m_ppServerlist[i]->m_Info.m_aMap, "dm8") == 0 || + str_comp(m_ppServerlist[i]->m_Info.m_aMap, "dm9") == 0 || + str_comp(m_ppServerlist[i]->m_Info.m_aMap, "ctf1") == 0 || + str_comp(m_ppServerlist[i]->m_Info.m_aMap, "ctf2") == 0 || + str_comp(m_ppServerlist[i]->m_Info.m_aMap, "ctf3") == 0 || + str_comp(m_ppServerlist[i]->m_Info.m_aMap, "ctf4") == 0 || + str_comp(m_ppServerlist[i]->m_Info.m_aMap, "ctf5") == 0) + ) + { + Filtered = 1; + } + else if(g_Config.m_BrFilterPing < m_ppServerlist[i]->m_Info.m_Latency) + Filtered = 1; + else if(g_Config.m_BrFilterCompatversion && str_comp_num(m_ppServerlist[i]->m_Info.m_aVersion, m_aNetVersion, 3) != 0) + Filtered = 1; + else if(g_Config.m_BrFilterServerAddress[0] && !str_find_nocase(m_ppServerlist[i]->m_Info.m_aAddress, g_Config.m_BrFilterServerAddress)) + Filtered = 1; + else if(g_Config.m_BrFilterGametype[0] && !str_find_nocase(m_ppServerlist[i]->m_Info.m_aGameType, g_Config.m_BrFilterGametype)) + Filtered = 1; + else if(g_Config.m_BrFilterString[0] != 0) + { + int MatchFound = 0; + + m_ppServerlist[i]->m_Info.m_QuickSearchHit = 0; + + // match against server name + if(str_find_nocase(m_ppServerlist[i]->m_Info.m_aName, g_Config.m_BrFilterString)) + { + MatchFound = 1; + m_ppServerlist[i]->m_Info.m_QuickSearchHit |= IServerBrowser::QUICK_SERVERNAME; + } + + // match against players + for(p = 0; p < m_ppServerlist[i]->m_Info.m_NumClients; p++) + { + if(str_find_nocase(m_ppServerlist[i]->m_Info.m_aClients[p].m_aName, g_Config.m_BrFilterString) || + str_find_nocase(m_ppServerlist[i]->m_Info.m_aClients[p].m_aClan, g_Config.m_BrFilterString)) + { + MatchFound = 1; + m_ppServerlist[i]->m_Info.m_QuickSearchHit |= IServerBrowser::QUICK_PLAYER; + break; + } + } + + // match against map + if(str_find_nocase(m_ppServerlist[i]->m_Info.m_aMap, g_Config.m_BrFilterString)) + { + MatchFound = 1; + m_ppServerlist[i]->m_Info.m_QuickSearchHit |= IServerBrowser::QUICK_MAPNAME; + } + + if(!MatchFound) + Filtered = 1; + } + } + + if(Filtered == 0) + m_pSortedServerlist[m_NumSortedServers++] = i; + } +} + +int CServerBrowser::SortHash() const +{ + int i = g_Config.m_BrSort&0xf; + i |= g_Config.m_BrFilterEmpty<<4; + i |= g_Config.m_BrFilterFull<<5; + i |= g_Config.m_BrFilterSpectators<<6; + i |= g_Config.m_BrFilterFriends<<7; + i |= g_Config.m_BrFilterPw<<8; + i |= g_Config.m_BrSortOrder<<9; + i |= g_Config.m_BrFilterCompatversion<<10; + i |= g_Config.m_BrFilterPure<<11; + i |= g_Config.m_BrFilterPureMap<<12; + i |= g_Config.m_BrFilterPing<<18; + return i; +} + +void CServerBrowser::Sort() +{ + int i; + + // create filtered list + Filter(); + + // sort + if(g_Config.m_BrSort == IServerBrowser::SORT_NAME) + std::sort(m_pSortedServerlist, m_pSortedServerlist+m_NumSortedServers, SortWrap(this, &CServerBrowser::SortCompareName)); + else if(g_Config.m_BrSort == IServerBrowser::SORT_PING) + std::sort(m_pSortedServerlist, m_pSortedServerlist+m_NumSortedServers, SortWrap(this, &CServerBrowser::SortComparePing)); + else if(g_Config.m_BrSort == IServerBrowser::SORT_MAP) + std::sort(m_pSortedServerlist, m_pSortedServerlist+m_NumSortedServers, SortWrap(this, &CServerBrowser::SortCompareMap)); + else if(g_Config.m_BrSort == IServerBrowser::SORT_NUMPLAYERS) + std::sort(m_pSortedServerlist, m_pSortedServerlist+m_NumSortedServers, SortWrap(this, + g_Config.m_BrFilterSpectators ? &CServerBrowser::SortCompareNumPlayers : &CServerBrowser::SortCompareNumClients)); + else if(g_Config.m_BrSort == IServerBrowser::SORT_GAMETYPE) + std::sort(m_pSortedServerlist, m_pSortedServerlist+m_NumSortedServers, SortWrap(this, &CServerBrowser::SortCompareGametype)); + + // invert the list if requested + if(g_Config.m_BrSortOrder) + { + for(i = 0; i < m_NumSortedServers/2; i++) + { + int Temp = m_pSortedServerlist[i]; + m_pSortedServerlist[i] = m_pSortedServerlist[m_NumSortedServers-i-1]; + m_pSortedServerlist[m_NumSortedServers-i-1] = Temp; + } + } + + // set indexes + for(i = 0; i < m_NumSortedServers; i++) + m_ppServerlist[m_pSortedServerlist[i]]->m_Info.m_SortedIndex = i; + + str_copy(m_aFilterGametypeString, g_Config.m_BrFilterGametype, sizeof(m_aFilterGametypeString)); + str_copy(m_aFilterString, g_Config.m_BrFilterString, sizeof(m_aFilterString)); + m_Sorthash = SortHash(); +} + +void CServerBrowser::RemoveRequest(CServerEntry *pEntry) +{ + if(pEntry->m_pPrevReq || pEntry->m_pNextReq || m_pFirstReqServer == pEntry) + { + if(pEntry->m_pPrevReq) + pEntry->m_pPrevReq->m_pNextReq = pEntry->m_pNextReq; + else + m_pFirstReqServer = pEntry->m_pNextReq; + + if(pEntry->m_pNextReq) + pEntry->m_pNextReq->m_pPrevReq = pEntry->m_pPrevReq; + else + m_pLastReqServer = pEntry->m_pPrevReq; + + pEntry->m_pPrevReq = 0; + pEntry->m_pNextReq = 0; + m_NumRequests--; + } +} + +CServerBrowser::CServerEntry *CServerBrowser::Find(const NETADDR &Addr) +{ + CServerEntry *pEntry = m_aServerlistIp[Addr.ip[0]]; + + for(; pEntry; pEntry = pEntry->m_pNextIp) + { + if(net_addr_comp(&pEntry->m_Addr, &Addr) == 0) + return pEntry; + } + return (CServerEntry*)0; +} + +void CServerBrowser::QueueRequest(CServerEntry *pEntry) +{ + // add it to the list of servers that we should request info from + pEntry->m_pPrevReq = m_pLastReqServer; + if(m_pLastReqServer) + m_pLastReqServer->m_pNextReq = pEntry; + else + m_pFirstReqServer = pEntry; + m_pLastReqServer = pEntry; + + m_NumRequests++; +} + +void CServerBrowser::SetInfo(CServerEntry *pEntry, const CServerInfo &Info) +{ + int Fav = pEntry->m_Info.m_Favorite; + pEntry->m_Info = Info; + pEntry->m_Info.m_Favorite = Fav; + pEntry->m_Info.m_NetAddr = pEntry->m_Addr; + + // all these are just for nice compability + if(pEntry->m_Info.m_aGameType[0] == '0' && pEntry->m_Info.m_aGameType[1] == 0) + str_copy(pEntry->m_Info.m_aGameType, "DM", sizeof(pEntry->m_Info.m_aGameType)); + else if(pEntry->m_Info.m_aGameType[0] == '1' && pEntry->m_Info.m_aGameType[1] == 0) + str_copy(pEntry->m_Info.m_aGameType, "TDM", sizeof(pEntry->m_Info.m_aGameType)); + else if(pEntry->m_Info.m_aGameType[0] == '2' && pEntry->m_Info.m_aGameType[1] == 0) + str_copy(pEntry->m_Info.m_aGameType, "CTF", sizeof(pEntry->m_Info.m_aGameType)); + + /*if(!request) + { + pEntry->m_Info.latency = (time_get()-pEntry->request_time)*1000/time_freq(); + RemoveRequest(pEntry); + }*/ + + pEntry->m_GotInfo = 1; + Sort(); +} + +CServerBrowser::CServerEntry *CServerBrowser::Add(const NETADDR &Addr) +{ + int Hash = Addr.ip[0]; + CServerEntry *pEntry = 0; + int i; + + // create new pEntry + pEntry = (CServerEntry *)m_ServerlistHeap.Allocate(sizeof(CServerEntry)); + mem_zero(pEntry, sizeof(CServerEntry)); + + // set the info + pEntry->m_Addr = Addr; + pEntry->m_Info.m_NetAddr = Addr; + + pEntry->m_Info.m_Latency = 999; + str_format(pEntry->m_Info.m_aAddress, sizeof(pEntry->m_Info.m_aAddress), "%d.%d.%d.%d:%d", + Addr.ip[0], Addr.ip[1], Addr.ip[2], + Addr.ip[3], Addr.port); + str_format(pEntry->m_Info.m_aName, sizeof(pEntry->m_Info.m_aName), "%d.%d.%d.%d:%d", + Addr.ip[0], Addr.ip[1], Addr.ip[2], + Addr.ip[3], Addr.port); + + /*if(serverlist_type == IServerBrowser::TYPE_LAN) + pEntry->m_Info.latency = (time_get()-broadcast_time)*1000/time_freq();*/ + + // check if it's a favorite + for(i = 0; i < m_NumFavoriteServers; i++) + { + if(net_addr_comp(&Addr, &m_aFavoriteServers[i]) == 0) + pEntry->m_Info.m_Favorite = 1; + } + + // add to the hash list + pEntry->m_pNextIp = m_aServerlistIp[Hash]; + m_aServerlistIp[Hash] = pEntry; + + if(m_NumServers == m_NumServerCapacity) + { + CServerEntry **ppNewlist; + m_NumServerCapacity += 100; + ppNewlist = (CServerEntry **)mem_alloc(m_NumServerCapacity*sizeof(CServerEntry*), 1); + mem_copy(ppNewlist, m_ppServerlist, m_NumServers*sizeof(CServerEntry*)); + mem_free(m_ppServerlist); + m_ppServerlist = ppNewlist; + } + + // add to list + m_ppServerlist[m_NumServers] = pEntry; + pEntry->m_Info.m_ServerIndex = m_NumServers; + m_NumServers++; + + return pEntry; +} + +void CServerBrowser::Set(const NETADDR &Addr, int Type, int Token, const CServerInfo *pInfo) +{ + CServerEntry *pEntry = 0; + if(Type == IServerBrowser::SET_MASTER_ADD) + { + if(m_ServerlistType != IServerBrowser::TYPE_INTERNET) + return; + + if(!Find(Addr)) + { + pEntry = Add(Addr); + QueueRequest(pEntry); + } + } + else if(Type == IServerBrowser::SET_FAV_ADD) + { + if(m_ServerlistType != IServerBrowser::TYPE_FAVORITES) + return; + + if(!Find(Addr)) + { + pEntry = Add(Addr); + QueueRequest(pEntry); + } + } + else if(Type == IServerBrowser::SET_TOKEN) + { + if(Token != m_CurrentToken) + return; + + pEntry = Find(Addr); + if(!pEntry) + pEntry = Add(Addr); + if(pEntry) + { + SetInfo(pEntry, *pInfo); + if(m_ServerlistType == IServerBrowser::TYPE_LAN) + pEntry->m_Info.m_Latency = min(static_cast((time_get()-m_BroadcastTime)*1000/time_freq()), 999); + else + pEntry->m_Info.m_Latency = min(static_cast((time_get()-pEntry->m_RequestTime)*1000/time_freq()), 999); + RemoveRequest(pEntry); + } + } + + Sort(); +} + +void CServerBrowser::Refresh(int Type) +{ + // clear out everything + m_ServerlistHeap.Reset(); + m_NumServers = 0; + m_NumSortedServers = 0; + mem_zero(m_aServerlistIp, sizeof(m_aServerlistIp)); + m_pFirstReqServer = 0; + m_pLastReqServer = 0; + m_NumRequests = 0; + + // next token + m_CurrentToken = (m_CurrentToken+1)&0xff; + + // + m_ServerlistType = Type; + + if(Type == IServerBrowser::TYPE_LAN) + { + unsigned char Buffer[sizeof(SERVERBROWSE_GETINFO)+1]; + CNetChunk Packet; + int i; + + mem_copy(Buffer, SERVERBROWSE_GETINFO, sizeof(SERVERBROWSE_GETINFO)); + Buffer[sizeof(SERVERBROWSE_GETINFO)] = m_CurrentToken; + + Packet.m_ClientID = -1; + mem_zero(&Packet, sizeof(Packet)); + Packet.m_Address.ip[0] = 255; + Packet.m_Address.ip[1] = 255; + Packet.m_Address.ip[2] = 255; + Packet.m_Address.ip[3] = 255; + Packet.m_Flags = NETSENDFLAG_CONNLESS; + Packet.m_DataSize = sizeof(Buffer); + Packet.m_pData = Buffer; + m_BroadcastTime = time_get(); + + for(i = 8303; i <= 8310; i++) + { + Packet.m_Address.port = i; + m_pNetClient->Send(&Packet); + } + + if(g_Config.m_Debug) + m_pConsole->Print(IConsole::OUTPUT_LEVEL_DEBUG, "client_srvbrowse", "broadcasting for servers"); + } + else if(Type == IServerBrowser::TYPE_INTERNET) + m_NeedRefresh = 1; + else if(Type == IServerBrowser::TYPE_FAVORITES) + { + for(int i = 0; i < m_NumFavoriteServers; i++) + Set(m_aFavoriteServers[i], IServerBrowser::SET_FAV_ADD, -1, 0); + } +} + +void CServerBrowser::RequestImpl(const NETADDR &Addr, CServerEntry *pEntry) const +{ + unsigned char Buffer[sizeof(SERVERBROWSE_GETINFO)+1]; + CNetChunk Packet; + + if(g_Config.m_Debug) + { + char aBuf[256]; + str_format(aBuf, sizeof(aBuf),"requesting server info from %d.%d.%d.%d:%d", + Addr.ip[0], Addr.ip[1], Addr.ip[2], + Addr.ip[3], Addr.port); + m_pConsole->Print(IConsole::OUTPUT_LEVEL_DEBUG, "client_srvbrowse", aBuf); + } + + mem_copy(Buffer, SERVERBROWSE_GETINFO, sizeof(SERVERBROWSE_GETINFO)); + Buffer[sizeof(SERVERBROWSE_GETINFO)] = m_CurrentToken; + + Packet.m_ClientID = -1; + Packet.m_Address = Addr; + Packet.m_Flags = NETSENDFLAG_CONNLESS; + Packet.m_DataSize = sizeof(Buffer); + Packet.m_pData = Buffer; + + m_pNetClient->Send(&Packet); + + if(pEntry) + pEntry->m_RequestTime = time_get(); +} + +void CServerBrowser::Request(const NETADDR &Addr) const +{ + RequestImpl(Addr, 0); +} + + +void CServerBrowser::Update(bool ForceResort) +{ + int64 Timeout = time_freq()/2; // TODO 0.6: increase this again + int64 Now = time_get(); + int Count; + CServerEntry *pEntry, *pNext; + + // do server list requests + if(m_NeedRefresh && !m_pMasterServer->IsRefreshing()) + { + NETADDR Addr; + CNetChunk Packet; + int i; + + m_NeedRefresh = 0; + + mem_zero(&Packet, sizeof(Packet)); + Packet.m_ClientID = -1; + Packet.m_Flags = NETSENDFLAG_CONNLESS; + Packet.m_DataSize = sizeof(SERVERBROWSE_GETLIST); + Packet.m_pData = SERVERBROWSE_GETLIST; + + for(i = 0; i < IMasterServer::MAX_MASTERSERVERS; i++) + { + Addr = m_pMasterServer->GetAddr(i); + if(!Addr.ip[0] && !Addr.ip[1] && !Addr.ip[2] && !Addr.ip[3]) + continue; + + Packet.m_Address = Addr; + m_pNetClient->Send(&Packet); + } + + if(g_Config.m_Debug) + m_pConsole->Print(IConsole::OUTPUT_LEVEL_DEBUG, "client_srvbrowse", "requesting server list"); + } + + // do timeouts + pEntry = m_pFirstReqServer; + while(1) + { + if(!pEntry) // no more entries + break; + + pNext = pEntry->m_pNextReq; + + if(pEntry->m_RequestTime && pEntry->m_RequestTime+Timeout < Now) + { + // timeout + RemoveRequest(pEntry); + } + + pEntry = pNext; + } + + // do timeouts + pEntry = m_pFirstReqServer; + Count = 0; + while(1) + { + if(!pEntry) // no more entries + break; + + // no more then 10 concurrent requests + if(Count == g_Config.m_BrMaxRequests) + break; + + if(pEntry->m_RequestTime == 0) + RequestImpl(pEntry->m_Addr, pEntry); + + Count++; + pEntry = pEntry->m_pNextReq; + } + + // check if we need to resort + if(m_Sorthash != SortHash() || ForceResort) + Sort(); +} + + +bool CServerBrowser::IsFavorite(const NETADDR &Addr) const +{ + // search for the address + int i; + for(i = 0; i < m_NumFavoriteServers; i++) + { + if(net_addr_comp(&Addr, &m_aFavoriteServers[i]) == 0) + return true; + } + return false; +} + +void CServerBrowser::AddFavorite(const NETADDR &Addr) +{ + CServerEntry *pEntry; + + if(m_NumFavoriteServers == MAX_FAVORITES) + return; + + // make sure that we don't already have the server in our list + for(int i = 0; i < m_NumFavoriteServers; i++) + { + if(net_addr_comp(&Addr, &m_aFavoriteServers[i]) == 0) + return; + } + + // add the server to the list + m_aFavoriteServers[m_NumFavoriteServers++] = Addr; + pEntry = Find(Addr); + if(pEntry) + pEntry->m_Info.m_Favorite = 1; + + if(g_Config.m_Debug) + { + char aBuf[256]; + str_format(aBuf, sizeof(aBuf), "added fav, %d.%d.%d.%d:%d", Addr.ip[0], Addr.ip[1], Addr.ip[2], Addr.ip[3], Addr.port); + m_pConsole->Print(IConsole::OUTPUT_LEVEL_DEBUG, "client_srvbrowse", aBuf); + } +} + +void CServerBrowser::RemoveFavorite(const NETADDR &Addr) +{ + int i; + CServerEntry *pEntry; + + for(i = 0; i < m_NumFavoriteServers; i++) + { + if(net_addr_comp(&Addr, &m_aFavoriteServers[i]) == 0) + { + mem_move(&m_aFavoriteServers[i], &m_aFavoriteServers[i+1], sizeof(NETADDR)*(m_NumFavoriteServers-(i+1))); + m_NumFavoriteServers--; + + pEntry = Find(Addr); + if(pEntry) + pEntry->m_Info.m_Favorite = 0; + + return; + } + } +} + +bool CServerBrowser::IsRefreshing() const +{ + return m_pFirstReqServer != 0; +} + +bool CServerBrowser::IsRefreshingMasters() const +{ + return m_pMasterServer->IsRefreshing(); +} + + +int CServerBrowser::LoadingProgression() const +{ + if(m_NumServers == 0) + return 0; + + int Servers = m_NumServers; + int Loaded = m_NumServers-m_NumRequests; + return 100.0f * Loaded/Servers; +} + + +void CServerBrowser::ConfigSaveCallback(IConfig *pConfig, void *pUserData) +{ + CServerBrowser *pSelf = (CServerBrowser *)pUserData; + + int i; + char aAddrStr[128]; + char aBuffer[256]; + for(i = 0; i < pSelf->m_NumFavoriteServers; i++) + { + net_addr_str(&pSelf->m_aFavoriteServers[i], aAddrStr, sizeof(aAddrStr)); + str_format(aBuffer, sizeof(aBuffer), "add_favorite %s", aAddrStr); + pConfig->WriteLine(aBuffer); + } +} diff --git a/src/engine/client/serverbrowser.h b/src/engine/client/serverbrowser.h new file mode 100644 index 00000000..e0d39aad --- /dev/null +++ b/src/engine/client/serverbrowser.h @@ -0,0 +1,117 @@ +/* (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_CLIENT_SERVERBROWSER_H +#define ENGINE_CLIENT_SERVERBROWSER_H + +#include + +class CServerBrowser : public IServerBrowser +{ +public: + class CServerEntry + { + public: + NETADDR m_Addr; + int64 m_RequestTime; + int m_GotInfo; + CServerInfo m_Info; + + CServerEntry *m_pNextIp; // ip hashed list + + CServerEntry *m_pPrevReq; // request list + CServerEntry *m_pNextReq; + }; + + enum + { + MAX_FAVORITES=256 + }; + + CServerBrowser(); + + // interface functions + void Refresh(int Type); + bool IsRefreshing() const; + bool IsRefreshingMasters() const; + int LoadingProgression() const; + + int NumServers() const { return m_NumServers; } + + int NumSortedServers() const { return m_NumSortedServers; } + const CServerInfo *SortedGet(int Index) const; + + bool IsFavorite(const NETADDR &Addr) const; + void AddFavorite(const NETADDR &Addr); + void RemoveFavorite(const NETADDR &Addr); + + // + void Update(bool ForceResort); + void Set(const NETADDR &Addr, int Type, int Token, const CServerInfo *pInfo); + void Request(const NETADDR &Addr) const; + + void SetBaseInfo(class CNetClient *pClient, const char *pNetVersion); + +private: + CNetClient *m_pNetClient; + IMasterServer *m_pMasterServer; + class IConsole *m_pConsole; + class IFriends *m_pFriends; + char m_aNetVersion[128]; + + CHeap m_ServerlistHeap; + CServerEntry **m_ppServerlist; + int *m_pSortedServerlist; + + NETADDR m_aFavoriteServers[MAX_FAVORITES]; + int m_NumFavoriteServers; + + CServerEntry *m_aServerlistIp[256]; // ip hash list + + CServerEntry *m_pFirstReqServer; // request list + CServerEntry *m_pLastReqServer; + int m_NumRequests; + + int m_NeedRefresh; + + int m_NumSortedServers; + int m_NumSortedServersCapacity; + int m_NumServers; + int m_NumServerCapacity; + + int m_Sorthash; + char m_aFilterString[64]; + char m_aFilterGametypeString[128]; + + // the token is to keep server refresh separated from each other + int m_CurrentToken; + + int m_ServerlistType; + int64 m_BroadcastTime; + + // sorting criterions + bool SortCompareName(int Index1, int Index2) const; + bool SortCompareMap(int Index1, int Index2) const; + bool SortComparePing(int Index1, int Index2) const; + bool SortCompareGametype(int Index1, int Index2) const; + bool SortCompareNumPlayers(int Index1, int Index2) const; + bool SortCompareNumClients(int Index1, int Index2) const; + + // + void Filter(); + void Sort(); + int SortHash() const; + + CServerEntry *Find(const NETADDR &Addr); + CServerEntry *Add(const NETADDR &Addr); + + void RemoveRequest(CServerEntry *pEntry); + void QueueRequest(CServerEntry *pEntry); + + void RequestImpl(const NETADDR &Addr, CServerEntry *pEntry) const; + + void SetInfo(CServerEntry *pEntry, const CServerInfo &Info); + + static void ConfigSaveCallback(IConfig *pConfig, void *pUserData); +}; + +#endif diff --git a/src/engine/client/srvbrowse.cpp b/src/engine/client/srvbrowse.cpp deleted file mode 100644 index be14eaa2..00000000 --- a/src/engine/client/srvbrowse.cpp +++ /dev/null @@ -1,734 +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 // sort - -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include "srvbrowse.h" - -class SortWrap -{ - typedef bool (CServerBrowser::*SortFunc)(int, int) const; - SortFunc m_pfnSort; - CServerBrowser *m_pThis; -public: - SortWrap(CServerBrowser *t, SortFunc f) : m_pfnSort(f), m_pThis(t) {} - bool operator()(int a, int b) { return (m_pThis->*m_pfnSort)(a, b); } -}; - -CServerBrowser::CServerBrowser() -{ - m_pMasterServer = 0; - m_ppServerlist = 0; - m_pSortedServerlist = 0; - - m_NumFavoriteServers = 0; - - mem_zero(m_aServerlistIp, sizeof(m_aServerlistIp)); - - m_pFirstReqServer = 0; // request list - m_pLastReqServer = 0; - m_NumRequests = 0; - - m_NeedRefresh = 0; - - m_NumSortedServers = 0; - m_NumSortedServersCapacity = 0; - m_NumServers = 0; - m_NumServerCapacity = 0; - - m_Sorthash = 0; - m_aFilterString[0] = 0; - m_aFilterGametypeString[0] = 0; - - // the token is to keep server refresh separated from each other - m_CurrentToken = 1; - - m_ServerlistType = 0; - m_BroadcastTime = 0; -} - -void CServerBrowser::SetBaseInfo(class CNetClient *pClient, const char *pNetVersion) -{ - m_pNetClient = pClient; - str_copy(m_aNetVersion, pNetVersion, sizeof(m_aNetVersion)); - m_pMasterServer = Kernel()->RequestInterface(); - m_pConsole = Kernel()->RequestInterface(); - m_pFriends = Kernel()->RequestInterface(); - IConfig *pConfig = Kernel()->RequestInterface(); - if(pConfig) - pConfig->RegisterCallback(ConfigSaveCallback, this); -} - -const CServerInfo *CServerBrowser::SortedGet(int Index) const -{ - if(Index < 0 || Index >= m_NumSortedServers) - return 0; - return &m_ppServerlist[m_pSortedServerlist[Index]]->m_Info; -} - - -bool CServerBrowser::SortCompareName(int Index1, int Index2) const -{ - CServerEntry *a = m_ppServerlist[Index1]; - CServerEntry *b = m_ppServerlist[Index2]; - // make sure empty entries are listed last - return (a->m_GotInfo && b->m_GotInfo) || (!a->m_GotInfo && !b->m_GotInfo) ? str_comp(a->m_Info.m_aName, b->m_Info.m_aName) < 0 : - a->m_GotInfo ? true : false; -} - -bool CServerBrowser::SortCompareMap(int Index1, int Index2) const -{ - CServerEntry *a = m_ppServerlist[Index1]; - CServerEntry *b = m_ppServerlist[Index2]; - return str_comp(a->m_Info.m_aMap, b->m_Info.m_aMap) < 0; -} - -bool CServerBrowser::SortComparePing(int Index1, int Index2) const -{ - CServerEntry *a = m_ppServerlist[Index1]; - CServerEntry *b = m_ppServerlist[Index2]; - return a->m_Info.m_Latency < b->m_Info.m_Latency; -} - -bool CServerBrowser::SortCompareGametype(int Index1, int Index2) const -{ - CServerEntry *a = m_ppServerlist[Index1]; - CServerEntry *b = m_ppServerlist[Index2]; - return str_comp(a->m_Info.m_aGameType, b->m_Info.m_aGameType) < 0; -} - -bool CServerBrowser::SortCompareNumPlayers(int Index1, int Index2) const -{ - CServerEntry *a = m_ppServerlist[Index1]; - CServerEntry *b = m_ppServerlist[Index2]; - return a->m_Info.m_NumPlayers < b->m_Info.m_NumPlayers; -} - -bool CServerBrowser::SortCompareNumClients(int Index1, int Index2) const -{ - CServerEntry *a = m_ppServerlist[Index1]; - CServerEntry *b = m_ppServerlist[Index2]; - return a->m_Info.m_NumClients < b->m_Info.m_NumClients; -} - -void CServerBrowser::Filter() -{ - int i = 0, p = 0; - m_NumSortedServers = 0; - - // allocate the sorted list - if(m_NumSortedServersCapacity < m_NumServers) - { - if(m_pSortedServerlist) - mem_free(m_pSortedServerlist); - m_NumSortedServersCapacity = m_NumServers; - m_pSortedServerlist = (int *)mem_alloc(m_NumSortedServersCapacity*sizeof(int), 1); - } - - // filter the servers - for(i = 0; i < m_NumServers; i++) - { - int Filtered = 0; - bool FoundFriend = false; - - if(g_Config.m_BrFilterFriends) - { - for(p = 0; p < m_ppServerlist[i]->m_Info.m_NumClients; p++) - { - if(m_pFriends->IsFriend(m_ppServerlist[i]->m_Info.m_aClients[p].m_aName, m_ppServerlist[i]->m_Info.m_aClients[p].m_aClan)) - { - FoundFriend = true; - break; - } - } - } - - if(!FoundFriend) - { - if(g_Config.m_BrFilterEmpty && ((g_Config.m_BrFilterSpectators && m_ppServerlist[i]->m_Info.m_NumPlayers == 0) || m_ppServerlist[i]->m_Info.m_NumClients == 0)) - Filtered = 1; - else if(g_Config.m_BrFilterFull && ((g_Config.m_BrFilterSpectators && m_ppServerlist[i]->m_Info.m_NumPlayers == m_ppServerlist[i]->m_Info.m_MaxPlayers) || - m_ppServerlist[i]->m_Info.m_NumClients == m_ppServerlist[i]->m_Info.m_MaxClients)) - Filtered = 1; - else if(g_Config.m_BrFilterPw && m_ppServerlist[i]->m_Info.m_Flags&SERVER_FLAG_PASSWORD) - Filtered = 1; - else if(g_Config.m_BrFilterPure && - (str_comp(m_ppServerlist[i]->m_Info.m_aGameType, "DM") != 0 && - str_comp(m_ppServerlist[i]->m_Info.m_aGameType, "TDM") != 0 && - str_comp(m_ppServerlist[i]->m_Info.m_aGameType, "CTF") != 0)) - { - Filtered = 1; - } - else if(g_Config.m_BrFilterPureMap && - !(str_comp(m_ppServerlist[i]->m_Info.m_aMap, "dm1") == 0 || - str_comp(m_ppServerlist[i]->m_Info.m_aMap, "dm2") == 0 || - str_comp(m_ppServerlist[i]->m_Info.m_aMap, "dm6") == 0 || - str_comp(m_ppServerlist[i]->m_Info.m_aMap, "dm7") == 0 || - str_comp(m_ppServerlist[i]->m_Info.m_aMap, "dm8") == 0 || - str_comp(m_ppServerlist[i]->m_Info.m_aMap, "dm9") == 0 || - str_comp(m_ppServerlist[i]->m_Info.m_aMap, "ctf1") == 0 || - str_comp(m_ppServerlist[i]->m_Info.m_aMap, "ctf2") == 0 || - str_comp(m_ppServerlist[i]->m_Info.m_aMap, "ctf3") == 0 || - str_comp(m_ppServerlist[i]->m_Info.m_aMap, "ctf4") == 0 || - str_comp(m_ppServerlist[i]->m_Info.m_aMap, "ctf5") == 0) - ) - { - Filtered = 1; - } - else if(g_Config.m_BrFilterPing < m_ppServerlist[i]->m_Info.m_Latency) - Filtered = 1; - else if(g_Config.m_BrFilterCompatversion && str_comp_num(m_ppServerlist[i]->m_Info.m_aVersion, m_aNetVersion, 3) != 0) - Filtered = 1; - else if(g_Config.m_BrFilterServerAddress[0] && !str_find_nocase(m_ppServerlist[i]->m_Info.m_aAddress, g_Config.m_BrFilterServerAddress)) - Filtered = 1; - else if(g_Config.m_BrFilterGametype[0] && !str_find_nocase(m_ppServerlist[i]->m_Info.m_aGameType, g_Config.m_BrFilterGametype)) - Filtered = 1; - else if(g_Config.m_BrFilterString[0] != 0) - { - int MatchFound = 0; - - m_ppServerlist[i]->m_Info.m_QuickSearchHit = 0; - - // match against server name - if(str_find_nocase(m_ppServerlist[i]->m_Info.m_aName, g_Config.m_BrFilterString)) - { - MatchFound = 1; - m_ppServerlist[i]->m_Info.m_QuickSearchHit |= IServerBrowser::QUICK_SERVERNAME; - } - - // match against players - for(p = 0; p < m_ppServerlist[i]->m_Info.m_NumClients; p++) - { - if(str_find_nocase(m_ppServerlist[i]->m_Info.m_aClients[p].m_aName, g_Config.m_BrFilterString) || - str_find_nocase(m_ppServerlist[i]->m_Info.m_aClients[p].m_aClan, g_Config.m_BrFilterString)) - { - MatchFound = 1; - m_ppServerlist[i]->m_Info.m_QuickSearchHit |= IServerBrowser::QUICK_PLAYER; - break; - } - } - - // match against map - if(str_find_nocase(m_ppServerlist[i]->m_Info.m_aMap, g_Config.m_BrFilterString)) - { - MatchFound = 1; - m_ppServerlist[i]->m_Info.m_QuickSearchHit |= IServerBrowser::QUICK_MAPNAME; - } - - if(!MatchFound) - Filtered = 1; - } - } - - if(Filtered == 0) - m_pSortedServerlist[m_NumSortedServers++] = i; - } -} - -int CServerBrowser::SortHash() const -{ - int i = g_Config.m_BrSort&0xf; - i |= g_Config.m_BrFilterEmpty<<4; - i |= g_Config.m_BrFilterFull<<5; - i |= g_Config.m_BrFilterSpectators<<6; - i |= g_Config.m_BrFilterFriends<<7; - i |= g_Config.m_BrFilterPw<<8; - i |= g_Config.m_BrSortOrder<<9; - i |= g_Config.m_BrFilterCompatversion<<10; - i |= g_Config.m_BrFilterPure<<11; - i |= g_Config.m_BrFilterPureMap<<12; - i |= g_Config.m_BrFilterPing<<18; - return i; -} - -void CServerBrowser::Sort() -{ - int i; - - // create filtered list - Filter(); - - // sort - if(g_Config.m_BrSort == IServerBrowser::SORT_NAME) - std::sort(m_pSortedServerlist, m_pSortedServerlist+m_NumSortedServers, SortWrap(this, &CServerBrowser::SortCompareName)); - else if(g_Config.m_BrSort == IServerBrowser::SORT_PING) - std::sort(m_pSortedServerlist, m_pSortedServerlist+m_NumSortedServers, SortWrap(this, &CServerBrowser::SortComparePing)); - else if(g_Config.m_BrSort == IServerBrowser::SORT_MAP) - std::sort(m_pSortedServerlist, m_pSortedServerlist+m_NumSortedServers, SortWrap(this, &CServerBrowser::SortCompareMap)); - else if(g_Config.m_BrSort == IServerBrowser::SORT_NUMPLAYERS) - std::sort(m_pSortedServerlist, m_pSortedServerlist+m_NumSortedServers, SortWrap(this, - g_Config.m_BrFilterSpectators ? &CServerBrowser::SortCompareNumPlayers : &CServerBrowser::SortCompareNumClients)); - else if(g_Config.m_BrSort == IServerBrowser::SORT_GAMETYPE) - std::sort(m_pSortedServerlist, m_pSortedServerlist+m_NumSortedServers, SortWrap(this, &CServerBrowser::SortCompareGametype)); - - // invert the list if requested - if(g_Config.m_BrSortOrder) - { - for(i = 0; i < m_NumSortedServers/2; i++) - { - int Temp = m_pSortedServerlist[i]; - m_pSortedServerlist[i] = m_pSortedServerlist[m_NumSortedServers-i-1]; - m_pSortedServerlist[m_NumSortedServers-i-1] = Temp; - } - } - - // set indexes - for(i = 0; i < m_NumSortedServers; i++) - m_ppServerlist[m_pSortedServerlist[i]]->m_Info.m_SortedIndex = i; - - str_copy(m_aFilterGametypeString, g_Config.m_BrFilterGametype, sizeof(m_aFilterGametypeString)); - str_copy(m_aFilterString, g_Config.m_BrFilterString, sizeof(m_aFilterString)); - m_Sorthash = SortHash(); -} - -void CServerBrowser::RemoveRequest(CServerEntry *pEntry) -{ - if(pEntry->m_pPrevReq || pEntry->m_pNextReq || m_pFirstReqServer == pEntry) - { - if(pEntry->m_pPrevReq) - pEntry->m_pPrevReq->m_pNextReq = pEntry->m_pNextReq; - else - m_pFirstReqServer = pEntry->m_pNextReq; - - if(pEntry->m_pNextReq) - pEntry->m_pNextReq->m_pPrevReq = pEntry->m_pPrevReq; - else - m_pLastReqServer = pEntry->m_pPrevReq; - - pEntry->m_pPrevReq = 0; - pEntry->m_pNextReq = 0; - m_NumRequests--; - } -} - -CServerBrowser::CServerEntry *CServerBrowser::Find(const NETADDR &Addr) -{ - CServerEntry *pEntry = m_aServerlistIp[Addr.ip[0]]; - - for(; pEntry; pEntry = pEntry->m_pNextIp) - { - if(net_addr_comp(&pEntry->m_Addr, &Addr) == 0) - return pEntry; - } - return (CServerEntry*)0; -} - -void CServerBrowser::QueueRequest(CServerEntry *pEntry) -{ - // add it to the list of servers that we should request info from - pEntry->m_pPrevReq = m_pLastReqServer; - if(m_pLastReqServer) - m_pLastReqServer->m_pNextReq = pEntry; - else - m_pFirstReqServer = pEntry; - m_pLastReqServer = pEntry; - - m_NumRequests++; -} - -void CServerBrowser::SetInfo(CServerEntry *pEntry, const CServerInfo &Info) -{ - int Fav = pEntry->m_Info.m_Favorite; - pEntry->m_Info = Info; - pEntry->m_Info.m_Favorite = Fav; - pEntry->m_Info.m_NetAddr = pEntry->m_Addr; - - // all these are just for nice compability - if(pEntry->m_Info.m_aGameType[0] == '0' && pEntry->m_Info.m_aGameType[1] == 0) - str_copy(pEntry->m_Info.m_aGameType, "DM", sizeof(pEntry->m_Info.m_aGameType)); - else if(pEntry->m_Info.m_aGameType[0] == '1' && pEntry->m_Info.m_aGameType[1] == 0) - str_copy(pEntry->m_Info.m_aGameType, "TDM", sizeof(pEntry->m_Info.m_aGameType)); - else if(pEntry->m_Info.m_aGameType[0] == '2' && pEntry->m_Info.m_aGameType[1] == 0) - str_copy(pEntry->m_Info.m_aGameType, "CTF", sizeof(pEntry->m_Info.m_aGameType)); - - /*if(!request) - { - pEntry->m_Info.latency = (time_get()-pEntry->request_time)*1000/time_freq(); - RemoveRequest(pEntry); - }*/ - - pEntry->m_GotInfo = 1; - Sort(); -} - -CServerBrowser::CServerEntry *CServerBrowser::Add(const NETADDR &Addr) -{ - int Hash = Addr.ip[0]; - CServerEntry *pEntry = 0; - int i; - - // create new pEntry - pEntry = (CServerEntry *)m_ServerlistHeap.Allocate(sizeof(CServerEntry)); - mem_zero(pEntry, sizeof(CServerEntry)); - - // set the info - pEntry->m_Addr = Addr; - pEntry->m_Info.m_NetAddr = Addr; - - pEntry->m_Info.m_Latency = 999; - str_format(pEntry->m_Info.m_aAddress, sizeof(pEntry->m_Info.m_aAddress), "%d.%d.%d.%d:%d", - Addr.ip[0], Addr.ip[1], Addr.ip[2], - Addr.ip[3], Addr.port); - str_format(pEntry->m_Info.m_aName, sizeof(pEntry->m_Info.m_aName), "%d.%d.%d.%d:%d", - Addr.ip[0], Addr.ip[1], Addr.ip[2], - Addr.ip[3], Addr.port); - - /*if(serverlist_type == IServerBrowser::TYPE_LAN) - pEntry->m_Info.latency = (time_get()-broadcast_time)*1000/time_freq();*/ - - // check if it's a favorite - for(i = 0; i < m_NumFavoriteServers; i++) - { - if(net_addr_comp(&Addr, &m_aFavoriteServers[i]) == 0) - pEntry->m_Info.m_Favorite = 1; - } - - // add to the hash list - pEntry->m_pNextIp = m_aServerlistIp[Hash]; - m_aServerlistIp[Hash] = pEntry; - - if(m_NumServers == m_NumServerCapacity) - { - CServerEntry **ppNewlist; - m_NumServerCapacity += 100; - ppNewlist = (CServerEntry **)mem_alloc(m_NumServerCapacity*sizeof(CServerEntry*), 1); - mem_copy(ppNewlist, m_ppServerlist, m_NumServers*sizeof(CServerEntry*)); - mem_free(m_ppServerlist); - m_ppServerlist = ppNewlist; - } - - // add to list - m_ppServerlist[m_NumServers] = pEntry; - pEntry->m_Info.m_ServerIndex = m_NumServers; - m_NumServers++; - - return pEntry; -} - -void CServerBrowser::Set(const NETADDR &Addr, int Type, int Token, const CServerInfo *pInfo) -{ - CServerEntry *pEntry = 0; - if(Type == IServerBrowser::SET_MASTER_ADD) - { - if(m_ServerlistType != IServerBrowser::TYPE_INTERNET) - return; - - if(!Find(Addr)) - { - pEntry = Add(Addr); - QueueRequest(pEntry); - } - } - else if(Type == IServerBrowser::SET_FAV_ADD) - { - if(m_ServerlistType != IServerBrowser::TYPE_FAVORITES) - return; - - if(!Find(Addr)) - { - pEntry = Add(Addr); - QueueRequest(pEntry); - } - } - else if(Type == IServerBrowser::SET_TOKEN) - { - if(Token != m_CurrentToken) - return; - - pEntry = Find(Addr); - if(!pEntry) - pEntry = Add(Addr); - if(pEntry) - { - SetInfo(pEntry, *pInfo); - if(m_ServerlistType == IServerBrowser::TYPE_LAN) - pEntry->m_Info.m_Latency = min(static_cast((time_get()-m_BroadcastTime)*1000/time_freq()), 999); - else - pEntry->m_Info.m_Latency = min(static_cast((time_get()-pEntry->m_RequestTime)*1000/time_freq()), 999); - RemoveRequest(pEntry); - } - } - - Sort(); -} - -void CServerBrowser::Refresh(int Type) -{ - // clear out everything - m_ServerlistHeap.Reset(); - m_NumServers = 0; - m_NumSortedServers = 0; - mem_zero(m_aServerlistIp, sizeof(m_aServerlistIp)); - m_pFirstReqServer = 0; - m_pLastReqServer = 0; - m_NumRequests = 0; - - // next token - m_CurrentToken = (m_CurrentToken+1)&0xff; - - // - m_ServerlistType = Type; - - if(Type == IServerBrowser::TYPE_LAN) - { - unsigned char Buffer[sizeof(SERVERBROWSE_GETINFO)+1]; - CNetChunk Packet; - int i; - - mem_copy(Buffer, SERVERBROWSE_GETINFO, sizeof(SERVERBROWSE_GETINFO)); - Buffer[sizeof(SERVERBROWSE_GETINFO)] = m_CurrentToken; - - Packet.m_ClientID = -1; - mem_zero(&Packet, sizeof(Packet)); - Packet.m_Address.ip[0] = 255; - Packet.m_Address.ip[1] = 255; - Packet.m_Address.ip[2] = 255; - Packet.m_Address.ip[3] = 255; - Packet.m_Flags = NETSENDFLAG_CONNLESS; - Packet.m_DataSize = sizeof(Buffer); - Packet.m_pData = Buffer; - m_BroadcastTime = time_get(); - - for(i = 8303; i <= 8310; i++) - { - Packet.m_Address.port = i; - m_pNetClient->Send(&Packet); - } - - if(g_Config.m_Debug) - m_pConsole->Print(IConsole::OUTPUT_LEVEL_DEBUG, "client_srvbrowse", "broadcasting for servers"); - } - else if(Type == IServerBrowser::TYPE_INTERNET) - m_NeedRefresh = 1; - else if(Type == IServerBrowser::TYPE_FAVORITES) - { - for(int i = 0; i < m_NumFavoriteServers; i++) - Set(m_aFavoriteServers[i], IServerBrowser::SET_FAV_ADD, -1, 0); - } -} - -void CServerBrowser::RequestImpl(const NETADDR &Addr, CServerEntry *pEntry) const -{ - unsigned char Buffer[sizeof(SERVERBROWSE_GETINFO)+1]; - CNetChunk Packet; - - if(g_Config.m_Debug) - { - char aBuf[256]; - str_format(aBuf, sizeof(aBuf),"requesting server info from %d.%d.%d.%d:%d", - Addr.ip[0], Addr.ip[1], Addr.ip[2], - Addr.ip[3], Addr.port); - m_pConsole->Print(IConsole::OUTPUT_LEVEL_DEBUG, "client_srvbrowse", aBuf); - } - - mem_copy(Buffer, SERVERBROWSE_GETINFO, sizeof(SERVERBROWSE_GETINFO)); - Buffer[sizeof(SERVERBROWSE_GETINFO)] = m_CurrentToken; - - Packet.m_ClientID = -1; - Packet.m_Address = Addr; - Packet.m_Flags = NETSENDFLAG_CONNLESS; - Packet.m_DataSize = sizeof(Buffer); - Packet.m_pData = Buffer; - - m_pNetClient->Send(&Packet); - - if(pEntry) - pEntry->m_RequestTime = time_get(); -} - -void CServerBrowser::Request(const NETADDR &Addr) const -{ - RequestImpl(Addr, 0); -} - - -void CServerBrowser::Update(bool ForceResort) -{ - int64 Timeout = time_freq()/2; // TODO 0.6: increase this again - int64 Now = time_get(); - int Count; - CServerEntry *pEntry, *pNext; - - // do server list requests - if(m_NeedRefresh && !m_pMasterServer->IsRefreshing()) - { - NETADDR Addr; - CNetChunk Packet; - int i; - - m_NeedRefresh = 0; - - mem_zero(&Packet, sizeof(Packet)); - Packet.m_ClientID = -1; - Packet.m_Flags = NETSENDFLAG_CONNLESS; - Packet.m_DataSize = sizeof(SERVERBROWSE_GETLIST); - Packet.m_pData = SERVERBROWSE_GETLIST; - - for(i = 0; i < IMasterServer::MAX_MASTERSERVERS; i++) - { - Addr = m_pMasterServer->GetAddr(i); - if(!Addr.ip[0] && !Addr.ip[1] && !Addr.ip[2] && !Addr.ip[3]) - continue; - - Packet.m_Address = Addr; - m_pNetClient->Send(&Packet); - } - - if(g_Config.m_Debug) - m_pConsole->Print(IConsole::OUTPUT_LEVEL_DEBUG, "client_srvbrowse", "requesting server list"); - } - - // do timeouts - pEntry = m_pFirstReqServer; - while(1) - { - if(!pEntry) // no more entries - break; - - pNext = pEntry->m_pNextReq; - - if(pEntry->m_RequestTime && pEntry->m_RequestTime+Timeout < Now) - { - // timeout - RemoveRequest(pEntry); - } - - pEntry = pNext; - } - - // do timeouts - pEntry = m_pFirstReqServer; - Count = 0; - while(1) - { - if(!pEntry) // no more entries - break; - - // no more then 10 concurrent requests - if(Count == g_Config.m_BrMaxRequests) - break; - - if(pEntry->m_RequestTime == 0) - RequestImpl(pEntry->m_Addr, pEntry); - - Count++; - pEntry = pEntry->m_pNextReq; - } - - // check if we need to resort - if(m_Sorthash != SortHash() || ForceResort) - Sort(); -} - - -bool CServerBrowser::IsFavorite(const NETADDR &Addr) const -{ - // search for the address - int i; - for(i = 0; i < m_NumFavoriteServers; i++) - { - if(net_addr_comp(&Addr, &m_aFavoriteServers[i]) == 0) - return true; - } - return false; -} - -void CServerBrowser::AddFavorite(const NETADDR &Addr) -{ - CServerEntry *pEntry; - - if(m_NumFavoriteServers == MAX_FAVORITES) - return; - - // make sure that we don't already have the server in our list - for(int i = 0; i < m_NumFavoriteServers; i++) - { - if(net_addr_comp(&Addr, &m_aFavoriteServers[i]) == 0) - return; - } - - // add the server to the list - m_aFavoriteServers[m_NumFavoriteServers++] = Addr; - pEntry = Find(Addr); - if(pEntry) - pEntry->m_Info.m_Favorite = 1; - - if(g_Config.m_Debug) - { - char aBuf[256]; - str_format(aBuf, sizeof(aBuf), "added fav, %d.%d.%d.%d:%d", Addr.ip[0], Addr.ip[1], Addr.ip[2], Addr.ip[3], Addr.port); - m_pConsole->Print(IConsole::OUTPUT_LEVEL_DEBUG, "client_srvbrowse", aBuf); - } -} - -void CServerBrowser::RemoveFavorite(const NETADDR &Addr) -{ - int i; - CServerEntry *pEntry; - - for(i = 0; i < m_NumFavoriteServers; i++) - { - if(net_addr_comp(&Addr, &m_aFavoriteServers[i]) == 0) - { - mem_move(&m_aFavoriteServers[i], &m_aFavoriteServers[i+1], sizeof(NETADDR)*(m_NumFavoriteServers-(i+1))); - m_NumFavoriteServers--; - - pEntry = Find(Addr); - if(pEntry) - pEntry->m_Info.m_Favorite = 0; - - return; - } - } -} - -bool CServerBrowser::IsRefreshing() const -{ - return m_pFirstReqServer != 0; -} - -bool CServerBrowser::IsRefreshingMasters() const -{ - return m_pMasterServer->IsRefreshing(); -} - - -int CServerBrowser::LoadingProgression() const -{ - if(m_NumServers == 0) - return 0; - - int Servers = m_NumServers; - int Loaded = m_NumServers-m_NumRequests; - return 100.0f * Loaded/Servers; -} - - -void CServerBrowser::ConfigSaveCallback(IConfig *pConfig, void *pUserData) -{ - CServerBrowser *pSelf = (CServerBrowser *)pUserData; - - int i; - char aAddrStr[128]; - char aBuffer[256]; - for(i = 0; i < pSelf->m_NumFavoriteServers; i++) - { - net_addr_str(&pSelf->m_aFavoriteServers[i], aAddrStr, sizeof(aAddrStr)); - str_format(aBuffer, sizeof(aBuffer), "add_favorite %s", aAddrStr); - pConfig->WriteLine(aBuffer); - } -} diff --git a/src/engine/client/srvbrowse.h b/src/engine/client/srvbrowse.h deleted file mode 100644 index 876627bf..00000000 --- a/src/engine/client/srvbrowse.h +++ /dev/null @@ -1,117 +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_CLIENT_SRVBROWSE_H -#define ENGINE_CLIENT_SRVBROWSE_H - -#include - -class CServerBrowser : public IServerBrowser -{ -public: - class CServerEntry - { - public: - NETADDR m_Addr; - int64 m_RequestTime; - int m_GotInfo; - CServerInfo m_Info; - - CServerEntry *m_pNextIp; // ip hashed list - - CServerEntry *m_pPrevReq; // request list - CServerEntry *m_pNextReq; - }; - - enum - { - MAX_FAVORITES=256 - }; - - CServerBrowser(); - - // interface functions - void Refresh(int Type); - bool IsRefreshing() const; - bool IsRefreshingMasters() const; - int LoadingProgression() const; - - int NumServers() const { return m_NumServers; } - - int NumSortedServers() const { return m_NumSortedServers; } - const CServerInfo *SortedGet(int Index) const; - - bool IsFavorite(const NETADDR &Addr) const; - void AddFavorite(const NETADDR &Addr); - void RemoveFavorite(const NETADDR &Addr); - - // - void Update(bool ForceResort); - void Set(const NETADDR &Addr, int Type, int Token, const CServerInfo *pInfo); - void Request(const NETADDR &Addr) const; - - void SetBaseInfo(class CNetClient *pClient, const char *pNetVersion); - -private: - CNetClient *m_pNetClient; - IMasterServer *m_pMasterServer; - class IConsole *m_pConsole; - class IFriends *m_pFriends; - char m_aNetVersion[128]; - - CHeap m_ServerlistHeap; - CServerEntry **m_ppServerlist; - int *m_pSortedServerlist; - - NETADDR m_aFavoriteServers[MAX_FAVORITES]; - int m_NumFavoriteServers; - - CServerEntry *m_aServerlistIp[256]; // ip hash list - - CServerEntry *m_pFirstReqServer; // request list - CServerEntry *m_pLastReqServer; - int m_NumRequests; - - int m_NeedRefresh; - - int m_NumSortedServers; - int m_NumSortedServersCapacity; - int m_NumServers; - int m_NumServerCapacity; - - int m_Sorthash; - char m_aFilterString[64]; - char m_aFilterGametypeString[128]; - - // the token is to keep server refresh separated from each other - int m_CurrentToken; - - int m_ServerlistType; - int64 m_BroadcastTime; - - // sorting criterions - bool SortCompareName(int Index1, int Index2) const; - bool SortCompareMap(int Index1, int Index2) const; - bool SortComparePing(int Index1, int Index2) const; - bool SortCompareGametype(int Index1, int Index2) const; - bool SortCompareNumPlayers(int Index1, int Index2) const; - bool SortCompareNumClients(int Index1, int Index2) const; - - // - void Filter(); - void Sort(); - int SortHash() const; - - CServerEntry *Find(const NETADDR &Addr); - CServerEntry *Add(const NETADDR &Addr); - - void RemoveRequest(CServerEntry *pEntry); - void QueueRequest(CServerEntry *pEntry); - - void RequestImpl(const NETADDR &Addr, CServerEntry *pEntry) const; - - void SetInfo(CServerEntry *pEntry, const CServerInfo &Info); - - static void ConfigSaveCallback(IConfig *pConfig, void *pUserData); -}; - -#endif -- cgit 1.4.1