ddnet/src/engine/client/serverbrowser.cpp

2218 lines
65 KiB
C++
Raw Normal View History

2010-11-20 10:37:14 +00:00
/* (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. */
2021-04-17 14:05:24 +00:00
#include "serverbrowser.h"
#include "serverbrowser_http.h"
#include "serverbrowser_ping_cache.h"
Add client-side HTTP server info Summary ======= The idea of this is that clients will not have to ping each server for server infos which takes long, leaks the client's IP address even to servers the user does not join and is a DoS vector of the game servers for attackers. For the Internet, DDNet and KoG tab, the server list is entirely fetched from the master server, filtering out servers that don't belong into the list. The favorites tab is also supposed to work that way, except for servers that are marked as "also ping this server if it's not in the master server list". The LAN tab continues to broadcast the server info packet to find servers in the LAN. How does it work? ================= The client ships with a list of master server list URLs. On first start, the client checks which of these work and selects the fastest one. Querying the server list is a HTTP GET request on that URL. The response is a JSON document that contains server infos, server addresses as URLs and an approximate location. It can also contain a legacy server list which is a list of bare IP addresses similar to the functionality the old master servers provided via UDP. This allows us to backtrack on the larger update if it won't work out. Lost functionality ================== (also known as user-visible changes) Since the client doesn't ping each server in the list anymore, it has no way of knowing its latency to the servers. This is alleviated a bit by providing an approximate location for each server (continent) so the client only has to know its own location for approximating pings.
2018-07-11 20:46:04 +00:00
#include <algorithm>
#include <unordered_set>
#include <vector>
2010-05-29 07:25:38 +00:00
#include <base/hash_ctxt.h>
#include <base/log.h>
2010-05-29 07:25:38 +00:00
#include <base/system.h>
2011-03-23 12:06:35 +00:00
2010-05-29 07:25:38 +00:00
#include <engine/shared/config.h>
#include <engine/shared/json.h>
Add HTTP masterserver registering and HTTP masterserver Registering ----------- The idea is that game servers push their server info to the masterservers every 15 seconds or when the server info changes, but not more than once per second. The game servers do not support the old registering protocol anymore, the backward compatibility is handled by the masterserver. The register call is a HTTP POST to a URL like `https://master1.ddnet.tw/ddnet/15/register` and looks like this: ```json POST /ddnet/15/register HTTP/1.1 Address: tw-0.6+udp://connecting-address.invalid:8303 Secret: 81fa3955-6f83-4290-818d-31c0906b1118 Challenge-Secret: 81fa3955-6f83-4290-818d-31c0906b1118:tw0.6/ipv6 Info-Serial: 0 { "max_clients": 64, "max_players": 64, "passworded": false, "game_type": "TestDDraceNetwork", "name": "My DDNet server", "map": { "name": "dm1", "sha256": "0b0c481d77519c32fbe85624ef16ec0fa9991aec7367ad538bd280f28d8c26cf", "size": 5805 }, "version": "0.6.4, 16.0.3", "clients": [] } ``` The `Address` header declares that the server wants to register itself as a `tw-0.6+udp` server, i.e. a server speaking a Teeworlds-0.6-compatible protocol. The free-form `Secret` header is used as a server identity, the server list will be deduplicated via this secret. The free-form `Challenge-Secret` is sent back via UDP for a port forward check. This might have security implications as the masterserver can be asked to send a UDP packet containing some user-controlled bytes. This is somewhat mitigated by the fact that it can only go to an attacker-controlled IP address. The `Info-Serial` header is an integer field that should increase each time the server info (in the body) changes. The masterserver uses that field to ensure that it doesn't use old server infos. The body is a free-form JSON object set by the game server. It should contain certain keys in the correct form to be accepted by clients. The body is optional if the masterserver already confirmed the reception of the info with the given `Info-Serial`. Not shown in this payload is the `Connless-Token` header that is used for Teeworlds 0.7 style communication. Also not shown is the `Challenge-Token` that should be included once the server receives the challenge token via UDP. The masterserver responds with a `200 OK` with a body like this: ``` {"status":"success"} ``` The `status` field can be `success` if the server was successfully registered on the masterserver, `need_challenge` if the masterserver wants the correct `Challenge-Token` header before the register process is successful, `need_info` if the server sent an empty body but the masterserver doesn't actually know the server info. It can also be `error` if the request was malformed, only in this case an HTTP status code except `200 OK` is sent. Synchronization --------------- The masterserver keeps state and outputs JSON files every second. ```json { "servers": [ { "addresses": [ "tw-0.6+udp://127.0.0.1:8303", "tw-0.6+udp://[::1]:8303" ], "info_serial": 0, "info": { "max_clients": 64, "max_players": 64, "passworded": false, "game_type": "TestDDraceNetwork", "name": "My DDNet server", "map": { "name": "dm1", "sha256": "0b0c481d77519c32fbe85624ef16ec0fa9991aec7367ad538bd280f28d8c26cf", "size": 5805 }, "version": "0.6.4, 16.0.3", "clients": [] } } ] } ``` `servers.json` (or configured by `--out`) is a server list that is compatible with DDNet 15.5+ clients. It is a JSON object containing a single key `servers` with a list of game servers. Each game server is represented by a JSON object with an `addresses` key containing a list of all known addresses of the server and an `info` key containing the free-form server info sent by the game server. The free-form `info` JSON object re-encoded by the master server and thus canonicalized and stripped of any whitespace characters outside strings. ```json { "kind": "mastersrv", "now": 1816002, "secrets": { "tw-0.6+udp://127.0.0.1:8303": { "ping_time": 1811999, "secret": "42d8f991-f2fa-46e5-a9ae-ebcc93846feb" }, "tw-0.6+udp://[::1]:8303": { "ping_time": 1811999, "secret": "42d8f991-f2fa-46e5-a9ae-ebcc93846feb" } }, "servers": { "42d8f991-f2fa-46e5-a9ae-ebcc93846feb": { "info_serial": 0, "info": { "max_clients": 64, "max_players": 64, "passworded": false, "game_type": "TestDDraceNetwork", "name": "My DDNet server", "map": { "name": "dm1", "sha256": "0b0c481d77519c32fbe85624ef16ec0fa9991aec7367ad538bd280f28d8c26cf", "size": 5805 }, "version": "0.6.4, 16.0.3", "clients": [] } } } } ``` `--write-dump` outputs a JSON file compatible with `--read-dump-dir`, this can be used to synchronize servers across different masterservers. `--read-dump-dir` is also used to ingest servers from the backward compatibility layer that pings each server for their server info using the old protocol. The `kind` field describe that this is `mastersrv` output and not from a `backcompat`. This is used for prioritizing `mastersrv` information over `backcompat` information. The `now` field contains an integer describing the current time in milliseconds relative an unspecified epoch that is fixed for each JSON file. This is done instead of using the current time as the epoch for better compression of non-changing data. `secrets` is a map from each server address and to a JSON object containing the last ping time (`ping_time`) in milliseconds relative to the same epoch as before, and the server secret (`secret`) that is used to unify server infos from different addresses of the same logical server. `servers` is a map from the aforementioned `secret`s to the corresponding `info_serial` and `info`. ```json [ "tw-0.6+udp://127.0.0.1:8303", "tw-0.6+udp://[::1]:8303" ] ``` `--write-addresses` outputs a JSON file containing all addresses corresponding to servers that are registered to HTTP masterservers. It does not contain the servers that are obtained via backward compatibility measures. This file can be used by an old-style masterserver to also list new-style servers without the game servers having to register there. An implementation of this can be found at https://github.com/heinrich5991/teeworlds/tree/mastersrv_6_backcompat for Teeworlds 0.5/0.6 masterservers and at https://github.com/heinrich5991/teeworlds/tree/mastersrv_7_backcompat for Teeworlds 0.7 masterservers. All these JSON files can be sent over the network in an efficient way using https://github.com/heinrich5991/twmaster-collect. It establishes a zstd-compressed TCP connection authenticated by a string token that is sent in plain-text. It watches the specified file and transmits it every time it changes. Due to the zstd-compression, the data sent over the network is similar to the size of a diff. Implementation -------------- The masterserver implementation was done in Rust. The current gameserver register implementation doesn't support more than one masterserver for registering.
2022-05-19 20:03:17 +00:00
#include <engine/shared/masterserver.h>
2011-03-23 12:06:35 +00:00
#include <engine/shared/network.h>
#include <engine/shared/protocol.h>
Add client-side HTTP server info Summary ======= The idea of this is that clients will not have to ping each server for server infos which takes long, leaks the client's IP address even to servers the user does not join and is a DoS vector of the game servers for attackers. For the Internet, DDNet and KoG tab, the server list is entirely fetched from the master server, filtering out servers that don't belong into the list. The favorites tab is also supposed to work that way, except for servers that are marked as "also ping this server if it's not in the master server list". The LAN tab continues to broadcast the server info packet to find servers in the LAN. How does it work? ================= The client ships with a list of master server list URLs. On first start, the client checks which of these work and selects the fastest one. Querying the server list is a HTTP GET request on that URL. The response is a JSON document that contains server infos, server addresses as URLs and an approximate location. It can also contain a legacy server list which is a list of bare IP addresses similar to the functionality the old master servers provided via UDP. This allows us to backtrack on the larger update if it won't work out. Lost functionality ================== (also known as user-visible changes) Since the client doesn't ping each server in the list anymore, it has no way of knowing its latency to the servers. This is alleviated a bit by providing an approximate location for each server (continent) so the client only has to know its own location for approximating pings.
2018-07-11 20:46:04 +00:00
#include <engine/shared/serverinfo.h>
2010-05-29 07:25:38 +00:00
2011-03-23 12:06:35 +00:00
#include <engine/console.h>
Add client-side HTTP server info Summary ======= The idea of this is that clients will not have to ping each server for server infos which takes long, leaks the client's IP address even to servers the user does not join and is a DoS vector of the game servers for attackers. For the Internet, DDNet and KoG tab, the server list is entirely fetched from the master server, filtering out servers that don't belong into the list. The favorites tab is also supposed to work that way, except for servers that are marked as "also ping this server if it's not in the master server list". The LAN tab continues to broadcast the server info packet to find servers in the LAN. How does it work? ================= The client ships with a list of master server list URLs. On first start, the client checks which of these work and selects the fastest one. Querying the server list is a HTTP GET request on that URL. The response is a JSON document that contains server infos, server addresses as URLs and an approximate location. It can also contain a legacy server list which is a list of bare IP addresses similar to the functionality the old master servers provided via UDP. This allows us to backtrack on the larger update if it won't work out. Lost functionality ================== (also known as user-visible changes) Since the client doesn't ping each server in the list anymore, it has no way of knowing its latency to the servers. This is alleviated a bit by providing an approximate location for each server (continent) so the client only has to know its own location for approximating pings.
2018-07-11 20:46:04 +00:00
#include <engine/engine.h>
#include <engine/favorites.h>
2011-03-23 12:06:35 +00:00
#include <engine/friends.h>
2023-12-18 19:01:26 +00:00
#include <engine/http.h>
2014-09-13 14:36:25 +00:00
#include <engine/storage.h>
2010-05-29 07:25:38 +00:00
static constexpr const char *COMMUNITY_COUNTRY_NONE = "none";
static constexpr const char *COMMUNITY_TYPE_NONE = "None";
2022-12-05 21:16:01 +00:00
class CSortWrap
2010-05-29 07:25:38 +00:00
{
typedef bool (CServerBrowser::*SortFunc)(int, int) const;
SortFunc m_pfnSort;
CServerBrowser *m_pThis;
2010-05-29 07:25:38 +00:00
public:
2022-12-05 21:16:01 +00:00
CSortWrap(CServerBrowser *pServer, SortFunc Func) :
m_pfnSort(Func), m_pThis(pServer) {}
bool operator()(int a, int b) { return (g_Config.m_BrSortOrder ? (m_pThis->*m_pfnSort)(b, a) : (m_pThis->*m_pfnSort)(a, b)); }
2010-05-29 07:25:38 +00:00
};
bool matchesPart(const char *a, const char *b)
{
return str_utf8_find_nocase(a, b) != nullptr;
}
bool matchesExactly(const char *a, const char *b)
{
return str_comp(a, &b[1]) == 0;
}
CServerBrowser::CServerBrowser() :
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
m_CountriesFilter([this]() { return CurrentCommunities(); }),
m_TypesFilter([this]() { return CurrentCommunities(); })
2010-05-29 07:25:38 +00:00
{
m_ppServerlist = nullptr;
m_pSortedServerlist = nullptr;
2010-05-29 07:25:38 +00:00
m_NeedResort = false;
m_Sorthash = 0;
2010-05-29 07:25:38 +00:00
m_NumSortedServersCapacity = 0;
m_NumServerCapacity = 0;
m_ServerlistType = 0;
m_BroadcastTime = 0;
secure_random_fill(m_aTokenSeed, sizeof(m_aTokenSeed));
CleanUp();
}
CServerBrowser::~CServerBrowser()
{
free(m_ppServerlist);
free(m_pSortedServerlist);
json_value_free(m_pDDNetInfo);
Add client-side HTTP server info Summary ======= The idea of this is that clients will not have to ping each server for server infos which takes long, leaks the client's IP address even to servers the user does not join and is a DoS vector of the game servers for attackers. For the Internet, DDNet and KoG tab, the server list is entirely fetched from the master server, filtering out servers that don't belong into the list. The favorites tab is also supposed to work that way, except for servers that are marked as "also ping this server if it's not in the master server list". The LAN tab continues to broadcast the server info packet to find servers in the LAN. How does it work? ================= The client ships with a list of master server list URLs. On first start, the client checks which of these work and selects the fastest one. Querying the server list is a HTTP GET request on that URL. The response is a JSON document that contains server infos, server addresses as URLs and an approximate location. It can also contain a legacy server list which is a list of bare IP addresses similar to the functionality the old master servers provided via UDP. This allows us to backtrack on the larger update if it won't work out. Lost functionality ================== (also known as user-visible changes) Since the client doesn't ping each server in the list anymore, it has no way of knowing its latency to the servers. This is alleviated a bit by providing an approximate location for each server (continent) so the client only has to know its own location for approximating pings.
2018-07-11 20:46:04 +00:00
delete m_pHttp;
m_pHttp = nullptr;
2021-04-17 14:05:24 +00:00
delete m_pPingCache;
m_pPingCache = nullptr;
2010-05-29 07:25:38 +00:00
}
void CServerBrowser::SetBaseInfo(class CNetClient *pClient, const char *pNetVersion)
{
m_pNetClient = pClient;
2022-07-09 16:14:56 +00:00
str_copy(m_aNetVersion, pNetVersion);
m_pConsole = Kernel()->RequestInterface<IConsole>();
m_pConfigManager = Kernel()->RequestInterface<IConfigManager>();
Add client-side HTTP server info Summary ======= The idea of this is that clients will not have to ping each server for server infos which takes long, leaks the client's IP address even to servers the user does not join and is a DoS vector of the game servers for attackers. For the Internet, DDNet and KoG tab, the server list is entirely fetched from the master server, filtering out servers that don't belong into the list. The favorites tab is also supposed to work that way, except for servers that are marked as "also ping this server if it's not in the master server list". The LAN tab continues to broadcast the server info packet to find servers in the LAN. How does it work? ================= The client ships with a list of master server list URLs. On first start, the client checks which of these work and selects the fastest one. Querying the server list is a HTTP GET request on that URL. The response is a JSON document that contains server infos, server addresses as URLs and an approximate location. It can also contain a legacy server list which is a list of bare IP addresses similar to the functionality the old master servers provided via UDP. This allows us to backtrack on the larger update if it won't work out. Lost functionality ================== (also known as user-visible changes) Since the client doesn't ping each server in the list anymore, it has no way of knowing its latency to the servers. This is alleviated a bit by providing an approximate location for each server (continent) so the client only has to know its own location for approximating pings.
2018-07-11 20:46:04 +00:00
m_pEngine = Kernel()->RequestInterface<IEngine>();
m_pFavorites = Kernel()->RequestInterface<IFavorites>();
2011-03-23 12:06:35 +00:00
m_pFriends = Kernel()->RequestInterface<IFriends>();
2021-04-17 14:05:24 +00:00
m_pStorage = Kernel()->RequestInterface<IStorage>();
2023-12-18 19:01:26 +00:00
m_pHttpClient = Kernel()->RequestInterface<IHttp>();
2021-04-17 14:05:24 +00:00
m_pPingCache = CreateServerBrowserPingCache(m_pConsole, m_pStorage);
RegisterCommands();
}
void CServerBrowser::OnInit()
{
2023-12-18 19:01:26 +00:00
m_pHttp = CreateServerBrowserHttp(m_pEngine, m_pConsole, m_pStorage, m_pHttpClient, g_Config.m_BrCachedBestServerinfoUrl);
}
void CServerBrowser::RegisterCommands()
{
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
m_pConfigManager->RegisterCallback(CServerBrowser::ConfigSaveCallback, this);
m_pConsole->Register("add_favorite_community", "s[community_id]", CFGFLAG_CLIENT, Con_AddFavoriteCommunity, this, "Add a community as a favorite");
m_pConsole->Register("remove_favorite_community", "s[community_id]", CFGFLAG_CLIENT, Con_RemoveFavoriteCommunity, this, "Remove a community from the favorites");
m_pConsole->Register("add_excluded_community", "s[community_id]", CFGFLAG_CLIENT, Con_AddExcludedCommunity, this, "Add a community to the exclusion filter");
m_pConsole->Register("remove_excluded_community", "s[community_id]", CFGFLAG_CLIENT, Con_RemoveExcludedCommunity, this, "Remove a community from the exclusion filter");
m_pConsole->Register("add_excluded_country", "s[community_id] s[country_code]", CFGFLAG_CLIENT, Con_AddExcludedCountry, this, "Add a country to the exclusion filter for a specific community");
m_pConsole->Register("remove_excluded_country", "s[community_id] s[country_code]", CFGFLAG_CLIENT, Con_RemoveExcludedCountry, this, "Remove a country from the exclusion filter for a specific community");
m_pConsole->Register("add_excluded_type", "s[community_id] s[type]", CFGFLAG_CLIENT, Con_AddExcludedType, this, "Add a type to the exclusion filter for a specific community");
m_pConsole->Register("remove_excluded_type", "s[community_id] s[type]", CFGFLAG_CLIENT, Con_RemoveExcludedType, this, "Remove a type from the exclusion filter for a specific community");
m_pConsole->Register("leak_ip_address_to_all_servers", "", CFGFLAG_CLIENT, Con_LeakIpAddress, this, "Leaks your IP address to all servers by pinging each of them, also acquiring the latency in the process");
}
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
void CServerBrowser::ConfigSaveCallback(IConfigManager *pConfigManager, void *pUserData)
{
CServerBrowser *pThis = static_cast<CServerBrowser *>(pUserData);
pThis->FavoriteCommunitiesFilter().Save(pConfigManager);
pThis->CommunitiesFilter().Save(pConfigManager);
pThis->CountriesFilter().Save(pConfigManager);
pThis->TypesFilter().Save(pConfigManager);
}
void CServerBrowser::Con_AddFavoriteCommunity(IConsole::IResult *pResult, void *pUserData)
{
CServerBrowser *pThis = static_cast<CServerBrowser *>(pUserData);
const char *pCommunityId = pResult->GetString(0);
if(!pThis->ValidateCommunityId(pCommunityId))
return;
pThis->FavoriteCommunitiesFilter().Add(pCommunityId);
}
void CServerBrowser::Con_RemoveFavoriteCommunity(IConsole::IResult *pResult, void *pUserData)
{
CServerBrowser *pThis = static_cast<CServerBrowser *>(pUserData);
const char *pCommunityId = pResult->GetString(0);
if(!pThis->ValidateCommunityId(pCommunityId))
return;
pThis->FavoriteCommunitiesFilter().Remove(pCommunityId);
}
void CServerBrowser::Con_AddExcludedCommunity(IConsole::IResult *pResult, void *pUserData)
{
CServerBrowser *pThis = static_cast<CServerBrowser *>(pUserData);
const char *pCommunityId = pResult->GetString(0);
if(!pThis->ValidateCommunityId(pCommunityId))
return;
pThis->CommunitiesFilter().Add(pCommunityId);
}
void CServerBrowser::Con_RemoveExcludedCommunity(IConsole::IResult *pResult, void *pUserData)
{
CServerBrowser *pThis = static_cast<CServerBrowser *>(pUserData);
const char *pCommunityId = pResult->GetString(0);
if(!pThis->ValidateCommunityId(pCommunityId))
return;
pThis->CommunitiesFilter().Remove(pCommunityId);
}
void CServerBrowser::Con_AddExcludedCountry(IConsole::IResult *pResult, void *pUserData)
{
CServerBrowser *pThis = static_cast<CServerBrowser *>(pUserData);
const char *pCommunityId = pResult->GetString(0);
const char *pCountryName = pResult->GetString(1);
if(!pThis->ValidateCommunityId(pCommunityId) || !pThis->ValidateCountryName(pCountryName))
return;
pThis->CountriesFilter().Add(pCommunityId, pCountryName);
}
void CServerBrowser::Con_RemoveExcludedCountry(IConsole::IResult *pResult, void *pUserData)
{
CServerBrowser *pThis = static_cast<CServerBrowser *>(pUserData);
const char *pCommunityId = pResult->GetString(0);
const char *pCountryName = pResult->GetString(1);
if(!pThis->ValidateCommunityId(pCommunityId) || !pThis->ValidateCountryName(pCountryName))
return;
pThis->CountriesFilter().Remove(pCommunityId, pCountryName);
}
void CServerBrowser::Con_AddExcludedType(IConsole::IResult *pResult, void *pUserData)
{
CServerBrowser *pThis = static_cast<CServerBrowser *>(pUserData);
const char *pCommunityId = pResult->GetString(0);
const char *pTypeName = pResult->GetString(1);
if(!pThis->ValidateCommunityId(pCommunityId) || !pThis->ValidateTypeName(pTypeName))
return;
pThis->TypesFilter().Add(pCommunityId, pTypeName);
}
void CServerBrowser::Con_RemoveExcludedType(IConsole::IResult *pResult, void *pUserData)
{
CServerBrowser *pThis = static_cast<CServerBrowser *>(pUserData);
const char *pCommunityId = pResult->GetString(0);
const char *pTypeName = pResult->GetString(1);
if(!pThis->ValidateCommunityId(pCommunityId) || !pThis->ValidateTypeName(pTypeName))
return;
pThis->TypesFilter().Remove(pCommunityId, pTypeName);
}
void CServerBrowser::Con_LeakIpAddress(IConsole::IResult *pResult, void *pUserData)
{
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
CServerBrowser *pThis = static_cast<CServerBrowser *>(pUserData);
// We only consider the first address of every server.
2022-06-15 17:34:41 +00:00
std::vector<int> vSortedServers;
// Sort servers by IP address, ignoring port.
class CAddrComparer
{
public:
CServerBrowser *m_pThis;
bool operator()(int i, int j) const
{
NETADDR Addr1 = m_pThis->m_ppServerlist[i]->m_Info.m_aAddresses[0];
NETADDR Addr2 = m_pThis->m_ppServerlist[j]->m_Info.m_aAddresses[0];
Addr1.port = 0;
Addr2.port = 0;
return net_addr_comp(&Addr1, &Addr2) < 0;
}
};
2022-06-15 17:34:41 +00:00
vSortedServers.reserve(pThis->m_NumServers);
for(int i = 0; i < pThis->m_NumServers; i++)
{
2022-06-15 17:34:41 +00:00
vSortedServers.push_back(i);
}
2022-06-15 17:34:41 +00:00
std::sort(vSortedServers.begin(), vSortedServers.end(), CAddrComparer{pThis});
// Group the servers into those with same IP address (but differing
// port).
NETADDR Addr;
int Start = -1;
2022-06-15 17:34:41 +00:00
for(int i = 0; i <= (int)vSortedServers.size(); i++)
{
NETADDR NextAddr;
2022-06-15 17:34:41 +00:00
if(i < (int)vSortedServers.size())
{
NextAddr = pThis->m_ppServerlist[vSortedServers[i]]->m_Info.m_aAddresses[0];
NextAddr.port = 0;
}
2022-06-15 17:34:41 +00:00
bool New = Start == -1 || i == (int)vSortedServers.size() || net_addr_comp(&Addr, &NextAddr) != 0;
if(Start != -1 && New)
{
int Chosen = Start + secure_rand_below(i - Start);
2022-06-15 17:34:41 +00:00
CServerEntry *pChosen = pThis->m_ppServerlist[vSortedServers[Chosen]];
pChosen->m_RequestIgnoreInfo = true;
pThis->QueueRequest(pChosen);
char aAddr[NETADDR_MAXSTRSIZE];
net_addr_str(&pChosen->m_Info.m_aAddresses[0], aAddr, sizeof(aAddr), true);
dbg_msg("serverbrowser", "queuing ping request for %s", aAddr);
}
2022-06-15 17:34:41 +00:00
if(i < (int)vSortedServers.size() && New)
{
Start = i;
Addr = NextAddr;
}
}
2010-05-29 07:25:38 +00:00
}
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
static bool ValidIdentifier(const char *pId, size_t MaxLength)
{
if(pId[0] == '\0' || (size_t)str_length(pId) >= MaxLength)
{
return false;
}
for(int i = 0; pId[i] != '\0'; ++i)
{
if(pId[i] == '"' || pId[i] == '/' || pId[i] == '\\')
{
return false;
}
}
return true;
}
static bool ValidateIdentifier(const char *pId, size_t MaxLength, const char *pContext, IConsole *pConsole)
{
if(!ValidIdentifier(pId, MaxLength))
{
char aError[32 + IConsole::CMDLINE_LENGTH];
str_format(aError, sizeof(aError), "%s '%s' is not valid", pContext, pId);
pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "serverbrowser", aError);
return false;
}
return true;
}
bool CServerBrowser::ValidateCommunityId(const char *pCommunityId) const
{
return ValidateIdentifier(pCommunityId, CServerInfo::MAX_COMMUNITY_ID_LENGTH, "Community ID", m_pConsole);
}
bool CServerBrowser::ValidateCountryName(const char *pCountryName) const
{
return ValidateIdentifier(pCountryName, CServerInfo::MAX_COMMUNITY_COUNTRY_LENGTH, "Country name", m_pConsole);
}
bool CServerBrowser::ValidateTypeName(const char *pTypeName) const
{
return ValidateIdentifier(pTypeName, CServerInfo::MAX_COMMUNITY_TYPE_LENGTH, "Type name", m_pConsole);
}
int CServerBrowser::Players(const CServerInfo &Item) const
{
return g_Config.m_BrFilterSpectators ? Item.m_NumPlayers : Item.m_NumClients;
}
int CServerBrowser::Max(const CServerInfo &Item) const
{
return g_Config.m_BrFilterSpectators ? Item.m_MaxPlayers : Item.m_MaxClients;
}
2010-05-29 07:25:38 +00:00
const CServerInfo *CServerBrowser::SortedGet(int Index) const
{
if(Index < 0 || Index >= m_NumSortedServers)
return nullptr;
2010-05-29 07:25:38 +00:00
return &m_ppServerlist[m_pSortedServerlist[Index]]->m_Info;
}
int CServerBrowser::GenerateToken(const NETADDR &Addr) const
{
SHA256_CTX Sha256;
sha256_init(&Sha256);
sha256_update(&Sha256, m_aTokenSeed, sizeof(m_aTokenSeed));
sha256_update(&Sha256, (unsigned char *)&Addr, sizeof(Addr));
SHA256_DIGEST Digest = sha256_finish(&Sha256);
return (Digest.data[0] << 16) | (Digest.data[1] << 8) | Digest.data[2];
}
int CServerBrowser::GetBasicToken(int Token)
{
return Token & 0xff;
}
int CServerBrowser::GetExtraToken(int Token)
{
return Token >> 8;
}
2010-05-29 07:25:38 +00:00
bool CServerBrowser::SortCompareName(int Index1, int Index2) const
{
CServerEntry *pIndex1 = m_ppServerlist[Index1];
CServerEntry *pIndex2 = m_ppServerlist[Index2];
// make sure empty entries are listed last
return (pIndex1->m_GotInfo && pIndex2->m_GotInfo) || (!pIndex1->m_GotInfo && !pIndex2->m_GotInfo) ? str_comp(pIndex1->m_Info.m_aName, pIndex2->m_Info.m_aName) < 0 :
pIndex1->m_GotInfo != 0;
2010-05-29 07:25:38 +00:00
}
bool CServerBrowser::SortCompareMap(int Index1, int Index2) const
{
CServerEntry *pIndex1 = m_ppServerlist[Index1];
CServerEntry *pIndex2 = m_ppServerlist[Index2];
return str_comp(pIndex1->m_Info.m_aMap, pIndex2->m_Info.m_aMap) < 0;
2010-05-29 07:25:38 +00:00
}
bool CServerBrowser::SortComparePing(int Index1, int Index2) const
{
CServerEntry *pIndex1 = m_ppServerlist[Index1];
CServerEntry *pIndex2 = m_ppServerlist[Index2];
return pIndex1->m_Info.m_Latency < pIndex2->m_Info.m_Latency;
2010-05-29 07:25:38 +00:00
}
bool CServerBrowser::SortCompareGametype(int Index1, int Index2) const
{
CServerEntry *pIndex1 = m_ppServerlist[Index1];
CServerEntry *pIndex2 = m_ppServerlist[Index2];
return str_comp(pIndex1->m_Info.m_aGameType, pIndex2->m_Info.m_aGameType) < 0;
2010-05-29 07:25:38 +00:00
}
bool CServerBrowser::SortCompareNumPlayers(int Index1, int Index2) const
{
CServerEntry *pIndex1 = m_ppServerlist[Index1];
CServerEntry *pIndex2 = m_ppServerlist[Index2];
return pIndex1->m_Info.m_NumFilteredPlayers > pIndex2->m_Info.m_NumFilteredPlayers;
2010-05-29 07:25:38 +00:00
}
bool CServerBrowser::SortCompareNumClients(int Index1, int Index2) const
{
CServerEntry *pIndex1 = m_ppServerlist[Index1];
CServerEntry *pIndex2 = m_ppServerlist[Index2];
return pIndex1->m_Info.m_NumClients > pIndex2->m_Info.m_NumClients;
}
bool CServerBrowser::SortCompareNumFriends(int Index1, int Index2) const
{
CServerEntry *pIndex1 = m_ppServerlist[Index1];
CServerEntry *pIndex2 = m_ppServerlist[Index2];
if(pIndex1->m_Info.m_FriendNum == pIndex2->m_Info.m_FriendNum)
return pIndex1->m_Info.m_NumFilteredPlayers > pIndex2->m_Info.m_NumFilteredPlayers;
else
return pIndex1->m_Info.m_FriendNum > pIndex2->m_Info.m_FriendNum;
}
bool CServerBrowser::SortCompareNumPlayersAndPing(int Index1, int Index2) const
{
CServerEntry *pIndex1 = m_ppServerlist[Index1];
CServerEntry *pIndex2 = m_ppServerlist[Index2];
if(pIndex1->m_Info.m_NumFilteredPlayers == pIndex2->m_Info.m_NumFilteredPlayers)
return pIndex1->m_Info.m_Latency > pIndex2->m_Info.m_Latency;
else if(pIndex1->m_Info.m_NumFilteredPlayers == 0 || pIndex2->m_Info.m_NumFilteredPlayers == 0 || pIndex1->m_Info.m_Latency / 100 == pIndex2->m_Info.m_Latency / 100)
return pIndex1->m_Info.m_NumFilteredPlayers < pIndex2->m_Info.m_NumFilteredPlayers;
else
return pIndex1->m_Info.m_Latency > pIndex2->m_Info.m_Latency;
}
2010-05-29 07:25:38 +00:00
void CServerBrowser::Filter()
{
m_NumSortedServers = 0;
m_NumSortedPlayers = 0;
2010-05-29 07:25:38 +00:00
// allocate the sorted list
if(m_NumSortedServersCapacity < m_NumServers)
{
free(m_pSortedServerlist);
2010-05-29 07:25:38 +00:00
m_NumSortedServersCapacity = m_NumServers;
m_pSortedServerlist = (int *)calloc(m_NumSortedServersCapacity, sizeof(int));
2010-05-29 07:25:38 +00:00
}
// filter the servers
for(int i = 0; i < m_NumServers; i++)
2010-05-29 07:25:38 +00:00
{
CServerInfo &Info = m_ppServerlist[i]->m_Info;
bool Filtered = false;
2010-05-29 07:25:38 +00:00
if(g_Config.m_BrFilterEmpty && Info.m_NumFilteredPlayers == 0)
Filtered = true;
else if(g_Config.m_BrFilterFull && Players(Info) == Max(Info))
Filtered = true;
else if(g_Config.m_BrFilterPw && Info.m_Flags & SERVER_FLAG_PASSWORD)
Filtered = true;
else if(g_Config.m_BrFilterServerAddress[0] && !str_find_nocase(Info.m_aAddress, g_Config.m_BrFilterServerAddress))
Filtered = true;
else if(g_Config.m_BrFilterGametypeStrict && g_Config.m_BrFilterGametype[0] && str_comp_nocase(Info.m_aGameType, g_Config.m_BrFilterGametype))
Filtered = true;
else if(!g_Config.m_BrFilterGametypeStrict && g_Config.m_BrFilterGametype[0] && !str_utf8_find_nocase(Info.m_aGameType, g_Config.m_BrFilterGametype))
Filtered = true;
else if(g_Config.m_BrFilterUnfinishedMap && Info.m_HasRank == CServerInfo::RANK_RANKED)
Filtered = true;
else
2011-06-26 15:10:13 +00:00
{
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
if(!Communities().empty())
{
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
if(m_ServerlistType == IServerBrowser::TYPE_INTERNET || m_ServerlistType == IServerBrowser::TYPE_FAVORITES)
{
Filtered = CommunitiesFilter().Filtered(Info.m_aCommunityId);
}
if(m_ServerlistType == IServerBrowser::TYPE_INTERNET || m_ServerlistType == IServerBrowser::TYPE_FAVORITES ||
(m_ServerlistType >= IServerBrowser::TYPE_FAVORITE_COMMUNITY_1 && m_ServerlistType <= IServerBrowser::TYPE_FAVORITE_COMMUNITY_3))
{
Filtered = Filtered || CountriesFilter().Filtered(Info.m_aCommunityCountry);
Filtered = Filtered || TypesFilter().Filtered(Info.m_aCommunityType);
}
}
if(!Filtered && g_Config.m_BrFilterCountry)
2011-06-26 15:10:13 +00:00
{
Filtered = true;
// match against player country
for(int p = 0; p < minimum(Info.m_NumClients, (int)MAX_CLIENTS); p++)
{
if(Info.m_aClients[p].m_Country == g_Config.m_BrFilterCountryIndex)
{
Filtered = false;
break;
}
}
2011-06-26 15:10:13 +00:00
}
if(!Filtered && g_Config.m_BrFilterString[0] != '\0')
2011-06-26 15:10:13 +00:00
{
Info.m_QuickSearchHit = 0;
const char *pStr = g_Config.m_BrFilterString;
char aFilterStr[sizeof(g_Config.m_BrFilterString)];
while((pStr = str_next_token(pStr, IServerBrowser::SEARCH_EXCLUDE_TOKEN, aFilterStr, sizeof(aFilterStr))))
2011-03-23 12:06:35 +00:00
{
if(aFilterStr[0] == '\0')
{
continue;
}
auto MatchesFn = matchesPart;
const int FilterLen = str_length(aFilterStr);
if(aFilterStr[0] == '"' && aFilterStr[FilterLen - 1] == '"')
{
aFilterStr[FilterLen - 1] = '\0';
MatchesFn = matchesExactly;
}
// match against server name
if(MatchesFn(Info.m_aName, aFilterStr))
{
Info.m_QuickSearchHit |= IServerBrowser::QUICK_SERVERNAME;
}
// match against players
for(int p = 0; p < minimum(Info.m_NumClients, (int)MAX_CLIENTS); p++)
{
if(MatchesFn(Info.m_aClients[p].m_aName, aFilterStr) ||
MatchesFn(Info.m_aClients[p].m_aClan, aFilterStr))
{
if(g_Config.m_BrFilterConnectingPlayers &&
str_comp(Info.m_aClients[p].m_aName, "(connecting)") == 0 &&
Info.m_aClients[p].m_aClan[0] == '\0')
{
continue;
}
Info.m_QuickSearchHit |= IServerBrowser::QUICK_PLAYER;
break;
}
}
// match against map
if(MatchesFn(Info.m_aMap, aFilterStr))
{
Info.m_QuickSearchHit |= IServerBrowser::QUICK_MAPNAME;
}
}
if(!Info.m_QuickSearchHit)
Filtered = true;
}
if(!Filtered && g_Config.m_BrExcludeString[0] != '\0')
{
const char *pStr = g_Config.m_BrExcludeString;
char aExcludeStr[sizeof(g_Config.m_BrExcludeString)];
while((pStr = str_next_token(pStr, IServerBrowser::SEARCH_EXCLUDE_TOKEN, aExcludeStr, sizeof(aExcludeStr))))
{
if(aExcludeStr[0] == '\0')
{
continue;
}
auto MatchesFn = matchesPart;
const int FilterLen = str_length(aExcludeStr);
if(aExcludeStr[0] == '"' && aExcludeStr[FilterLen - 1] == '"')
{
aExcludeStr[FilterLen - 1] = '\0';
MatchesFn = matchesExactly;
}
// match against server name
if(MatchesFn(Info.m_aName, aExcludeStr))
{
Filtered = true;
break;
}
2019-03-05 09:46:29 +00:00
// match against map
if(MatchesFn(Info.m_aMap, aExcludeStr))
{
Filtered = true;
break;
}
// match against gametype
if(MatchesFn(Info.m_aGameType, aExcludeStr))
{
Filtered = true;
break;
}
}
}
2010-05-29 07:25:38 +00:00
}
if(!Filtered)
2011-06-26 15:10:13 +00:00
{
UpdateServerFriends(&Info);
2011-06-26 15:10:13 +00:00
if(!g_Config.m_BrFilterFriends || Info.m_FriendState != IFriends::FRIEND_NO)
{
m_NumSortedPlayers += Info.m_NumFilteredPlayers;
2011-06-26 15:10:13 +00:00
m_pSortedServerlist[m_NumSortedServers++] = i;
}
2011-06-26 15:10:13 +00:00
}
2010-05-29 07:25:38 +00:00
}
}
int CServerBrowser::SortHash() const
{
2020-09-26 19:33:36 +00:00
int i = g_Config.m_BrSort & 0xff;
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_BrFilterGametypeStrict << 12;
i |= g_Config.m_BrFilterUnfinishedMap << 13;
i |= g_Config.m_BrFilterCountry << 14;
i |= g_Config.m_BrFilterConnectingPlayers << 15;
2010-05-29 07:25:38 +00:00
return i;
}
void CServerBrowser::Sort()
{
// update number of filtered players
for(int i = 0; i < m_NumServers; i++)
2018-10-29 21:03:57 +00:00
{
UpdateServerFilteredPlayers(&m_ppServerlist[i]->m_Info);
2018-10-29 21:03:57 +00:00
}
2010-05-29 07:25:38 +00:00
// create filtered list
Filter();
// sort
if(g_Config.m_BrSortOrder == 2 && (g_Config.m_BrSort == IServerBrowser::SORT_NUMPLAYERS || g_Config.m_BrSort == IServerBrowser::SORT_PING))
2022-12-05 21:16:01 +00:00
std::stable_sort(m_pSortedServerlist, m_pSortedServerlist + m_NumSortedServers, CSortWrap(this, &CServerBrowser::SortCompareNumPlayersAndPing));
else if(g_Config.m_BrSort == IServerBrowser::SORT_NAME)
2022-12-05 21:16:01 +00:00
std::stable_sort(m_pSortedServerlist, m_pSortedServerlist + m_NumSortedServers, CSortWrap(this, &CServerBrowser::SortCompareName));
2010-05-29 07:25:38 +00:00
else if(g_Config.m_BrSort == IServerBrowser::SORT_PING)
2022-12-05 21:16:01 +00:00
std::stable_sort(m_pSortedServerlist, m_pSortedServerlist + m_NumSortedServers, CSortWrap(this, &CServerBrowser::SortComparePing));
2010-05-29 07:25:38 +00:00
else if(g_Config.m_BrSort == IServerBrowser::SORT_MAP)
2022-12-05 21:16:01 +00:00
std::stable_sort(m_pSortedServerlist, m_pSortedServerlist + m_NumSortedServers, CSortWrap(this, &CServerBrowser::SortCompareMap));
else if(g_Config.m_BrSort == IServerBrowser::SORT_NUMFRIENDS)
std::stable_sort(m_pSortedServerlist, m_pSortedServerlist + m_NumSortedServers, CSortWrap(this, &CServerBrowser::SortCompareNumFriends));
2010-05-29 07:25:38 +00:00
else if(g_Config.m_BrSort == IServerBrowser::SORT_NUMPLAYERS)
2022-12-05 21:16:01 +00:00
std::stable_sort(m_pSortedServerlist, m_pSortedServerlist + m_NumSortedServers, CSortWrap(this, &CServerBrowser::SortCompareNumPlayers));
2010-05-29 07:25:38 +00:00
else if(g_Config.m_BrSort == IServerBrowser::SORT_GAMETYPE)
2022-12-05 21:16:01 +00:00
std::stable_sort(m_pSortedServerlist, m_pSortedServerlist + m_NumSortedServers, CSortWrap(this, &CServerBrowser::SortCompareGametype));
2010-05-29 07:25:38 +00:00
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 = nullptr;
pEntry->m_pNextReq = nullptr;
2010-05-29 07:25:38 +00:00
m_NumRequests--;
}
}
CServerBrowser::CServerEntry *CServerBrowser::Find(const NETADDR &Addr)
{
auto Entry = m_ByAddr.find(Addr);
if(Entry == m_ByAddr.end())
2010-05-29 07:25:38 +00:00
{
return nullptr;
2010-05-29 07:25:38 +00:00
}
return m_ppServerlist[Entry->second];
2010-05-29 07:25:38 +00:00
}
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;
pEntry->m_pNextReq = nullptr;
2010-05-29 07:25:38 +00:00
m_NumRequests++;
}
void ServerBrowserFormatAddresses(char *pBuffer, int BufferSize, NETADDR *pAddrs, int NumAddrs)
{
for(int i = 0; i < NumAddrs; i++)
{
if(i != 0)
{
if(BufferSize <= 1)
{
return;
}
pBuffer[0] = ',';
pBuffer[1] = '\0';
pBuffer += 1;
BufferSize -= 1;
}
if(BufferSize <= 1)
{
return;
}
net_addr_str(&pAddrs[i], pBuffer, BufferSize, true);
int Length = str_length(pBuffer);
pBuffer += Length;
BufferSize -= Length;
}
}
void CServerBrowser::SetInfo(CServerEntry *pEntry, const CServerInfo &Info) const
2010-05-29 07:25:38 +00:00
{
const CServerInfo TmpInfo = pEntry->m_Info;
2010-05-29 07:25:38 +00:00
pEntry->m_Info = Info;
pEntry->m_Info.m_Favorite = TmpInfo.m_Favorite;
pEntry->m_Info.m_FavoriteAllowPing = TmpInfo.m_FavoriteAllowPing;
mem_copy(pEntry->m_Info.m_aAddresses, TmpInfo.m_aAddresses, sizeof(pEntry->m_Info.m_aAddresses));
pEntry->m_Info.m_NumAddresses = TmpInfo.m_NumAddresses;
ServerBrowserFormatAddresses(pEntry->m_Info.m_aAddress, sizeof(pEntry->m_Info.m_aAddress), pEntry->m_Info.m_aAddresses, pEntry->m_Info.m_NumAddresses);
str_copy(pEntry->m_Info.m_aCommunityId, TmpInfo.m_aCommunityId);
str_copy(pEntry->m_Info.m_aCommunityCountry, TmpInfo.m_aCommunityCountry);
str_copy(pEntry->m_Info.m_aCommunityType, TmpInfo.m_aCommunityType);
UpdateServerRank(&pEntry->m_Info);
2010-05-29 07:25:38 +00:00
if(pEntry->m_Info.m_ClientScoreKind == CServerInfo::CLIENT_SCORE_KIND_UNSPECIFIED)
{
if((str_find_nocase(pEntry->m_Info.m_aGameType, "race") || str_find_nocase(pEntry->m_Info.m_aGameType, "fastcap")) && g_Config.m_ClDDRaceScoreBoard)
{
pEntry->m_Info.m_ClientScoreKind = CServerInfo::CLIENT_SCORE_KIND_TIME_BACKCOMPAT;
}
else
{
pEntry->m_Info.m_ClientScoreKind = CServerInfo::CLIENT_SCORE_KIND_POINTS;
}
}
class CPlayerScoreNameLess
{
const int ScoreKind;
2023-05-22 11:00:06 +00:00
public:
2023-05-22 11:00:06 +00:00
CPlayerScoreNameLess(int ClientScoreKind) :
ScoreKind(ClientScoreKind)
{
}
bool operator()(const CServerInfo::CClient &p0, const CServerInfo::CClient &p1) const
{
// Sort players before non players
if(p0.m_Player && !p1.m_Player)
return true;
if(!p0.m_Player && p1.m_Player)
return false;
int Score0 = p0.m_Score;
int Score1 = p1.m_Score;
2023-05-22 11:00:06 +00:00
if(ScoreKind == CServerInfo::CLIENT_SCORE_KIND_TIME || ScoreKind == CServerInfo::CLIENT_SCORE_KIND_TIME_BACKCOMPAT)
2023-05-22 11:00:06 +00:00
{
// Sort unfinished (-9999) and still connecting players (-1) after others
if(Score0 < 0 && Score1 >= 0)
return false;
if(Score0 >= 0 && Score1 < 0)
return true;
2023-05-22 11:00:06 +00:00
}
if(Score0 != Score1)
{
// Handle the sign change introduced with CLIENT_SCORE_KIND_TIME
if(ScoreKind == CServerInfo::CLIENT_SCORE_KIND_TIME)
return Score0 < Score1;
else
return Score0 > Score1;
}
2023-05-22 11:00:06 +00:00
return str_comp_nocase(p0.m_aName, p1.m_aName) < 0;
}
};
2023-05-22 11:00:06 +00:00
std::sort(pEntry->m_Info.m_aClients, pEntry->m_Info.m_aClients + Info.m_NumReceivedClients, CPlayerScoreNameLess(pEntry->m_Info.m_ClientScoreKind));
2010-05-29 07:25:38 +00:00
pEntry->m_GotInfo = 1;
}
void CServerBrowser::SetLatency(NETADDR Addr, int Latency)
{
m_pPingCache->CachePing(Addr, Latency);
Addr.port = 0;
for(int i = 0; i < m_NumServers; i++)
{
if(!m_ppServerlist[i]->m_GotInfo)
{
continue;
}
bool Found = false;
for(int j = 0; j < m_ppServerlist[i]->m_Info.m_NumAddresses; j++)
{
NETADDR Other = m_ppServerlist[i]->m_Info.m_aAddresses[j];
Other.port = 0;
if(Addr == Other)
{
Found = true;
break;
}
}
if(!Found)
{
continue;
}
int Ping = m_pPingCache->GetPing(m_ppServerlist[i]->m_Info.m_aAddresses, m_ppServerlist[i]->m_Info.m_NumAddresses);
if(Ping == -1)
{
continue;
}
m_ppServerlist[i]->m_Info.m_Latency = Ping;
m_ppServerlist[i]->m_Info.m_LatencyIsEstimated = false;
}
}
CServerBrowser::CServerEntry *CServerBrowser::Add(const NETADDR *pAddrs, int NumAddrs)
2010-05-29 07:25:38 +00:00
{
// create new pEntry
CServerEntry *pEntry = m_ServerlistHeap.Allocate<CServerEntry>();
2010-05-29 07:25:38 +00:00
mem_zero(pEntry, sizeof(CServerEntry));
// set the info
mem_copy(pEntry->m_Info.m_aAddresses, pAddrs, NumAddrs * sizeof(pAddrs[0]));
pEntry->m_Info.m_NumAddresses = NumAddrs;
2010-05-29 07:25:38 +00:00
pEntry->m_Info.m_Latency = 999;
pEntry->m_Info.m_HasRank = CServerInfo::RANK_UNAVAILABLE;
ServerBrowserFormatAddresses(pEntry->m_Info.m_aAddress, sizeof(pEntry->m_Info.m_aAddress), pEntry->m_Info.m_aAddresses, pEntry->m_Info.m_NumAddresses);
UpdateServerCommunity(&pEntry->m_Info);
str_copy(pEntry->m_Info.m_aName, pEntry->m_Info.m_aAddress, sizeof(pEntry->m_Info.m_aName));
2010-05-29 07:25:38 +00:00
// check if it's a favorite
pEntry->m_Info.m_Favorite = m_pFavorites->IsFavorite(pEntry->m_Info.m_aAddresses, pEntry->m_Info.m_NumAddresses);
pEntry->m_Info.m_FavoriteAllowPing = m_pFavorites->IsPingAllowed(pEntry->m_Info.m_aAddresses, pEntry->m_Info.m_NumAddresses);
for(int i = 0; i < NumAddrs; i++)
{
m_ByAddr[pAddrs[i]] = m_NumServers;
}
2010-05-29 07:25:38 +00:00
if(m_NumServers == m_NumServerCapacity)
{
CServerEntry **ppNewlist;
m_NumServerCapacity += 100;
ppNewlist = (CServerEntry **)calloc(m_NumServerCapacity, sizeof(CServerEntry *)); // NOLINT(bugprone-sizeof-expression)
if(m_NumServers > 0)
mem_copy(ppNewlist, m_ppServerlist, m_NumServers * sizeof(CServerEntry *)); // NOLINT(bugprone-sizeof-expression)
free(m_ppServerlist);
2010-05-29 07:25:38 +00:00
m_ppServerlist = ppNewlist;
}
// add to list
m_ppServerlist[m_NumServers] = pEntry;
pEntry->m_Info.m_ServerIndex = m_NumServers;
m_NumServers++;
return pEntry;
}
void CServerBrowser::OnServerInfoUpdate(const NETADDR &Addr, int Token, const CServerInfo *pInfo)
2010-05-29 07:25:38 +00:00
{
int BasicToken = Token;
int ExtraToken = 0;
if(pInfo->m_Type == SERVERINFO_EXTENDED)
2010-05-29 07:25:38 +00:00
{
BasicToken = Token & 0xff;
ExtraToken = Token >> 8;
2010-05-29 07:25:38 +00:00
}
CServerEntry *pEntry = Find(Addr);
2014-09-13 14:36:25 +00:00
if(m_ServerlistType == IServerBrowser::TYPE_LAN)
{
NETADDR Broadcast;
mem_zero(&Broadcast, sizeof(Broadcast));
Broadcast.type = m_pNetClient->NetType() | NETTYPE_LINK_BROADCAST;
int TokenBC = GenerateToken(Broadcast);
bool Drop = false;
Drop = Drop || BasicToken != GetBasicToken(TokenBC);
Drop = Drop || (pInfo->m_Type == SERVERINFO_EXTENDED && ExtraToken != GetExtraToken(TokenBC));
if(Drop)
2014-09-13 14:36:25 +00:00
{
return;
2014-09-13 14:36:25 +00:00
}
if(!pEntry)
pEntry = Add(&Addr, 1);
2014-09-13 14:36:25 +00:00
}
else
{
if(!pEntry)
{
return;
}
int TokenAddr = GenerateToken(Addr);
bool Drop = false;
Drop = Drop || BasicToken != GetBasicToken(TokenAddr);
Drop = Drop || (pInfo->m_Type == SERVERINFO_EXTENDED && ExtraToken != GetExtraToken(TokenAddr));
if(Drop)
{
return;
}
}
if(m_ServerlistType == IServerBrowser::TYPE_LAN)
Add client-side HTTP server info Summary ======= The idea of this is that clients will not have to ping each server for server infos which takes long, leaks the client's IP address even to servers the user does not join and is a DoS vector of the game servers for attackers. For the Internet, DDNet and KoG tab, the server list is entirely fetched from the master server, filtering out servers that don't belong into the list. The favorites tab is also supposed to work that way, except for servers that are marked as "also ping this server if it's not in the master server list". The LAN tab continues to broadcast the server info packet to find servers in the LAN. How does it work? ================= The client ships with a list of master server list URLs. On first start, the client checks which of these work and selects the fastest one. Querying the server list is a HTTP GET request on that URL. The response is a JSON document that contains server infos, server addresses as URLs and an approximate location. It can also contain a legacy server list which is a list of bare IP addresses similar to the functionality the old master servers provided via UDP. This allows us to backtrack on the larger update if it won't work out. Lost functionality ================== (also known as user-visible changes) Since the client doesn't ping each server in the list anymore, it has no way of knowing its latency to the servers. This is alleviated a bit by providing an approximate location for each server (continent) so the client only has to know its own location for approximating pings.
2018-07-11 20:46:04 +00:00
{
SetInfo(pEntry, *pInfo);
pEntry->m_Info.m_Latency = minimum(static_cast<int>((time_get() - m_BroadcastTime) * 1000 / time_freq()), 999);
Add client-side HTTP server info Summary ======= The idea of this is that clients will not have to ping each server for server infos which takes long, leaks the client's IP address even to servers the user does not join and is a DoS vector of the game servers for attackers. For the Internet, DDNet and KoG tab, the server list is entirely fetched from the master server, filtering out servers that don't belong into the list. The favorites tab is also supposed to work that way, except for servers that are marked as "also ping this server if it's not in the master server list". The LAN tab continues to broadcast the server info packet to find servers in the LAN. How does it work? ================= The client ships with a list of master server list URLs. On first start, the client checks which of these work and selects the fastest one. Querying the server list is a HTTP GET request on that URL. The response is a JSON document that contains server infos, server addresses as URLs and an approximate location. It can also contain a legacy server list which is a list of bare IP addresses similar to the functionality the old master servers provided via UDP. This allows us to backtrack on the larger update if it won't work out. Lost functionality ================== (also known as user-visible changes) Since the client doesn't ping each server in the list anymore, it has no way of knowing its latency to the servers. This is alleviated a bit by providing an approximate location for each server (continent) so the client only has to know its own location for approximating pings.
2018-07-11 20:46:04 +00:00
}
else if(pEntry->m_RequestTime > 0)
2010-05-29 07:25:38 +00:00
{
if(!pEntry->m_RequestIgnoreInfo)
{
SetInfo(pEntry, *pInfo);
}
int Latency = minimum(static_cast<int>((time_get() - pEntry->m_RequestTime) * 1000 / time_freq()), 999);
if(!pEntry->m_RequestIgnoreInfo)
{
pEntry->m_Info.m_Latency = Latency;
}
else
{
char aAddr[NETADDR_MAXSTRSIZE];
net_addr_str(&Addr, aAddr, sizeof(aAddr), true);
dbg_msg("serverbrowser", "received ping response from %s", aAddr);
SetLatency(Addr, Latency);
}
pEntry->m_RequestTime = -1; // Request has been answered
2010-05-29 07:25:38 +00:00
}
RemoveRequest(pEntry);
RequestResort();
2010-05-29 07:25:38 +00:00
}
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
void CServerBrowser::Refresh(int Type, bool Force)
2010-05-29 07:25:38 +00:00
{
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
bool ServerListTypeChanged = Force || m_ServerlistType != Type;
2021-07-08 17:18:01 +00:00
int OldServerListType = m_ServerlistType;
2010-05-29 07:25:38 +00:00
m_ServerlistType = Type;
2020-09-03 00:03:22 +00:00
secure_random_fill(m_aTokenSeed, sizeof(m_aTokenSeed));
2010-05-29 07:25:38 +00:00
2021-07-08 17:18:01 +00:00
if(Type == IServerBrowser::TYPE_LAN || (ServerListTypeChanged && OldServerListType == IServerBrowser::TYPE_LAN))
CleanUp();
2010-05-29 07:25:38 +00:00
if(Type == IServerBrowser::TYPE_LAN)
{
unsigned char aBuffer[sizeof(SERVERBROWSE_GETINFO) + 1];
2010-05-29 07:25:38 +00:00
CNetChunk Packet;
/* do the broadcast version */
2010-05-29 07:25:38 +00:00
Packet.m_ClientID = -1;
mem_zero(&Packet, sizeof(Packet));
Packet.m_Address.type = m_pNetClient->NetType() | NETTYPE_LINK_BROADCAST;
Packet.m_Flags = NETSENDFLAG_CONNLESS | NETSENDFLAG_EXTENDED;
Packet.m_DataSize = sizeof(aBuffer);
Packet.m_pData = aBuffer;
mem_zero(&Packet.m_aExtraData, sizeof(Packet.m_aExtraData));
int Token = GenerateToken(Packet.m_Address);
mem_copy(aBuffer, SERVERBROWSE_GETINFO, sizeof(SERVERBROWSE_GETINFO));
aBuffer[sizeof(SERVERBROWSE_GETINFO)] = GetBasicToken(Token);
Packet.m_aExtraData[0] = GetExtraToken(Token) >> 8;
Packet.m_aExtraData[1] = GetExtraToken(Token) & 0xff;
2010-05-29 07:25:38 +00:00
m_BroadcastTime = time_get();
for(int i = 8303; i <= 8310; i++)
2010-05-29 07:25:38 +00:00
{
Packet.m_Address.port = i;
m_pNetClient->Send(&Packet);
}
if(g_Config.m_Debug)
m_pConsole->Print(IConsole::OUTPUT_LEVEL_DEBUG, "serverbrowser", "broadcasting for servers");
2010-05-29 07:25:38 +00:00
}
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
else
{
Add client-side HTTP server info Summary ======= The idea of this is that clients will not have to ping each server for server infos which takes long, leaks the client's IP address even to servers the user does not join and is a DoS vector of the game servers for attackers. For the Internet, DDNet and KoG tab, the server list is entirely fetched from the master server, filtering out servers that don't belong into the list. The favorites tab is also supposed to work that way, except for servers that are marked as "also ping this server if it's not in the master server list". The LAN tab continues to broadcast the server info packet to find servers in the LAN. How does it work? ================= The client ships with a list of master server list URLs. On first start, the client checks which of these work and selects the fastest one. Querying the server list is a HTTP GET request on that URL. The response is a JSON document that contains server infos, server addresses as URLs and an approximate location. It can also contain a legacy server list which is a list of bare IP addresses similar to the functionality the old master servers provided via UDP. This allows us to backtrack on the larger update if it won't work out. Lost functionality ================== (also known as user-visible changes) Since the client doesn't ping each server in the list anymore, it has no way of knowing its latency to the servers. This is alleviated a bit by providing an approximate location for each server (continent) so the client only has to know its own location for approximating pings.
2018-07-11 20:46:04 +00:00
m_pHttp->Refresh();
m_pPingCache->Load();
Add client-side HTTP server info Summary ======= The idea of this is that clients will not have to ping each server for server infos which takes long, leaks the client's IP address even to servers the user does not join and is a DoS vector of the game servers for attackers. For the Internet, DDNet and KoG tab, the server list is entirely fetched from the master server, filtering out servers that don't belong into the list. The favorites tab is also supposed to work that way, except for servers that are marked as "also ping this server if it's not in the master server list". The LAN tab continues to broadcast the server info packet to find servers in the LAN. How does it work? ================= The client ships with a list of master server list URLs. On first start, the client checks which of these work and selects the fastest one. Querying the server list is a HTTP GET request on that URL. The response is a JSON document that contains server infos, server addresses as URLs and an approximate location. It can also contain a legacy server list which is a list of bare IP addresses similar to the functionality the old master servers provided via UDP. This allows us to backtrack on the larger update if it won't work out. Lost functionality ================== (also known as user-visible changes) Since the client doesn't ping each server in the list anymore, it has no way of knowing its latency to the servers. This is alleviated a bit by providing an approximate location for each server (continent) so the client only has to know its own location for approximating pings.
2018-07-11 20:46:04 +00:00
m_RefreshingHttp = true;
2021-07-08 17:18:01 +00:00
if(ServerListTypeChanged && m_pHttp->NumServers() > 0)
{
CleanUp();
UpdateFromHttp();
Sort();
}
}
2010-05-29 07:25:38 +00:00
}
void CServerBrowser::RequestImpl(const NETADDR &Addr, CServerEntry *pEntry, int *pBasicToken, int *pToken, bool RandomToken) const
2010-05-29 07:25:38 +00:00
{
if(g_Config.m_Debug)
{
char aAddrStr[NETADDR_MAXSTRSIZE];
2011-12-29 22:36:53 +00:00
net_addr_str(&Addr, aAddrStr, sizeof(aAddrStr), true);
char aBuf[256];
str_format(aBuf, sizeof(aBuf), "requesting server info from %s", aAddrStr);
m_pConsole->Print(IConsole::OUTPUT_LEVEL_DEBUG, "serverbrowser", aBuf);
2010-05-29 07:25:38 +00:00
}
int Token = GenerateToken(Addr);
if(RandomToken)
{
int AvoidBasicToken = GetBasicToken(Token);
do
{
secure_random_fill(&Token, sizeof(Token));
Token &= 0xffffff;
} while(GetBasicToken(Token) == AvoidBasicToken);
}
if(pToken)
{
*pToken = Token;
}
if(pBasicToken)
{
*pBasicToken = GetBasicToken(Token);
}
unsigned char aBuffer[sizeof(SERVERBROWSE_GETINFO) + 1];
mem_copy(aBuffer, SERVERBROWSE_GETINFO, sizeof(SERVERBROWSE_GETINFO));
aBuffer[sizeof(SERVERBROWSE_GETINFO)] = GetBasicToken(Token);
2010-05-29 07:25:38 +00:00
CNetChunk Packet;
2010-05-29 07:25:38 +00:00
Packet.m_ClientID = -1;
Packet.m_Address = Addr;
Packet.m_Flags = NETSENDFLAG_CONNLESS | NETSENDFLAG_EXTENDED;
Packet.m_DataSize = sizeof(aBuffer);
Packet.m_pData = aBuffer;
mem_zero(&Packet.m_aExtraData, sizeof(Packet.m_aExtraData));
Packet.m_aExtraData[0] = GetExtraToken(Token) >> 8;
Packet.m_aExtraData[1] = GetExtraToken(Token) & 0xff;
2010-05-29 07:25:38 +00:00
m_pNetClient->Send(&Packet);
if(pEntry)
pEntry->m_RequestTime = time_get();
}
void CServerBrowser::RequestCurrentServer(const NETADDR &Addr) const
{
RequestImpl(Addr, nullptr, nullptr, nullptr, false);
}
void CServerBrowser::RequestCurrentServerWithRandomToken(const NETADDR &Addr, int *pBasicToken, int *pToken) const
{
RequestImpl(Addr, nullptr, pBasicToken, pToken, true);
}
void CServerBrowser::SetCurrentServerPing(const NETADDR &Addr, int Ping)
2010-05-29 07:25:38 +00:00
{
2021-08-20 15:16:18 +00:00
SetLatency(Addr, minimum(Ping, 999));
2010-05-29 07:25:38 +00:00
}
Add client-side HTTP server info Summary ======= The idea of this is that clients will not have to ping each server for server infos which takes long, leaks the client's IP address even to servers the user does not join and is a DoS vector of the game servers for attackers. For the Internet, DDNet and KoG tab, the server list is entirely fetched from the master server, filtering out servers that don't belong into the list. The favorites tab is also supposed to work that way, except for servers that are marked as "also ping this server if it's not in the master server list". The LAN tab continues to broadcast the server info packet to find servers in the LAN. How does it work? ================= The client ships with a list of master server list URLs. On first start, the client checks which of these work and selects the fastest one. Querying the server list is a HTTP GET request on that URL. The response is a JSON document that contains server infos, server addresses as URLs and an approximate location. It can also contain a legacy server list which is a list of bare IP addresses similar to the functionality the old master servers provided via UDP. This allows us to backtrack on the larger update if it won't work out. Lost functionality ================== (also known as user-visible changes) Since the client doesn't ping each server in the list anymore, it has no way of knowing its latency to the servers. This is alleviated a bit by providing an approximate location for each server (continent) so the client only has to know its own location for approximating pings.
2018-07-11 20:46:04 +00:00
void CServerBrowser::UpdateFromHttp()
2015-07-09 00:08:14 +00:00
{
int OwnLocation;
if(str_comp(g_Config.m_BrLocation, "auto") == 0)
{
OwnLocation = m_OwnLocation;
}
else
{
if(CServerInfo::ParseLocation(&OwnLocation, g_Config.m_BrLocation))
{
char aBuf[64];
str_format(aBuf, sizeof(aBuf), "cannot parse br_location: '%s'", g_Config.m_BrLocation);
m_pConsole->Print(IConsole::OUTPUT_LEVEL_STANDARD, "serverbrowser", aBuf);
}
}
Add client-side HTTP server info Summary ======= The idea of this is that clients will not have to ping each server for server infos which takes long, leaks the client's IP address even to servers the user does not join and is a DoS vector of the game servers for attackers. For the Internet, DDNet and KoG tab, the server list is entirely fetched from the master server, filtering out servers that don't belong into the list. The favorites tab is also supposed to work that way, except for servers that are marked as "also ping this server if it's not in the master server list". The LAN tab continues to broadcast the server info packet to find servers in the LAN. How does it work? ================= The client ships with a list of master server list URLs. On first start, the client checks which of these work and selects the fastest one. Querying the server list is a HTTP GET request on that URL. The response is a JSON document that contains server infos, server addresses as URLs and an approximate location. It can also contain a legacy server list which is a list of bare IP addresses similar to the functionality the old master servers provided via UDP. This allows us to backtrack on the larger update if it won't work out. Lost functionality ================== (also known as user-visible changes) Since the client doesn't ping each server in the list anymore, it has no way of knowing its latency to the servers. This is alleviated a bit by providing an approximate location for each server (continent) so the client only has to know its own location for approximating pings.
2018-07-11 20:46:04 +00:00
int NumServers = m_pHttp->NumServers();
int NumLegacyServers = m_pHttp->NumLegacyServers();
std::function<bool(const NETADDR *, int)> Want = [](const NETADDR *pAddrs, int NumAddrs) { return true; };
if(m_ServerlistType == IServerBrowser::TYPE_FAVORITES)
2010-05-29 07:25:38 +00:00
{
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
Want = [this](const NETADDR *pAddrs, int NumAddrs) -> bool {
return m_pFavorites->IsFavorite(pAddrs, NumAddrs) != TRISTATE::NONE;
};
}
else if(m_ServerlistType >= IServerBrowser::TYPE_FAVORITE_COMMUNITY_1 && m_ServerlistType <= IServerBrowser::TYPE_FAVORITE_COMMUNITY_3)
{
const size_t CommunityIndex = m_ServerlistType - IServerBrowser::TYPE_FAVORITE_COMMUNITY_1;
std::vector<const CCommunity *> vpFavoriteCommunities = FavoriteCommunities();
dbg_assert(CommunityIndex < vpFavoriteCommunities.size(), "Invalid community index");
const CCommunity *pWantedCommunity = vpFavoriteCommunities[CommunityIndex];
const bool IsNoneCommunity = str_comp(pWantedCommunity->Id(), COMMUNITY_NONE) == 0;
Want = [this, pWantedCommunity, IsNoneCommunity](const NETADDR *pAddrs, int NumAddrs) -> bool {
for(int AddressIndex = 0; AddressIndex < NumAddrs; AddressIndex++)
{
const auto CommunityServer = m_CommunityServersByAddr.find(pAddrs[AddressIndex]);
if(CommunityServer != m_CommunityServersByAddr.end())
{
if(IsNoneCommunity)
{
// Servers with community "none" are not present in m_CommunityServersByAddr, so we ignore
// any server that is found in this map to determine only the servers without community.
return false;
}
else if(str_comp(CommunityServer->second.CommunityId(), pWantedCommunity->Id()) == 0)
{
return true;
}
}
}
return IsNoneCommunity;
};
}
for(int i = 0; i < NumServers; i++)
{
CServerInfo Info = m_pHttp->Server(i);
if(!Want(Info.m_aAddresses, Info.m_NumAddresses))
{
continue;
}
int Ping = m_pPingCache->GetPing(Info.m_aAddresses, Info.m_NumAddresses);
Info.m_LatencyIsEstimated = Ping == -1;
if(Info.m_LatencyIsEstimated)
Add client-side HTTP server info Summary ======= The idea of this is that clients will not have to ping each server for server infos which takes long, leaks the client's IP address even to servers the user does not join and is a DoS vector of the game servers for attackers. For the Internet, DDNet and KoG tab, the server list is entirely fetched from the master server, filtering out servers that don't belong into the list. The favorites tab is also supposed to work that way, except for servers that are marked as "also ping this server if it's not in the master server list". The LAN tab continues to broadcast the server info packet to find servers in the LAN. How does it work? ================= The client ships with a list of master server list URLs. On first start, the client checks which of these work and selects the fastest one. Querying the server list is a HTTP GET request on that URL. The response is a JSON document that contains server infos, server addresses as URLs and an approximate location. It can also contain a legacy server list which is a list of bare IP addresses similar to the functionality the old master servers provided via UDP. This allows us to backtrack on the larger update if it won't work out. Lost functionality ================== (also known as user-visible changes) Since the client doesn't ping each server in the list anymore, it has no way of knowing its latency to the servers. This is alleviated a bit by providing an approximate location for each server (continent) so the client only has to know its own location for approximating pings.
2018-07-11 20:46:04 +00:00
{
Info.m_Latency = CServerInfo::EstimateLatency(OwnLocation, Info.m_Location);
Add client-side HTTP server info Summary ======= The idea of this is that clients will not have to ping each server for server infos which takes long, leaks the client's IP address even to servers the user does not join and is a DoS vector of the game servers for attackers. For the Internet, DDNet and KoG tab, the server list is entirely fetched from the master server, filtering out servers that don't belong into the list. The favorites tab is also supposed to work that way, except for servers that are marked as "also ping this server if it's not in the master server list". The LAN tab continues to broadcast the server info packet to find servers in the LAN. How does it work? ================= The client ships with a list of master server list URLs. On first start, the client checks which of these work and selects the fastest one. Querying the server list is a HTTP GET request on that URL. The response is a JSON document that contains server infos, server addresses as URLs and an approximate location. It can also contain a legacy server list which is a list of bare IP addresses similar to the functionality the old master servers provided via UDP. This allows us to backtrack on the larger update if it won't work out. Lost functionality ================== (also known as user-visible changes) Since the client doesn't ping each server in the list anymore, it has no way of knowing its latency to the servers. This is alleviated a bit by providing an approximate location for each server (continent) so the client only has to know its own location for approximating pings.
2018-07-11 20:46:04 +00:00
}
else
Add client-side HTTP server info Summary ======= The idea of this is that clients will not have to ping each server for server infos which takes long, leaks the client's IP address even to servers the user does not join and is a DoS vector of the game servers for attackers. For the Internet, DDNet and KoG tab, the server list is entirely fetched from the master server, filtering out servers that don't belong into the list. The favorites tab is also supposed to work that way, except for servers that are marked as "also ping this server if it's not in the master server list". The LAN tab continues to broadcast the server info packet to find servers in the LAN. How does it work? ================= The client ships with a list of master server list URLs. On first start, the client checks which of these work and selects the fastest one. Querying the server list is a HTTP GET request on that URL. The response is a JSON document that contains server infos, server addresses as URLs and an approximate location. It can also contain a legacy server list which is a list of bare IP addresses similar to the functionality the old master servers provided via UDP. This allows us to backtrack on the larger update if it won't work out. Lost functionality ================== (also known as user-visible changes) Since the client doesn't ping each server in the list anymore, it has no way of knowing its latency to the servers. This is alleviated a bit by providing an approximate location for each server (continent) so the client only has to know its own location for approximating pings.
2018-07-11 20:46:04 +00:00
{
Info.m_Latency = Ping;
}
CServerEntry *pEntry = Add(Info.m_aAddresses, Info.m_NumAddresses);
SetInfo(pEntry, Info);
pEntry->m_RequestIgnoreInfo = true;
}
for(int i = 0; i < NumLegacyServers; i++)
{
NETADDR Addr = m_pHttp->LegacyServer(i);
if(!Want(&Addr, 1))
{
continue;
}
QueueRequest(Add(&Addr, 1));
}
Add client-side HTTP server info Summary ======= The idea of this is that clients will not have to ping each server for server infos which takes long, leaks the client's IP address even to servers the user does not join and is a DoS vector of the game servers for attackers. For the Internet, DDNet and KoG tab, the server list is entirely fetched from the master server, filtering out servers that don't belong into the list. The favorites tab is also supposed to work that way, except for servers that are marked as "also ping this server if it's not in the master server list". The LAN tab continues to broadcast the server info packet to find servers in the LAN. How does it work? ================= The client ships with a list of master server list URLs. On first start, the client checks which of these work and selects the fastest one. Querying the server list is a HTTP GET request on that URL. The response is a JSON document that contains server infos, server addresses as URLs and an approximate location. It can also contain a legacy server list which is a list of bare IP addresses similar to the functionality the old master servers provided via UDP. This allows us to backtrack on the larger update if it won't work out. Lost functionality ================== (also known as user-visible changes) Since the client doesn't ping each server in the list anymore, it has no way of knowing its latency to the servers. This is alleviated a bit by providing an approximate location for each server (continent) so the client only has to know its own location for approximating pings.
2018-07-11 20:46:04 +00:00
if(m_ServerlistType == IServerBrowser::TYPE_FAVORITES)
{
const IFavorites::CEntry *pFavorites;
int NumFavorites;
m_pFavorites->AllEntries(&pFavorites, &NumFavorites);
for(int i = 0; i < NumFavorites; i++)
Add client-side HTTP server info Summary ======= The idea of this is that clients will not have to ping each server for server infos which takes long, leaks the client's IP address even to servers the user does not join and is a DoS vector of the game servers for attackers. For the Internet, DDNet and KoG tab, the server list is entirely fetched from the master server, filtering out servers that don't belong into the list. The favorites tab is also supposed to work that way, except for servers that are marked as "also ping this server if it's not in the master server list". The LAN tab continues to broadcast the server info packet to find servers in the LAN. How does it work? ================= The client ships with a list of master server list URLs. On first start, the client checks which of these work and selects the fastest one. Querying the server list is a HTTP GET request on that URL. The response is a JSON document that contains server infos, server addresses as URLs and an approximate location. It can also contain a legacy server list which is a list of bare IP addresses similar to the functionality the old master servers provided via UDP. This allows us to backtrack on the larger update if it won't work out. Lost functionality ================== (also known as user-visible changes) Since the client doesn't ping each server in the list anymore, it has no way of knowing its latency to the servers. This is alleviated a bit by providing an approximate location for each server (continent) so the client only has to know its own location for approximating pings.
2018-07-11 20:46:04 +00:00
{
bool Found = false;
for(int j = 0; j < pFavorites[i].m_NumAddrs; j++)
Add client-side HTTP server info Summary ======= The idea of this is that clients will not have to ping each server for server infos which takes long, leaks the client's IP address even to servers the user does not join and is a DoS vector of the game servers for attackers. For the Internet, DDNet and KoG tab, the server list is entirely fetched from the master server, filtering out servers that don't belong into the list. The favorites tab is also supposed to work that way, except for servers that are marked as "also ping this server if it's not in the master server list". The LAN tab continues to broadcast the server info packet to find servers in the LAN. How does it work? ================= The client ships with a list of master server list URLs. On first start, the client checks which of these work and selects the fastest one. Querying the server list is a HTTP GET request on that URL. The response is a JSON document that contains server infos, server addresses as URLs and an approximate location. It can also contain a legacy server list which is a list of bare IP addresses similar to the functionality the old master servers provided via UDP. This allows us to backtrack on the larger update if it won't work out. Lost functionality ================== (also known as user-visible changes) Since the client doesn't ping each server in the list anymore, it has no way of knowing its latency to the servers. This is alleviated a bit by providing an approximate location for each server (continent) so the client only has to know its own location for approximating pings.
2018-07-11 20:46:04 +00:00
{
if(Find(pFavorites[i].m_aAddrs[j]))
Add client-side HTTP server info Summary ======= The idea of this is that clients will not have to ping each server for server infos which takes long, leaks the client's IP address even to servers the user does not join and is a DoS vector of the game servers for attackers. For the Internet, DDNet and KoG tab, the server list is entirely fetched from the master server, filtering out servers that don't belong into the list. The favorites tab is also supposed to work that way, except for servers that are marked as "also ping this server if it's not in the master server list". The LAN tab continues to broadcast the server info packet to find servers in the LAN. How does it work? ================= The client ships with a list of master server list URLs. On first start, the client checks which of these work and selects the fastest one. Querying the server list is a HTTP GET request on that URL. The response is a JSON document that contains server infos, server addresses as URLs and an approximate location. It can also contain a legacy server list which is a list of bare IP addresses similar to the functionality the old master servers provided via UDP. This allows us to backtrack on the larger update if it won't work out. Lost functionality ================== (also known as user-visible changes) Since the client doesn't ping each server in the list anymore, it has no way of knowing its latency to the servers. This is alleviated a bit by providing an approximate location for each server (continent) so the client only has to know its own location for approximating pings.
2018-07-11 20:46:04 +00:00
{
Found = true;
break;
Add client-side HTTP server info Summary ======= The idea of this is that clients will not have to ping each server for server infos which takes long, leaks the client's IP address even to servers the user does not join and is a DoS vector of the game servers for attackers. For the Internet, DDNet and KoG tab, the server list is entirely fetched from the master server, filtering out servers that don't belong into the list. The favorites tab is also supposed to work that way, except for servers that are marked as "also ping this server if it's not in the master server list". The LAN tab continues to broadcast the server info packet to find servers in the LAN. How does it work? ================= The client ships with a list of master server list URLs. On first start, the client checks which of these work and selects the fastest one. Querying the server list is a HTTP GET request on that URL. The response is a JSON document that contains server infos, server addresses as URLs and an approximate location. It can also contain a legacy server list which is a list of bare IP addresses similar to the functionality the old master servers provided via UDP. This allows us to backtrack on the larger update if it won't work out. Lost functionality ================== (also known as user-visible changes) Since the client doesn't ping each server in the list anymore, it has no way of knowing its latency to the servers. This is alleviated a bit by providing an approximate location for each server (continent) so the client only has to know its own location for approximating pings.
2018-07-11 20:46:04 +00:00
}
}
if(Found)
2015-07-09 00:08:14 +00:00
{
Add client-side HTTP server info Summary ======= The idea of this is that clients will not have to ping each server for server infos which takes long, leaks the client's IP address even to servers the user does not join and is a DoS vector of the game servers for attackers. For the Internet, DDNet and KoG tab, the server list is entirely fetched from the master server, filtering out servers that don't belong into the list. The favorites tab is also supposed to work that way, except for servers that are marked as "also ping this server if it's not in the master server list". The LAN tab continues to broadcast the server info packet to find servers in the LAN. How does it work? ================= The client ships with a list of master server list URLs. On first start, the client checks which of these work and selects the fastest one. Querying the server list is a HTTP GET request on that URL. The response is a JSON document that contains server infos, server addresses as URLs and an approximate location. It can also contain a legacy server list which is a list of bare IP addresses similar to the functionality the old master servers provided via UDP. This allows us to backtrack on the larger update if it won't work out. Lost functionality ================== (also known as user-visible changes) Since the client doesn't ping each server in the list anymore, it has no way of knowing its latency to the servers. This is alleviated a bit by providing an approximate location for each server (continent) so the client only has to know its own location for approximating pings.
2018-07-11 20:46:04 +00:00
continue;
2014-01-03 15:14:41 +00:00
}
// (Also add favorites we're not allowed to ping.)
CServerEntry *pEntry = Add(pFavorites[i].m_aAddrs, pFavorites[i].m_NumAddrs);
if(pFavorites->m_AllowPing)
{
QueueRequest(pEntry);
}
}
2014-01-03 15:14:41 +00:00
}
RequestResort();
Add client-side HTTP server info Summary ======= The idea of this is that clients will not have to ping each server for server infos which takes long, leaks the client's IP address even to servers the user does not join and is a DoS vector of the game servers for attackers. For the Internet, DDNet and KoG tab, the server list is entirely fetched from the master server, filtering out servers that don't belong into the list. The favorites tab is also supposed to work that way, except for servers that are marked as "also ping this server if it's not in the master server list". The LAN tab continues to broadcast the server info packet to find servers in the LAN. How does it work? ================= The client ships with a list of master server list URLs. On first start, the client checks which of these work and selects the fastest one. Querying the server list is a HTTP GET request on that URL. The response is a JSON document that contains server infos, server addresses as URLs and an approximate location. It can also contain a legacy server list which is a list of bare IP addresses similar to the functionality the old master servers provided via UDP. This allows us to backtrack on the larger update if it won't work out. Lost functionality ================== (also known as user-visible changes) Since the client doesn't ping each server in the list anymore, it has no way of knowing its latency to the servers. This is alleviated a bit by providing an approximate location for each server (continent) so the client only has to know its own location for approximating pings.
2018-07-11 20:46:04 +00:00
}
2021-07-08 17:18:01 +00:00
void CServerBrowser::CleanUp()
{
// clear out everything
m_ServerlistHeap.Reset();
m_NumServers = 0;
m_NumSortedServers = 0;
m_NumSortedPlayers = 0;
m_ByAddr.clear();
m_pFirstReqServer = nullptr;
m_pLastReqServer = nullptr;
2021-07-08 17:18:01 +00:00
m_NumRequests = 0;
m_CurrentMaxRequests = g_Config.m_BrMaxRequests;
}
void CServerBrowser::Update()
Add client-side HTTP server info Summary ======= The idea of this is that clients will not have to ping each server for server infos which takes long, leaks the client's IP address even to servers the user does not join and is a DoS vector of the game servers for attackers. For the Internet, DDNet and KoG tab, the server list is entirely fetched from the master server, filtering out servers that don't belong into the list. The favorites tab is also supposed to work that way, except for servers that are marked as "also ping this server if it's not in the master server list". The LAN tab continues to broadcast the server info packet to find servers in the LAN. How does it work? ================= The client ships with a list of master server list URLs. On first start, the client checks which of these work and selects the fastest one. Querying the server list is a HTTP GET request on that URL. The response is a JSON document that contains server infos, server addresses as URLs and an approximate location. It can also contain a legacy server list which is a list of bare IP addresses similar to the functionality the old master servers provided via UDP. This allows us to backtrack on the larger update if it won't work out. Lost functionality ================== (also known as user-visible changes) Since the client doesn't ping each server in the list anymore, it has no way of knowing its latency to the servers. This is alleviated a bit by providing an approximate location for each server (continent) so the client only has to know its own location for approximating pings.
2018-07-11 20:46:04 +00:00
{
2021-06-23 05:05:49 +00:00
int64_t Timeout = time_freq();
int64_t Now = time_get();
Add client-side HTTP server info Summary ======= The idea of this is that clients will not have to ping each server for server infos which takes long, leaks the client's IP address even to servers the user does not join and is a DoS vector of the game servers for attackers. For the Internet, DDNet and KoG tab, the server list is entirely fetched from the master server, filtering out servers that don't belong into the list. The favorites tab is also supposed to work that way, except for servers that are marked as "also ping this server if it's not in the master server list". The LAN tab continues to broadcast the server info packet to find servers in the LAN. How does it work? ================= The client ships with a list of master server list URLs. On first start, the client checks which of these work and selects the fastest one. Querying the server list is a HTTP GET request on that URL. The response is a JSON document that contains server infos, server addresses as URLs and an approximate location. It can also contain a legacy server list which is a list of bare IP addresses similar to the functionality the old master servers provided via UDP. This allows us to backtrack on the larger update if it won't work out. Lost functionality ================== (also known as user-visible changes) Since the client doesn't ping each server in the list anymore, it has no way of knowing its latency to the servers. This is alleviated a bit by providing an approximate location for each server (continent) so the client only has to know its own location for approximating pings.
2018-07-11 20:46:04 +00:00
const char *pHttpBestUrl;
if(!m_pHttp->GetBestUrl(&pHttpBestUrl) && pHttpBestUrl != m_pHttpPrevBestUrl)
{
2022-07-09 16:14:56 +00:00
str_copy(g_Config.m_BrCachedBestServerinfoUrl, pHttpBestUrl);
m_pHttpPrevBestUrl = pHttpBestUrl;
}
Add client-side HTTP server info Summary ======= The idea of this is that clients will not have to ping each server for server infos which takes long, leaks the client's IP address even to servers the user does not join and is a DoS vector of the game servers for attackers. For the Internet, DDNet and KoG tab, the server list is entirely fetched from the master server, filtering out servers that don't belong into the list. The favorites tab is also supposed to work that way, except for servers that are marked as "also ping this server if it's not in the master server list". The LAN tab continues to broadcast the server info packet to find servers in the LAN. How does it work? ================= The client ships with a list of master server list URLs. On first start, the client checks which of these work and selects the fastest one. Querying the server list is a HTTP GET request on that URL. The response is a JSON document that contains server infos, server addresses as URLs and an approximate location. It can also contain a legacy server list which is a list of bare IP addresses similar to the functionality the old master servers provided via UDP. This allows us to backtrack on the larger update if it won't work out. Lost functionality ================== (also known as user-visible changes) Since the client doesn't ping each server in the list anymore, it has no way of knowing its latency to the servers. This is alleviated a bit by providing an approximate location for each server (continent) so the client only has to know its own location for approximating pings.
2018-07-11 20:46:04 +00:00
m_pHttp->Update();
if(m_ServerlistType != TYPE_LAN && m_RefreshingHttp && !m_pHttp->IsRefreshing())
2010-05-29 07:25:38 +00:00
{
Add client-side HTTP server info Summary ======= The idea of this is that clients will not have to ping each server for server infos which takes long, leaks the client's IP address even to servers the user does not join and is a DoS vector of the game servers for attackers. For the Internet, DDNet and KoG tab, the server list is entirely fetched from the master server, filtering out servers that don't belong into the list. The favorites tab is also supposed to work that way, except for servers that are marked as "also ping this server if it's not in the master server list". The LAN tab continues to broadcast the server info packet to find servers in the LAN. How does it work? ================= The client ships with a list of master server list URLs. On first start, the client checks which of these work and selects the fastest one. Querying the server list is a HTTP GET request on that URL. The response is a JSON document that contains server infos, server addresses as URLs and an approximate location. It can also contain a legacy server list which is a list of bare IP addresses similar to the functionality the old master servers provided via UDP. This allows us to backtrack on the larger update if it won't work out. Lost functionality ================== (also known as user-visible changes) Since the client doesn't ping each server in the list anymore, it has no way of knowing its latency to the servers. This is alleviated a bit by providing an approximate location for each server (continent) so the client only has to know its own location for approximating pings.
2018-07-11 20:46:04 +00:00
m_RefreshingHttp = false;
2021-07-08 17:18:01 +00:00
CleanUp();
Add client-side HTTP server info Summary ======= The idea of this is that clients will not have to ping each server for server infos which takes long, leaks the client's IP address even to servers the user does not join and is a DoS vector of the game servers for attackers. For the Internet, DDNet and KoG tab, the server list is entirely fetched from the master server, filtering out servers that don't belong into the list. The favorites tab is also supposed to work that way, except for servers that are marked as "also ping this server if it's not in the master server list". The LAN tab continues to broadcast the server info packet to find servers in the LAN. How does it work? ================= The client ships with a list of master server list URLs. On first start, the client checks which of these work and selects the fastest one. Querying the server list is a HTTP GET request on that URL. The response is a JSON document that contains server infos, server addresses as URLs and an approximate location. It can also contain a legacy server list which is a list of bare IP addresses similar to the functionality the old master servers provided via UDP. This allows us to backtrack on the larger update if it won't work out. Lost functionality ================== (also known as user-visible changes) Since the client doesn't ping each server in the list anymore, it has no way of knowing its latency to the servers. This is alleviated a bit by providing an approximate location for each server (continent) so the client only has to know its own location for approximating pings.
2018-07-11 20:46:04 +00:00
UpdateFromHttp();
// TODO: move this somewhere else
2021-07-08 17:18:01 +00:00
Sort();
Add client-side HTTP server info Summary ======= The idea of this is that clients will not have to ping each server for server infos which takes long, leaks the client's IP address even to servers the user does not join and is a DoS vector of the game servers for attackers. For the Internet, DDNet and KoG tab, the server list is entirely fetched from the master server, filtering out servers that don't belong into the list. The favorites tab is also supposed to work that way, except for servers that are marked as "also ping this server if it's not in the master server list". The LAN tab continues to broadcast the server info packet to find servers in the LAN. How does it work? ================= The client ships with a list of master server list URLs. On first start, the client checks which of these work and selects the fastest one. Querying the server list is a HTTP GET request on that URL. The response is a JSON document that contains server infos, server addresses as URLs and an approximate location. It can also contain a legacy server list which is a list of bare IP addresses similar to the functionality the old master servers provided via UDP. This allows us to backtrack on the larger update if it won't work out. Lost functionality ================== (also known as user-visible changes) Since the client doesn't ping each server in the list anymore, it has no way of knowing its latency to the servers. This is alleviated a bit by providing an approximate location for each server (continent) so the client only has to know its own location for approximating pings.
2018-07-11 20:46:04 +00:00
return;
2010-05-29 07:25:38 +00:00
}
Add client-side HTTP server info Summary ======= The idea of this is that clients will not have to ping each server for server infos which takes long, leaks the client's IP address even to servers the user does not join and is a DoS vector of the game servers for attackers. For the Internet, DDNet and KoG tab, the server list is entirely fetched from the master server, filtering out servers that don't belong into the list. The favorites tab is also supposed to work that way, except for servers that are marked as "also ping this server if it's not in the master server list". The LAN tab continues to broadcast the server info packet to find servers in the LAN. How does it work? ================= The client ships with a list of master server list URLs. On first start, the client checks which of these work and selects the fastest one. Querying the server list is a HTTP GET request on that URL. The response is a JSON document that contains server infos, server addresses as URLs and an approximate location. It can also contain a legacy server list which is a list of bare IP addresses similar to the functionality the old master servers provided via UDP. This allows us to backtrack on the larger update if it won't work out. Lost functionality ================== (also known as user-visible changes) Since the client doesn't ping each server in the list anymore, it has no way of knowing its latency to the servers. This is alleviated a bit by providing an approximate location for each server (continent) so the client only has to know its own location for approximating pings.
2018-07-11 20:46:04 +00:00
CServerEntry *pEntry = m_pFirstReqServer;
int Count = 0;
2022-02-14 23:12:52 +00:00
while(true)
2010-05-29 07:25:38 +00:00
{
if(!pEntry) // no more entries
break;
if(pEntry->m_RequestTime && pEntry->m_RequestTime + Timeout < Now)
{
pEntry = pEntry->m_pNextReq;
continue;
}
// no more than 10 concurrent requests
if(Count == m_CurrentMaxRequests)
2010-05-29 07:25:38 +00:00
break;
if(pEntry->m_RequestTime == 0)
2014-01-08 05:15:56 +00:00
{
RequestImpl(pEntry->m_Info.m_aAddresses[0], pEntry, nullptr, nullptr, false);
2014-01-08 05:15:56 +00:00
}
2010-05-29 07:25:38 +00:00
Count++;
pEntry = pEntry->m_pNextReq;
}
2015-07-09 00:08:14 +00:00
if(m_pFirstReqServer && Count == 0 && m_CurrentMaxRequests > 1) //NO More current Server Requests
{
//reset old ones
pEntry = m_pFirstReqServer;
2022-02-14 23:12:52 +00:00
while(true)
{
if(!pEntry) // no more entries
break;
2015-07-09 00:08:14 +00:00
pEntry->m_RequestTime = 0;
pEntry = pEntry->m_pNextReq;
}
2015-07-09 00:08:14 +00:00
//update max-requests
m_CurrentMaxRequests = m_CurrentMaxRequests / 2;
if(m_CurrentMaxRequests < 1)
m_CurrentMaxRequests = 1;
}
else if(Count == 0 && m_CurrentMaxRequests == 1) //we reached the limit, just release all left requests. IF a server sends us a packet, a new request will be added automatically, so we can delete all
2015-07-09 00:08:14 +00:00
{
pEntry = m_pFirstReqServer;
2022-02-14 23:12:52 +00:00
while(true)
{
if(!pEntry) // no more entries
2015-07-09 00:08:14 +00:00
break;
Add client-side HTTP server info Summary ======= The idea of this is that clients will not have to ping each server for server infos which takes long, leaks the client's IP address even to servers the user does not join and is a DoS vector of the game servers for attackers. For the Internet, DDNet and KoG tab, the server list is entirely fetched from the master server, filtering out servers that don't belong into the list. The favorites tab is also supposed to work that way, except for servers that are marked as "also ping this server if it's not in the master server list". The LAN tab continues to broadcast the server info packet to find servers in the LAN. How does it work? ================= The client ships with a list of master server list URLs. On first start, the client checks which of these work and selects the fastest one. Querying the server list is a HTTP GET request on that URL. The response is a JSON document that contains server infos, server addresses as URLs and an approximate location. It can also contain a legacy server list which is a list of bare IP addresses similar to the functionality the old master servers provided via UDP. This allows us to backtrack on the larger update if it won't work out. Lost functionality ================== (also known as user-visible changes) Since the client doesn't ping each server in the list anymore, it has no way of knowing its latency to the servers. This is alleviated a bit by providing an approximate location for each server (continent) so the client only has to know its own location for approximating pings.
2018-07-11 20:46:04 +00:00
CServerEntry *pNext = pEntry->m_pNextReq;
RemoveRequest(pEntry); //release request
pEntry = pNext;
2014-01-03 15:14:41 +00:00
}
}
2015-07-09 00:08:14 +00:00
2010-05-29 07:25:38 +00:00
// check if we need to resort
if(m_Sorthash != SortHash() || m_NeedResort)
2020-12-22 10:13:51 +00:00
{
for(int i = 0; i < m_NumServers; i++)
{
CServerInfo *pInfo = &m_ppServerlist[i]->m_Info;
pInfo->m_Favorite = m_pFavorites->IsFavorite(pInfo->m_aAddresses, pInfo->m_NumAddresses);
pInfo->m_FavoriteAllowPing = m_pFavorites->IsPingAllowed(pInfo->m_aAddresses, pInfo->m_NumAddresses);
}
2010-05-29 07:25:38 +00:00
Sort();
m_NeedResort = false;
2020-12-22 10:13:51 +00:00
}
2010-05-29 07:25:38 +00:00
}
const json_value *CServerBrowser::LoadDDNetInfo()
{
LoadDDNetInfoJson();
LoadDDNetLocation();
LoadDDNetServers();
for(int i = 0; i < m_NumServers; i++)
{
UpdateServerCommunity(&m_ppServerlist[i]->m_Info);
UpdateServerRank(&m_ppServerlist[i]->m_Info);
}
return m_pDDNetInfo;
}
void CServerBrowser::LoadDDNetInfoJson()
{
void *pBuf;
unsigned Length;
if(!m_pStorage->ReadFile(DDNET_INFO_FILE, IStorage::TYPE_SAVE, &pBuf, &Length))
{
m_DDNetInfoSha256 = SHA256_ZEROED;
return;
}
m_DDNetInfoSha256 = sha256(pBuf, Length);
json_value_free(m_pDDNetInfo);
json_settings JsonSettings{};
char aError[256];
m_pDDNetInfo = json_parse_ex(&JsonSettings, static_cast<json_char *>(pBuf), Length, aError);
free(pBuf);
if(m_pDDNetInfo == nullptr)
{
log_error("serverbrowser", "invalid info json: '%s'", aError);
}
else if(m_pDDNetInfo->type != json_object)
{
log_error("serverbrowser", "invalid info root");
json_value_free(m_pDDNetInfo);
m_pDDNetInfo = nullptr;
}
}
void CServerBrowser::LoadDDNetLocation()
{
m_OwnLocation = CServerInfo::LOC_UNKNOWN;
if(m_pDDNetInfo)
{
const json_value &Location = (*m_pDDNetInfo)["location"];
if(Location.type != json_string || CServerInfo::ParseLocation(&m_OwnLocation, Location))
{
log_error("serverbrowser", "invalid location");
}
}
}
bool CServerBrowser::ParseCommunityServers(CCommunity *pCommunity, const json_value &Servers)
{
for(unsigned ServerIndex = 0; ServerIndex < Servers.u.array.length; ++ServerIndex)
{
// pServer - { name, flagId, servers }
const json_value &Server = Servers[ServerIndex];
if(Server.type != json_object)
{
log_error("serverbrowser", "invalid server (ServerIndex=%u)", ServerIndex);
return false;
}
const json_value &Name = Server["name"];
const json_value &FlagId = Server["flagId"];
const json_value &Types = Server["servers"];
if(Name.type != json_string || FlagId.type != json_integer || Types.type != json_object)
{
log_error("serverbrowser", "invalid server attribute (ServerIndex=%u)", ServerIndex);
return false;
}
if(Types.u.object.length == 0)
continue;
pCommunity->m_vCountries.emplace_back(Name.u.string.ptr, FlagId.u.integer);
CCommunityCountry *pCountry = &pCommunity->m_vCountries.back();
for(unsigned TypeIndex = 0; TypeIndex < Types.u.object.length; ++TypeIndex)
{
const json_value &Addresses = *Types.u.object.values[TypeIndex].value;
if(Addresses.type != json_array)
{
log_error("serverbrowser", "invalid addresses (ServerIndex=%u, TypeIndex=%u)", ServerIndex, TypeIndex);
return false;
}
if(Addresses.u.array.length == 0)
continue;
const char *pTypeName = Types.u.object.values[TypeIndex].name;
// add type if it doesn't exist already
const auto CommunityType = std::find_if(pCommunity->m_vTypes.begin(), pCommunity->m_vTypes.end(), [pTypeName](const auto &Elem) {
return str_comp(Elem.Name(), pTypeName) == 0;
});
if(CommunityType == pCommunity->m_vTypes.end())
{
pCommunity->m_vTypes.emplace_back(pTypeName);
}
// add addresses
for(unsigned AddressIndex = 0; AddressIndex < Addresses.u.array.length; ++AddressIndex)
{
const json_value &Address = Addresses[AddressIndex];
if(Address.type != json_string)
{
log_error("serverbrowser", "invalid address (ServerIndex=%u, TypeIndex=%u, AddressIndex=%u)", ServerIndex, TypeIndex, AddressIndex);
return false;
}
NETADDR NetAddr;
if(net_addr_from_str(&NetAddr, Address.u.string.ptr))
{
log_error("serverbrowser", "invalid address (ServerIndex=%u, TypeIndex=%u, AddressIndex=%u)", ServerIndex, TypeIndex, AddressIndex);
continue;
}
pCountry->m_vServers.emplace_back(NetAddr, pTypeName);
}
}
}
return true;
}
bool CServerBrowser::ParseCommunityFinishes(CCommunity *pCommunity, const json_value &Finishes)
{
for(unsigned FinishIndex = 0; FinishIndex < Finishes.u.array.length; ++FinishIndex)
{
const json_value &Finish = Finishes[FinishIndex];
if(Finish.type != json_string)
{
log_error("serverbrowser", "invalid rank (FinishIndex=%u)", FinishIndex);
return false;
}
pCommunity->m_FinishedMaps.emplace((const char *)Finish);
}
return true;
}
void CServerBrowser::LoadDDNetServers()
2014-09-13 14:36:25 +00:00
{
// Parse communities
m_vCommunities.clear();
m_CommunityServersByAddr.clear();
if(!m_pDDNetInfo)
{
return;
}
const json_value &Communities = (*m_pDDNetInfo)["communities"];
if(Communities.type != json_array)
{
return;
}
for(unsigned CommunityIndex = 0; CommunityIndex < Communities.u.array.length; ++CommunityIndex)
{
const json_value &Community = Communities[CommunityIndex];
if(Community.type != json_object)
{
log_error("serverbrowser", "invalid community (CommunityIndex=%d)", (int)CommunityIndex);
continue;
}
const json_value &Id = Community["id"];
if(Id.type != json_string)
{
log_error("serverbrowser", "invalid community id (CommunityIndex=%d)", (int)CommunityIndex);
continue;
}
const json_value &Icon = Community["icon"];
const json_value &IconSha256 = Icon["sha256"];
const json_value &IconUrl = Icon["url"];
const json_value &Name = Community["name"];
const json_value HasFinishes = Community["has_finishes"];
const json_value *pFinishes = &Icon["finishes"];
const json_value *pServers = &Icon["servers"];
if(pFinishes->type == json_none)
{
if(str_comp(Id, COMMUNITY_DDNET) == 0)
{
pFinishes = &(*m_pDDNetInfo)["maps"];
}
}
// Backward compatibility.
if(pServers->type == json_none)
{
if(str_comp(Id, COMMUNITY_DDNET) == 0)
{
pServers = &(*m_pDDNetInfo)["servers"];
}
else if(str_comp(Id, "kog") == 0)
{
pServers = &(*m_pDDNetInfo)["servers-kog"];
}
}
if(false ||
Icon.type != json_object ||
IconSha256.type != json_string ||
IconUrl.type != json_string ||
Name.type != json_string ||
HasFinishes.type != json_boolean ||
(pFinishes->type != json_array && pFinishes->type != json_none) ||
pServers->type != json_array)
{
log_error("serverbrowser", "invalid community attribute (CommunityId=%s)", (const char *)Id);
continue;
}
SHA256_DIGEST ParsedIconSha256;
if(sha256_from_str(&ParsedIconSha256, IconSha256) != 0)
{
log_error("serverbrowser", "invalid community icon sha256 (CommunityId=%s)", (const char *)Id);
continue;
}
CCommunity NewCommunity(Id, Name, ParsedIconSha256, IconUrl);
if(!ParseCommunityServers(&NewCommunity, *pServers))
{
log_error("serverbrowser", "invalid community servers (CommunityId=%s)", NewCommunity.Id());
continue;
}
NewCommunity.m_HasFinishes = HasFinishes;
if(NewCommunity.m_HasFinishes && pFinishes->type == json_array && !ParseCommunityFinishes(&NewCommunity, *pFinishes))
{
log_error("serverbrowser", "invalid community finishes (CommunityId=%s)", NewCommunity.Id());
continue;
}
2014-09-13 14:36:25 +00:00
for(const auto &Country : NewCommunity.Countries())
2014-09-13 14:36:25 +00:00
{
for(const auto &Server : Country.Servers())
{
m_CommunityServersByAddr.emplace(Server.Address(), CCommunityServer(NewCommunity.Id(), Country.Name(), Server.TypeName()));
}
}
m_vCommunities.push_back(std::move(NewCommunity));
}
// Add default none community
{
CCommunity NoneCommunity(COMMUNITY_NONE, "None", SHA256_ZEROED, "");
NoneCommunity.m_vCountries.emplace_back(COMMUNITY_COUNTRY_NONE, -1);
NoneCommunity.m_vTypes.emplace_back(COMMUNITY_TYPE_NONE);
m_vCommunities.push_back(std::move(NoneCommunity));
}
// Remove unknown elements from exclude lists
CleanFilters();
}
void CServerBrowser::UpdateServerFilteredPlayers(CServerInfo *pInfo) const
{
pInfo->m_NumFilteredPlayers = g_Config.m_BrFilterSpectators ? pInfo->m_NumPlayers : pInfo->m_NumClients;
if(g_Config.m_BrFilterConnectingPlayers)
{
for(const auto &Client : pInfo->m_aClients)
{
if((!g_Config.m_BrFilterSpectators || Client.m_Player) && str_comp(Client.m_aName, "(connecting)") == 0 && Client.m_aClan[0] == '\0')
pInfo->m_NumFilteredPlayers--;
}
}
}
void CServerBrowser::UpdateServerFriends(CServerInfo *pInfo) const
{
pInfo->m_FriendState = IFriends::FRIEND_NO;
pInfo->m_FriendNum = 0;
for(int ClientIndex = 0; ClientIndex < minimum(pInfo->m_NumReceivedClients, (int)MAX_CLIENTS); ClientIndex++)
{
pInfo->m_aClients[ClientIndex].m_FriendState = m_pFriends->GetFriendState(pInfo->m_aClients[ClientIndex].m_aName, pInfo->m_aClients[ClientIndex].m_aClan);
pInfo->m_FriendState = maximum(pInfo->m_FriendState, pInfo->m_aClients[ClientIndex].m_FriendState);
if(pInfo->m_aClients[ClientIndex].m_FriendState != IFriends::FRIEND_NO)
pInfo->m_FriendNum++;
}
}
void CServerBrowser::UpdateServerCommunity(CServerInfo *pInfo) const
{
for(int AddressIndex = 0; AddressIndex < pInfo->m_NumAddresses; AddressIndex++)
{
const auto Community = m_CommunityServersByAddr.find(pInfo->m_aAddresses[AddressIndex]);
if(Community != m_CommunityServersByAddr.end())
{
str_copy(pInfo->m_aCommunityId, Community->second.CommunityId());
str_copy(pInfo->m_aCommunityCountry, Community->second.CountryName());
str_copy(pInfo->m_aCommunityType, Community->second.TypeName());
return;
}
}
str_copy(pInfo->m_aCommunityId, COMMUNITY_NONE);
str_copy(pInfo->m_aCommunityCountry, COMMUNITY_COUNTRY_NONE);
str_copy(pInfo->m_aCommunityType, COMMUNITY_TYPE_NONE);
}
void CServerBrowser::UpdateServerRank(CServerInfo *pInfo) const
{
const CCommunity *pCommunity = Community(pInfo->m_aCommunityId);
pInfo->m_HasRank = pCommunity == nullptr ? CServerInfo::RANK_UNAVAILABLE : pCommunity->HasRank(pInfo->m_aMap);
}
const char *CServerBrowser::GetTutorialServer()
{
const CCommunity *pCommunity = Community(COMMUNITY_DDNET);
if(pCommunity == nullptr)
return nullptr;
const char *pBestAddr = nullptr;
int BestLatency = std::numeric_limits<int>::max();
for(const auto &Country : pCommunity->Countries())
{
for(const auto &Server : Country.Servers())
{
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
if(str_comp(Server.TypeName(), "Tutorial") != 0)
continue;
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
const CServerEntry *pEntry = Find(Server.Address());
if(!pEntry)
continue;
if(pEntry->m_Info.m_NumPlayers > pEntry->m_Info.m_MaxPlayers - 10)
continue;
if(pEntry->m_Info.m_Latency >= BestLatency)
continue;
BestLatency = pEntry->m_Info.m_Latency;
pBestAddr = pEntry->m_Info.m_aAddress;
}
}
return pBestAddr;
}
bool CServerBrowser::IsRefreshing() const
{
return m_pFirstReqServer != nullptr;
}
2010-05-29 07:25:38 +00:00
Add client-side HTTP server info Summary ======= The idea of this is that clients will not have to ping each server for server infos which takes long, leaks the client's IP address even to servers the user does not join and is a DoS vector of the game servers for attackers. For the Internet, DDNet and KoG tab, the server list is entirely fetched from the master server, filtering out servers that don't belong into the list. The favorites tab is also supposed to work that way, except for servers that are marked as "also ping this server if it's not in the master server list". The LAN tab continues to broadcast the server info packet to find servers in the LAN. How does it work? ================= The client ships with a list of master server list URLs. On first start, the client checks which of these work and selects the fastest one. Querying the server list is a HTTP GET request on that URL. The response is a JSON document that contains server infos, server addresses as URLs and an approximate location. It can also contain a legacy server list which is a list of bare IP addresses similar to the functionality the old master servers provided via UDP. This allows us to backtrack on the larger update if it won't work out. Lost functionality ================== (also known as user-visible changes) Since the client doesn't ping each server in the list anymore, it has no way of knowing its latency to the servers. This is alleviated a bit by providing an approximate location for each server (continent) so the client only has to know its own location for approximating pings.
2018-07-11 20:46:04 +00:00
bool CServerBrowser::IsGettingServerlist() const
2010-05-29 07:25:38 +00:00
{
Add client-side HTTP server info Summary ======= The idea of this is that clients will not have to ping each server for server infos which takes long, leaks the client's IP address even to servers the user does not join and is a DoS vector of the game servers for attackers. For the Internet, DDNet and KoG tab, the server list is entirely fetched from the master server, filtering out servers that don't belong into the list. The favorites tab is also supposed to work that way, except for servers that are marked as "also ping this server if it's not in the master server list". The LAN tab continues to broadcast the server info packet to find servers in the LAN. How does it work? ================= The client ships with a list of master server list URLs. On first start, the client checks which of these work and selects the fastest one. Querying the server list is a HTTP GET request on that URL. The response is a JSON document that contains server infos, server addresses as URLs and an approximate location. It can also contain a legacy server list which is a list of bare IP addresses similar to the functionality the old master servers provided via UDP. This allows us to backtrack on the larger update if it won't work out. Lost functionality ================== (also known as user-visible changes) Since the client doesn't ping each server in the list anymore, it has no way of knowing its latency to the servers. This is alleviated a bit by providing an approximate location for each server (continent) so the client only has to know its own location for approximating pings.
2018-07-11 20:46:04 +00:00
return m_pHttp->IsRefreshing();
2010-05-29 07:25:38 +00:00
}
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;
}
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
bool CCommunity::HasCountry(const char *pCountryName) const
{
return std::find_if(Countries().begin(), Countries().end(), [pCountryName](const auto &Elem) {
return str_comp(Elem.Name(), pCountryName) == 0;
}) != Countries().end();
}
bool CCommunity::HasType(const char *pTypeName) const
{
return std::find_if(Types().begin(), Types().end(), [pTypeName](const auto &Elem) {
return str_comp(Elem.Name(), pTypeName) == 0;
}) != Types().end();
}
CServerInfo::ERankState CCommunity::HasRank(const char *pMap) const
{
if(!HasRanks())
return CServerInfo::RANK_UNAVAILABLE;
const CCommunityMap Needle(pMap);
return m_FinishedMaps.count(Needle) == 0 ? CServerInfo::RANK_UNRANKED : CServerInfo::RANK_RANKED;
}
const std::vector<CCommunity> &CServerBrowser::Communities() const
{
return m_vCommunities;
}
const CCommunity *CServerBrowser::Community(const char *pCommunityId) const
{
const auto Community = std::find_if(Communities().begin(), Communities().end(), [pCommunityId](const auto &Elem) {
return str_comp(Elem.Id(), pCommunityId) == 0;
});
return Community == Communities().end() ? nullptr : &(*Community);
}
std::vector<const CCommunity *> CServerBrowser::SelectedCommunities() const
{
std::vector<const CCommunity *> vpSelected;
for(const auto &Community : Communities())
{
if(!CommunitiesFilter().Filtered(Community.Id()))
{
vpSelected.push_back(&Community);
}
}
return vpSelected;
}
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
std::vector<const CCommunity *> CServerBrowser::FavoriteCommunities() const
2014-09-19 21:52:09 +00:00
{
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
// This is done differently than SelectedCommunities because the favorite
// communities should be returned in the order specified by the user.
std::vector<const CCommunity *> vpFavorites;
for(const auto &CommunityId : FavoriteCommunitiesFilter().Entries())
{
const CCommunity *pCommunity = Community(CommunityId.Id());
if(pCommunity)
{
vpFavorites.push_back(pCommunity);
}
}
return vpFavorites;
}
2015-07-09 00:08:14 +00:00
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
std::vector<const CCommunity *> CServerBrowser::CurrentCommunities() const
{
if(m_ServerlistType == IServerBrowser::TYPE_INTERNET || m_ServerlistType == IServerBrowser::TYPE_FAVORITES)
{
return SelectedCommunities();
}
else if(m_ServerlistType >= IServerBrowser::TYPE_FAVORITE_COMMUNITY_1 && m_ServerlistType <= IServerBrowser::TYPE_FAVORITE_COMMUNITY_3)
{
const size_t CommunityIndex = m_ServerlistType - IServerBrowser::TYPE_FAVORITE_COMMUNITY_1;
std::vector<const CCommunity *> vpFavoriteCommunities = FavoriteCommunities();
dbg_assert(CommunityIndex < vpFavoriteCommunities.size(), "Invalid favorite community serverbrowser type");
return {vpFavoriteCommunities[CommunityIndex]};
}
else
{
return {};
}
2014-09-19 21:52:09 +00:00
}
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
unsigned CServerBrowser::CurrentCommunitiesHash() const
2014-09-19 21:52:09 +00:00
{
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
std::vector<const CCommunity *> vpCommunities = CurrentCommunities();
unsigned Hash = 5381;
for(const CCommunity *pCommunity : CurrentCommunities())
{
Hash = (Hash << 5) + Hash + str_quickhash(pCommunity->Id());
}
return Hash;
}
2014-09-19 21:52:09 +00:00
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
void CFavoriteCommunityFilterList::Add(const char *pCommunityId)
{
// Remove community if it's already a favorite, so it will be added again at
// the end of the list, to allow setting the entire list easier with binds.
Remove(pCommunityId);
2014-09-19 21:52:09 +00:00
// Ensure maximum number of favorite communities, by removing the least-recently
// added community from the beginning, when the maximum number of favorite
// communities has been reached.
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
constexpr size_t MaxFavoriteCommunities = 3;
if(m_vEntries.size() >= MaxFavoriteCommunities)
{
dbg_assert(m_vEntries.size() == MaxFavoriteCommunities, "Maximum number of communities can never be exceeded");
m_vEntries.erase(m_vEntries.begin());
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
}
m_vEntries.emplace_back(pCommunityId);
}
2014-09-19 21:52:09 +00:00
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
void CFavoriteCommunityFilterList::Remove(const char *pCommunityId)
{
auto FoundCommunity = std::find(m_vEntries.begin(), m_vEntries.end(), CCommunityId(pCommunityId));
if(FoundCommunity != m_vEntries.end())
2014-09-19 21:52:09 +00:00
{
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
m_vEntries.erase(FoundCommunity);
}
}
void CFavoriteCommunityFilterList::Clear()
{
m_vEntries.clear();
}
bool CFavoriteCommunityFilterList::Filtered(const char *pCommunityId) const
{
return std::find(m_vEntries.begin(), m_vEntries.end(), CCommunityId(pCommunityId)) != m_vEntries.end();
}
bool CFavoriteCommunityFilterList::Empty() const
{
return m_vEntries.empty();
}
void CFavoriteCommunityFilterList::Clean(const std::vector<CCommunity> &vAllowedCommunities)
{
auto It = std::remove_if(m_vEntries.begin(), m_vEntries.end(), [&](const auto &Community) {
return std::find_if(vAllowedCommunities.begin(), vAllowedCommunities.end(), [&](const CCommunity &AllowedCommunity) {
return str_comp(Community.Id(), AllowedCommunity.Id()) == 0;
}) == vAllowedCommunities.end();
});
m_vEntries.erase(It, m_vEntries.end());
}
void CFavoriteCommunityFilterList::Save(IConfigManager *pConfigManager) const
{
char aBuf[32 + CServerInfo::MAX_COMMUNITY_ID_LENGTH];
for(const auto &FavoriteCommunity : m_vEntries)
{
str_copy(aBuf, "add_favorite_community \"");
str_append(aBuf, FavoriteCommunity.Id());
str_append(aBuf, "\"");
pConfigManager->WriteLine(aBuf);
}
}
const std::vector<CCommunityId> &CFavoriteCommunityFilterList::Entries() const
{
return m_vEntries;
}
void CExcludedCommunityFilterList::Add(const char *pCommunityId)
{
m_Entries.emplace(pCommunityId);
}
void CExcludedCommunityFilterList::Remove(const char *pCommunityId)
{
m_Entries.erase(CCommunityId(pCommunityId));
}
void CExcludedCommunityFilterList::Clear()
{
m_Entries.clear();
}
bool CExcludedCommunityFilterList::Filtered(const char *pCommunityId) const
{
return std::find(m_Entries.begin(), m_Entries.end(), CCommunityId(pCommunityId)) != m_Entries.end();
}
bool CExcludedCommunityFilterList::Empty() const
{
return m_Entries.empty();
}
void CExcludedCommunityFilterList::Clean(const std::vector<CCommunity> &vAllowedCommunities)
{
for(auto It = m_Entries.begin(); It != m_Entries.end();)
{
const bool Found = std::find_if(vAllowedCommunities.begin(), vAllowedCommunities.end(), [&](const CCommunity &AllowedCommunity) {
return str_comp(It->Id(), AllowedCommunity.Id()) == 0;
}) != vAllowedCommunities.end();
if(Found)
{
++It;
}
else
2014-09-19 21:52:09 +00:00
{
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
It = m_Entries.erase(It);
2014-09-19 21:52:09 +00:00
}
2019-03-11 11:39:54 +00:00
}
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
// Prevent filter that would exclude all allowed communities
if(m_Entries.size() == vAllowedCommunities.size())
{
m_Entries.clear();
}
2014-09-19 21:52:09 +00:00
}
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
void CExcludedCommunityFilterList::Save(IConfigManager *pConfigManager) const
{
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
char aBuf[32 + CServerInfo::MAX_COMMUNITY_ID_LENGTH];
for(const auto &ExcludedCommunity : m_Entries)
{
str_copy(aBuf, "add_excluded_community \"");
str_append(aBuf, ExcludedCommunity.Id());
str_append(aBuf, "\"");
pConfigManager->WriteLine(aBuf);
}
}
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
void CExcludedCommunityCountryFilterList::Add(const char *pCountryName)
{
for(const CCommunity *pCommunity : m_CurrentCommunitiesGetter())
{
if(pCommunity->HasCountry(pCountryName))
{
Add(pCommunity->Id(), pCountryName);
}
}
}
void CExcludedCommunityCountryFilterList::Add(const char *pCommunityId, const char *pCountryName)
{
CCommunityId CommunityId(pCommunityId);
if(m_Entries.find(CommunityId) == m_Entries.end())
{
m_Entries[CommunityId] = {};
}
m_Entries[CommunityId].emplace(pCountryName);
}
void CExcludedCommunityCountryFilterList::Remove(const char *pCountryName)
{
for(const CCommunity *pCommunity : m_CurrentCommunitiesGetter())
{
Remove(pCommunity->Id(), pCountryName);
}
}
void CExcludedCommunityCountryFilterList::Remove(const char *pCommunityId, const char *pCountryName)
{
auto CommunityEntry = m_Entries.find(CCommunityId(pCommunityId));
if(CommunityEntry != m_Entries.end())
{
CommunityEntry->second.erase(pCountryName);
}
}
void CExcludedCommunityCountryFilterList::Clear()
{
for(const CCommunity *pCommunity : m_CurrentCommunitiesGetter())
{
auto CommunityEntry = m_Entries.find(pCommunity->Id());
if(CommunityEntry != m_Entries.end())
{
CommunityEntry->second.clear();
}
}
}
bool CExcludedCommunityCountryFilterList::Filtered(const char *pCountryName) const
2014-09-19 21:52:09 +00:00
{
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
const auto Communities = m_CurrentCommunitiesGetter();
return std::none_of(Communities.begin(), Communities.end(), [&](const CCommunity *pCommunity) {
if(!pCommunity->HasCountry(pCountryName))
return false;
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
auto CommunityEntry = m_Entries.find(CCommunityId(pCommunity->Id()));
if(CommunityEntry == m_Entries.end())
return true;
const auto &CountryEntries = CommunityEntry->second;
if(CountryEntries.find(CCommunityCountryName(pCountryName)) == CountryEntries.end())
return true;
return false;
});
2014-09-19 21:52:09 +00:00
}
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
bool CExcludedCommunityCountryFilterList::Empty() const
2014-09-19 21:52:09 +00:00
{
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
for(const CCommunity *pCommunity : m_CurrentCommunitiesGetter())
{
auto CommunityEntry = m_Entries.find(CCommunityId(pCommunity->Id()));
return CommunityEntry == m_Entries.end() || CommunityEntry->second.empty();
}
return false;
}
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
void CExcludedCommunityCountryFilterList::Clean(const std::vector<CCommunity> &vAllowedCommunities)
{
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
for(auto It = m_Entries.begin(); It != m_Entries.end();)
{
const bool Found = std::find_if(vAllowedCommunities.begin(), vAllowedCommunities.end(), [&](const CCommunity &AllowedCommunity) {
return str_comp(It->first.Id(), AllowedCommunity.Id()) == 0;
}) != vAllowedCommunities.end();
if(Found)
{
++It;
}
else
{
It = m_Entries.erase(It);
}
}
2015-07-09 00:08:14 +00:00
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
for(const CCommunity &AllowedCommunity : vAllowedCommunities)
2014-09-19 21:52:09 +00:00
{
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
auto CommunityEntry = m_Entries.find(CCommunityId(AllowedCommunity.Id()));
if(CommunityEntry != m_Entries.end())
2014-09-19 21:52:09 +00:00
{
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
auto &CountryEntries = CommunityEntry->second;
for(auto It = CountryEntries.begin(); It != CountryEntries.end();)
{
if(AllowedCommunity.HasCountry(It->Name()))
{
++It;
}
else
{
It = CountryEntries.erase(It);
}
}
// Prevent filter that would exclude all allowed countries
if(CountryEntries.size() == AllowedCommunity.Countries().size())
{
CountryEntries.clear();
}
2014-09-19 21:52:09 +00:00
}
}
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
}
2014-09-19 21:52:09 +00:00
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
void CExcludedCommunityCountryFilterList::Save(IConfigManager *pConfigManager) const
{
char aBuf[32 + CServerInfo::MAX_COMMUNITY_ID_LENGTH + CServerInfo::MAX_COMMUNITY_COUNTRY_LENGTH];
for(const auto &[Community, Countries] : m_Entries)
{
for(const auto &Country : Countries)
{
str_copy(aBuf, "add_excluded_country \"");
str_append(aBuf, Community.Id());
str_append(aBuf, "\" \"");
str_append(aBuf, Country.Name());
str_append(aBuf, "\"");
pConfigManager->WriteLine(aBuf);
}
}
2014-09-19 21:52:09 +00:00
}
2014-12-14 15:45:18 +00:00
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
void CExcludedCommunityTypeFilterList::Add(const char *pTypeName)
2014-12-14 15:45:18 +00:00
{
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
for(const CCommunity *pCommunity : m_CurrentCommunitiesGetter())
{
if(pCommunity->HasType(pTypeName))
{
Add(pCommunity->Id(), pTypeName);
}
}
}
2015-07-09 00:08:14 +00:00
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
void CExcludedCommunityTypeFilterList::Add(const char *pCommunityId, const char *pTypeName)
{
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
CCommunityId CommunityId(pCommunityId);
if(m_Entries.find(CommunityId) == m_Entries.end())
{
m_Entries[CommunityId] = {};
}
m_Entries[CommunityId].emplace(pTypeName);
}
void CExcludedCommunityTypeFilterList::Remove(const char *pTypeName)
{
for(const CCommunity *pCommunity : m_CurrentCommunitiesGetter())
{
Remove(pCommunity->Id(), pTypeName);
}
}
void CExcludedCommunityTypeFilterList::Remove(const char *pCommunityId, const char *pTypeName)
{
auto CommunityEntry = m_Entries.find(CCommunityId(pCommunityId));
if(CommunityEntry != m_Entries.end())
{
CommunityEntry->second.erase(pTypeName);
}
}
void CExcludedCommunityTypeFilterList::Clear()
{
for(const CCommunity *pCommunity : m_CurrentCommunitiesGetter())
{
auto CommunityEntry = m_Entries.find(pCommunity->Id());
if(CommunityEntry != m_Entries.end())
{
CommunityEntry->second.clear();
}
}
}
bool CExcludedCommunityTypeFilterList::Filtered(const char *pTypeName) const
{
const auto Communities = m_CurrentCommunitiesGetter();
return std::none_of(Communities.begin(), Communities.end(), [&](const CCommunity *pCommunity) {
if(!pCommunity->HasType(pTypeName))
return false;
auto CommunityEntry = m_Entries.find(CCommunityId(pCommunity->Id()));
if(CommunityEntry == m_Entries.end())
return true;
const auto &TypeEntries = CommunityEntry->second;
return TypeEntries.find(CCommunityTypeName(pTypeName)) == TypeEntries.end();
});
}
2014-12-14 15:45:18 +00:00
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
bool CExcludedCommunityTypeFilterList::Empty() const
{
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
for(const CCommunity *pCommunity : m_CurrentCommunitiesGetter())
{
auto CommunityEntry = m_Entries.find(CCommunityId(pCommunity->Id()));
return CommunityEntry == m_Entries.end() || CommunityEntry->second.empty();
}
return false;
}
void CExcludedCommunityTypeFilterList::Clean(const std::vector<CCommunity> &vAllowedCommunities)
{
for(auto It = m_Entries.begin(); It != m_Entries.end();)
{
const bool Found = std::find_if(vAllowedCommunities.begin(), vAllowedCommunities.end(), [&](const CCommunity &AllowedCommunity) {
return str_comp(It->first.Id(), AllowedCommunity.Id()) == 0;
}) != vAllowedCommunities.end();
if(Found)
{
++It;
}
else
{
It = m_Entries.erase(It);
}
}
for(const CCommunity &AllowedCommunity : vAllowedCommunities)
{
auto CommunityEntry = m_Entries.find(CCommunityId(AllowedCommunity.Id()));
if(CommunityEntry != m_Entries.end())
{
auto &TypeEntries = CommunityEntry->second;
for(auto It = TypeEntries.begin(); It != TypeEntries.end();)
{
if(AllowedCommunity.HasType(It->Name()))
{
++It;
}
else
{
It = TypeEntries.erase(It);
}
}
// Prevent filter that would exclude all allowed countries
if(TypeEntries.size() == AllowedCommunity.Types().size())
{
TypeEntries.clear();
}
}
}
}
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
void CExcludedCommunityTypeFilterList::Save(IConfigManager *pConfigManager) const
{
Add tabs for favorite communities, separate country/type filters Support adding up to three communities as favorites in the server browser. Favorites can be changed with favorite buttons which are shown in the community filter on the Internet and Favorites tabs. The commands `add_favorite_community` and `remove_favorite_community` are added to change the favorite communities via the console and for saving the favorite communities to the config file. For the favorite communities, additional tabs using the communities' icons are shown in the server browser next to the Internet, LAN and Favorites tabs. Each community tab shows only the servers from the respective community, hence the community filters UI is not shown on the community tabs but only on the Internet and Favorites tabs. The country and type filters on community tabs cover only the countries and types from the respective community. Favorite communities are added from left to right. When more than three favorite communities are added, the oldest (leftmost) favorite community will be removed from the list. When starting the client for the first time, i.e. with `cl_show_welcome 1`, the DDNet tab will be created as the only favorite community and selected initially. The community, country and type filters are unset when starting for the first time, so the Internet tab now shows all servers per default. When starting with a `ui_page` for a favorite community that is not configured, the page is reset to the Internet tab. This also affects those who upgrade from versions with the old DDNet and KoG tabs. The server browser is now also correctly updated when changing `ui_page` via the console. Track country and type filters for every community separately, to avoid filters resetting when switching between community tabs or changing the community filter. The commands `add_excluded_community`, `remove_excluded_community`, `add_excluded_country`, `remove_excluded_country`, `add_excluded_type` and `remove_excluded_type` are added to change the exclusion filters via the console and for saving the exclusion filters to the config file. Render community filters above the toolbox (filter, info and friends) tabs when on the Internet and Favorites tab, so this setting is more visible and can be changed also when the other toolbox tabs are selected. Add icon for the none community, based on the tee country flag color. This icon is hard-coded in the client, as the none community also is, so fetching the icon from the server would be inconvenient. Load community icons already when rendering the menu instead of only when rendering the server browser, so the icons are immediately available when using the start menu. Find tutorial server by searching for community type "Tutorial" instead of searching for "(Tutorial)" in the server name. Avoid cleaning favorite communities and filters when there are no communities, i.e. when the DDNet info failed to be loaded or does not contain any communities, to avoid losing all favorite communities and filters in this case. Closes #7774.
2024-01-21 10:06:25 +00:00
char aBuf[32 + CServerInfo::MAX_COMMUNITY_ID_LENGTH + CServerInfo::MAX_COMMUNITY_TYPE_LENGTH];
for(const auto &[Community, Types] : m_Entries)
{
for(const auto &Type : Types)
{
str_copy(aBuf, "add_excluded_type \"");
str_append(aBuf, Community.Id());
str_append(aBuf, "\" \"");
str_append(aBuf, Type.Name());
str_append(aBuf, "\"");
pConfigManager->WriteLine(aBuf);
}
}
}
void CServerBrowser::CleanFilters()
{
// Keep filters if we failed to load any communities
if(Communities().empty())
return;
FavoriteCommunitiesFilter().Clean(Communities());
CommunitiesFilter().Clean(Communities());
CountriesFilter().Clean(Communities());
TypesFilter().Clean(Communities());
2014-12-14 15:45:18 +00:00
}
Add client-side HTTP server info Summary ======= The idea of this is that clients will not have to ping each server for server infos which takes long, leaks the client's IP address even to servers the user does not join and is a DoS vector of the game servers for attackers. For the Internet, DDNet and KoG tab, the server list is entirely fetched from the master server, filtering out servers that don't belong into the list. The favorites tab is also supposed to work that way, except for servers that are marked as "also ping this server if it's not in the master server list". The LAN tab continues to broadcast the server info packet to find servers in the LAN. How does it work? ================= The client ships with a list of master server list URLs. On first start, the client checks which of these work and selects the fastest one. Querying the server list is a HTTP GET request on that URL. The response is a JSON document that contains server infos, server addresses as URLs and an approximate location. It can also contain a legacy server list which is a list of bare IP addresses similar to the functionality the old master servers provided via UDP. This allows us to backtrack on the larger update if it won't work out. Lost functionality ================== (also known as user-visible changes) Since the client doesn't ping each server in the list anymore, it has no way of knowing its latency to the servers. This is alleviated a bit by providing an approximate location for each server (continent) so the client only has to know its own location for approximating pings.
2018-07-11 20:46:04 +00:00
bool CServerBrowser::IsRegistered(const NETADDR &Addr)
{
const int NumServers = m_pHttp->NumServers();
for(int i = 0; i < NumServers; i++)
{
const CServerInfo Info = m_pHttp->Server(i);
for(int j = 0; j < Info.m_NumAddresses; j++)
{
if(net_addr_comp(&Info.m_aAddresses[j], &Addr) == 0)
{
return true;
}
}
}
const int NumLegacyServers = m_pHttp->NumLegacyServers();
for(int i = 0; i < NumLegacyServers; i++)
{
if(net_addr_comp(&m_pHttp->LegacyServer(i), &Addr) == 0)
{
return true;
}
}
return false;
}
Add client-side HTTP server info Summary ======= The idea of this is that clients will not have to ping each server for server infos which takes long, leaks the client's IP address even to servers the user does not join and is a DoS vector of the game servers for attackers. For the Internet, DDNet and KoG tab, the server list is entirely fetched from the master server, filtering out servers that don't belong into the list. The favorites tab is also supposed to work that way, except for servers that are marked as "also ping this server if it's not in the master server list". The LAN tab continues to broadcast the server info packet to find servers in the LAN. How does it work? ================= The client ships with a list of master server list URLs. On first start, the client checks which of these work and selects the fastest one. Querying the server list is a HTTP GET request on that URL. The response is a JSON document that contains server infos, server addresses as URLs and an approximate location. It can also contain a legacy server list which is a list of bare IP addresses similar to the functionality the old master servers provided via UDP. This allows us to backtrack on the larger update if it won't work out. Lost functionality ================== (also known as user-visible changes) Since the client doesn't ping each server in the list anymore, it has no way of knowing its latency to the servers. This is alleviated a bit by providing an approximate location for each server (continent) so the client only has to know its own location for approximating pings.
2018-07-11 20:46:04 +00:00
int CServerInfo::EstimateLatency(int Loc1, int Loc2)
{
if(Loc1 == LOC_UNKNOWN || Loc2 == LOC_UNKNOWN)
{
return 999;
}
if(Loc1 != Loc2)
{
return 199;
Add client-side HTTP server info Summary ======= The idea of this is that clients will not have to ping each server for server infos which takes long, leaks the client's IP address even to servers the user does not join and is a DoS vector of the game servers for attackers. For the Internet, DDNet and KoG tab, the server list is entirely fetched from the master server, filtering out servers that don't belong into the list. The favorites tab is also supposed to work that way, except for servers that are marked as "also ping this server if it's not in the master server list". The LAN tab continues to broadcast the server info packet to find servers in the LAN. How does it work? ================= The client ships with a list of master server list URLs. On first start, the client checks which of these work and selects the fastest one. Querying the server list is a HTTP GET request on that URL. The response is a JSON document that contains server infos, server addresses as URLs and an approximate location. It can also contain a legacy server list which is a list of bare IP addresses similar to the functionality the old master servers provided via UDP. This allows us to backtrack on the larger update if it won't work out. Lost functionality ================== (also known as user-visible changes) Since the client doesn't ping each server in the list anymore, it has no way of knowing its latency to the servers. This is alleviated a bit by providing an approximate location for each server (continent) so the client only has to know its own location for approximating pings.
2018-07-11 20:46:04 +00:00
}
return 99;
Add client-side HTTP server info Summary ======= The idea of this is that clients will not have to ping each server for server infos which takes long, leaks the client's IP address even to servers the user does not join and is a DoS vector of the game servers for attackers. For the Internet, DDNet and KoG tab, the server list is entirely fetched from the master server, filtering out servers that don't belong into the list. The favorites tab is also supposed to work that way, except for servers that are marked as "also ping this server if it's not in the master server list". The LAN tab continues to broadcast the server info packet to find servers in the LAN. How does it work? ================= The client ships with a list of master server list URLs. On first start, the client checks which of these work and selects the fastest one. Querying the server list is a HTTP GET request on that URL. The response is a JSON document that contains server infos, server addresses as URLs and an approximate location. It can also contain a legacy server list which is a list of bare IP addresses similar to the functionality the old master servers provided via UDP. This allows us to backtrack on the larger update if it won't work out. Lost functionality ================== (also known as user-visible changes) Since the client doesn't ping each server in the list anymore, it has no way of knowing its latency to the servers. This is alleviated a bit by providing an approximate location for each server (continent) so the client only has to know its own location for approximating pings.
2018-07-11 20:46:04 +00:00
}
Add client-side HTTP server info Summary ======= The idea of this is that clients will not have to ping each server for server infos which takes long, leaks the client's IP address even to servers the user does not join and is a DoS vector of the game servers for attackers. For the Internet, DDNet and KoG tab, the server list is entirely fetched from the master server, filtering out servers that don't belong into the list. The favorites tab is also supposed to work that way, except for servers that are marked as "also ping this server if it's not in the master server list". The LAN tab continues to broadcast the server info packet to find servers in the LAN. How does it work? ================= The client ships with a list of master server list URLs. On first start, the client checks which of these work and selects the fastest one. Querying the server list is a HTTP GET request on that URL. The response is a JSON document that contains server infos, server addresses as URLs and an approximate location. It can also contain a legacy server list which is a list of bare IP addresses similar to the functionality the old master servers provided via UDP. This allows us to backtrack on the larger update if it won't work out. Lost functionality ================== (also known as user-visible changes) Since the client doesn't ping each server in the list anymore, it has no way of knowing its latency to the servers. This is alleviated a bit by providing an approximate location for each server (continent) so the client only has to know its own location for approximating pings.
2018-07-11 20:46:04 +00:00
bool CServerInfo::ParseLocation(int *pResult, const char *pString)
{
*pResult = LOC_UNKNOWN;
int Length = str_length(pString);
if(Length < 2)
{
return true;
}
// ISO continent code. Allow antarctica, but treat it as unknown.
static const char s_apLocations[NUM_LOCS][6] = {
Add client-side HTTP server info Summary ======= The idea of this is that clients will not have to ping each server for server infos which takes long, leaks the client's IP address even to servers the user does not join and is a DoS vector of the game servers for attackers. For the Internet, DDNet and KoG tab, the server list is entirely fetched from the master server, filtering out servers that don't belong into the list. The favorites tab is also supposed to work that way, except for servers that are marked as "also ping this server if it's not in the master server list". The LAN tab continues to broadcast the server info packet to find servers in the LAN. How does it work? ================= The client ships with a list of master server list URLs. On first start, the client checks which of these work and selects the fastest one. Querying the server list is a HTTP GET request on that URL. The response is a JSON document that contains server infos, server addresses as URLs and an approximate location. It can also contain a legacy server list which is a list of bare IP addresses similar to the functionality the old master servers provided via UDP. This allows us to backtrack on the larger update if it won't work out. Lost functionality ================== (also known as user-visible changes) Since the client doesn't ping each server in the list anymore, it has no way of knowing its latency to the servers. This is alleviated a bit by providing an approximate location for each server (continent) so the client only has to know its own location for approximating pings.
2018-07-11 20:46:04 +00:00
"an", // LOC_UNKNOWN
"af", // LOC_AFRICA
"as", // LOC_ASIA
"oc", // LOC_AUSTRALIA
"eu", // LOC_EUROPE
"na", // LOC_NORTH_AMERICA
"sa", // LOC_SOUTH_AMERICA
"as:cn", // LOC_CHINA
Add client-side HTTP server info Summary ======= The idea of this is that clients will not have to ping each server for server infos which takes long, leaks the client's IP address even to servers the user does not join and is a DoS vector of the game servers for attackers. For the Internet, DDNet and KoG tab, the server list is entirely fetched from the master server, filtering out servers that don't belong into the list. The favorites tab is also supposed to work that way, except for servers that are marked as "also ping this server if it's not in the master server list". The LAN tab continues to broadcast the server info packet to find servers in the LAN. How does it work? ================= The client ships with a list of master server list URLs. On first start, the client checks which of these work and selects the fastest one. Querying the server list is a HTTP GET request on that URL. The response is a JSON document that contains server infos, server addresses as URLs and an approximate location. It can also contain a legacy server list which is a list of bare IP addresses similar to the functionality the old master servers provided via UDP. This allows us to backtrack on the larger update if it won't work out. Lost functionality ================== (also known as user-visible changes) Since the client doesn't ping each server in the list anymore, it has no way of knowing its latency to the servers. This is alleviated a bit by providing an approximate location for each server (continent) so the client only has to know its own location for approximating pings.
2018-07-11 20:46:04 +00:00
};
for(int i = std::size(s_apLocations) - 1; i >= 0; i--)
Add client-side HTTP server info Summary ======= The idea of this is that clients will not have to ping each server for server infos which takes long, leaks the client's IP address even to servers the user does not join and is a DoS vector of the game servers for attackers. For the Internet, DDNet and KoG tab, the server list is entirely fetched from the master server, filtering out servers that don't belong into the list. The favorites tab is also supposed to work that way, except for servers that are marked as "also ping this server if it's not in the master server list". The LAN tab continues to broadcast the server info packet to find servers in the LAN. How does it work? ================= The client ships with a list of master server list URLs. On first start, the client checks which of these work and selects the fastest one. Querying the server list is a HTTP GET request on that URL. The response is a JSON document that contains server infos, server addresses as URLs and an approximate location. It can also contain a legacy server list which is a list of bare IP addresses similar to the functionality the old master servers provided via UDP. This allows us to backtrack on the larger update if it won't work out. Lost functionality ================== (also known as user-visible changes) Since the client doesn't ping each server in the list anymore, it has no way of knowing its latency to the servers. This is alleviated a bit by providing an approximate location for each server (continent) so the client only has to know its own location for approximating pings.
2018-07-11 20:46:04 +00:00
{
if(str_startswith(pString, s_apLocations[i]))
Add client-side HTTP server info Summary ======= The idea of this is that clients will not have to ping each server for server infos which takes long, leaks the client's IP address even to servers the user does not join and is a DoS vector of the game servers for attackers. For the Internet, DDNet and KoG tab, the server list is entirely fetched from the master server, filtering out servers that don't belong into the list. The favorites tab is also supposed to work that way, except for servers that are marked as "also ping this server if it's not in the master server list". The LAN tab continues to broadcast the server info packet to find servers in the LAN. How does it work? ================= The client ships with a list of master server list URLs. On first start, the client checks which of these work and selects the fastest one. Querying the server list is a HTTP GET request on that URL. The response is a JSON document that contains server infos, server addresses as URLs and an approximate location. It can also contain a legacy server list which is a list of bare IP addresses similar to the functionality the old master servers provided via UDP. This allows us to backtrack on the larger update if it won't work out. Lost functionality ================== (also known as user-visible changes) Since the client doesn't ping each server in the list anymore, it has no way of knowing its latency to the servers. This is alleviated a bit by providing an approximate location for each server (continent) so the client only has to know its own location for approximating pings.
2018-07-11 20:46:04 +00:00
{
*pResult = i;
return false;
}
}
return true;
}
void CServerInfo::InfoToString(char *pBuffer, int BufferSize) const
{
str_format(
pBuffer,
BufferSize,
"%s\n"
"Address: ddnet://%s\n"
"My IGN: %s\n",
m_aName,
m_aAddress,
g_Config.m_PlayerName);
}