/* (c) Magnus Auvinen. See licence.txt in the root of the distribution for more information. */ /* If you are missing that file, acquire a complete release at teeworlds.com. */ #ifndef ENGINE_CLIENT_SERVERBROWSER_H #define ENGINE_CLIENT_SERVERBROWSER_H #include #include #include #include #include #include #include typedef struct _json_value json_value; class CNetClient; class IConfigManager; class IConsole; class IEngine; class IFavorites; class IFriends; class IServerBrowserHttp; class IServerBrowserPingCache; class IStorage; class IHttp; class CCommunityId { char m_aId[CServerInfo::MAX_COMMUNITY_ID_LENGTH]; public: CCommunityId(const char *pCommunityId) { str_copy(m_aId, pCommunityId); } const char *Id() const { return m_aId; } bool operator==(const CCommunityId &Other) const { return str_comp(Id(), Other.Id()) == 0; } }; template<> struct std::hash { size_t operator()(const CCommunityId &Elem) const noexcept { return str_quickhash(Elem.Id()); } }; class CCommunityCountryName { char m_aName[CServerInfo::MAX_COMMUNITY_COUNTRY_LENGTH]; public: CCommunityCountryName(const char *pCountryName) { str_copy(m_aName, pCountryName); } const char *Name() const { return m_aName; } bool operator==(const CCommunityCountryName &Other) const { return str_comp(Name(), Other.Name()) == 0; } }; template<> struct std::hash { size_t operator()(const CCommunityCountryName &Elem) const noexcept { return str_quickhash(Elem.Name()); } }; class CCommunityTypeName { char m_aName[CServerInfo::MAX_COMMUNITY_TYPE_LENGTH]; public: CCommunityTypeName(const char *pTypeName) { str_copy(m_aName, pTypeName); } const char *Name() const { return m_aName; } bool operator==(const CCommunityTypeName &Other) const { return str_comp(Name(), Other.Name()) == 0; } }; template<> struct std::hash { size_t operator()(const CCommunityTypeName &Elem) const noexcept { return str_quickhash(Elem.Name()); } }; class CCommunityServer { char m_aCommunityId[CServerInfo::MAX_COMMUNITY_ID_LENGTH]; char m_aCountryName[CServerInfo::MAX_COMMUNITY_COUNTRY_LENGTH]; char m_aTypeName[CServerInfo::MAX_COMMUNITY_TYPE_LENGTH]; public: CCommunityServer(const char *pCommunityId, const char *pCountryName, const char *pTypeName) { str_copy(m_aCommunityId, pCommunityId); str_copy(m_aCountryName, pCountryName); str_copy(m_aTypeName, pTypeName); } const char *CommunityId() const { return m_aCommunityId; } const char *CountryName() const { return m_aCountryName; } const char *TypeName() const { return m_aTypeName; } }; class CFavoriteCommunityFilterList : public IFilterList { public: void Add(const char *pCommunityId) override; void Remove(const char *pCommunityId) override; void Clear() override; bool Filtered(const char *pCommunityId) const override; bool Empty() const override; void Clean(const std::vector &vAllowedCommunities); void Save(IConfigManager *pConfigManager) const; const std::vector &Entries() const; private: std::vector m_vEntries; }; class CExcludedCommunityFilterList : public IFilterList { public: void Add(const char *pCommunityId) override; void Remove(const char *pCommunityId) override; void Clear() override; bool Filtered(const char *pCommunityId) const override; bool Empty() const override; void Clean(const std::vector &vAllowedCommunities); void Save(IConfigManager *pConfigManager) const; private: std::unordered_set m_Entries; }; class CExcludedCommunityCountryFilterList : public IFilterList { public: CExcludedCommunityCountryFilterList(std::function()> CurrentCommunitiesGetter) : m_CurrentCommunitiesGetter(CurrentCommunitiesGetter) { } void Add(const char *pCountryName) override; void Add(const char *pCommunityId, const char *pCountryName); void Remove(const char *pCountryName) override; void Remove(const char *pCommunityId, const char *pCountryName); void Clear() override; bool Filtered(const char *pCountryName) const override; bool Empty() const override; void Clean(const std::vector &vAllowedCommunities); void Save(IConfigManager *pConfigManager) const; private: std::function()> m_CurrentCommunitiesGetter; std::unordered_map> m_Entries; }; class CExcludedCommunityTypeFilterList : public IFilterList { public: CExcludedCommunityTypeFilterList(std::function()> CurrentCommunitiesGetter) : m_CurrentCommunitiesGetter(CurrentCommunitiesGetter) { } void Add(const char *pTypeName) override; void Add(const char *pCommunityId, const char *pTypeName); void Remove(const char *pTypeName) override; void Remove(const char *pCommunityId, const char *pTypeName); void Clear() override; bool Filtered(const char *pTypeName) const override; bool Empty() const override; void Clean(const std::vector &vAllowedCommunities); void Save(IConfigManager *pConfigManager) const; private: std::function()> m_CurrentCommunitiesGetter; std::unordered_map> m_Entries; }; class CServerBrowser : public IServerBrowser { public: class CServerEntry { public: int64_t m_RequestTime; bool m_RequestIgnoreInfo; int m_GotInfo; CServerInfo m_Info; CServerEntry *m_pPrevReq; // request list CServerEntry *m_pNextReq; }; CServerBrowser(); virtual ~CServerBrowser(); // interface functions void Refresh(int Type, bool Force = false) override; bool IsRefreshing() const override; bool IsGettingServerlist() const override; int LoadingProgression() const override; void RequestResort() { m_NeedResort = true; } int NumServers() const override { return m_NumServers; } int Players(const CServerInfo &Item) const override; int Max(const CServerInfo &Item) const override; int NumSortedServers() const override { return m_NumSortedServers; } int NumSortedPlayers() const override { return m_NumSortedPlayers; } const CServerInfo *SortedGet(int Index) const override; const json_value *LoadDDNetInfo(); void LoadDDNetInfoJson(); void LoadDDNetLocation(); void LoadDDNetServers(); void UpdateServerFilteredPlayers(CServerInfo *pInfo) const; void UpdateServerFriends(CServerInfo *pInfo) const; void UpdateServerCommunity(CServerInfo *pInfo) const; void UpdateServerRank(CServerInfo *pInfo) const; const char *GetTutorialServer() override; const std::vector &Communities() const override; const CCommunity *Community(const char *pCommunityId) const override; std::vector SelectedCommunities() const override; std::vector FavoriteCommunities() const override; std::vector CurrentCommunities() const override; unsigned CurrentCommunitiesHash() const override; bool DDNetInfoAvailable() const override { return m_pDDNetInfo != nullptr; } int64_t DDNetInfoUpdateTime() const override { return m_DDNetInfoUpdateTime; } CFavoriteCommunityFilterList &FavoriteCommunitiesFilter() override { return m_FavoriteCommunitiesFilter; } CExcludedCommunityFilterList &CommunitiesFilter() override { return m_CommunitiesFilter; } CExcludedCommunityCountryFilterList &CountriesFilter() override { return m_CountriesFilter; } CExcludedCommunityTypeFilterList &TypesFilter() override { return m_TypesFilter; } const CFavoriteCommunityFilterList &FavoriteCommunitiesFilter() const override { return m_FavoriteCommunitiesFilter; } const CExcludedCommunityFilterList &CommunitiesFilter() const override { return m_CommunitiesFilter; } const CExcludedCommunityCountryFilterList &CountriesFilter() const override { return m_CountriesFilter; } const CExcludedCommunityTypeFilterList &TypesFilter() const override { return m_TypesFilter; } void CleanFilters() override; // void Update(); void OnServerInfoUpdate(const NETADDR &Addr, int Token, const CServerInfo *pInfo); void SetHttpInfo(const CServerInfo *pInfo); void RequestCurrentServer(const NETADDR &Addr) const; void RequestCurrentServerWithRandomToken(const NETADDR &Addr, int *pBasicToken, int *pToken) const; void SetCurrentServerPing(const NETADDR &Addr, int Ping); void SetBaseInfo(class CNetClient *pClient, const char *pNetVersion); void OnInit(); void QueueRequest(CServerEntry *pEntry); CServerEntry *Find(const NETADDR &Addr); int GetCurrentType() override { return m_ServerlistType; } bool IsRegistered(const NETADDR &Addr); private: CNetClient *m_pNetClient = nullptr; IConfigManager *m_pConfigManager = nullptr; IConsole *m_pConsole = nullptr; IEngine *m_pEngine = nullptr; IFriends *m_pFriends = nullptr; IFavorites *m_pFavorites = nullptr; IStorage *m_pStorage = nullptr; IHttp *m_pHttpClient = nullptr; char m_aNetVersion[128]; bool m_RefreshingHttp = false; IServerBrowserHttp *m_pHttp = nullptr; IServerBrowserPingCache *m_pPingCache = nullptr; const char *m_pHttpPrevBestUrl = nullptr; CHeap m_ServerlistHeap; CServerEntry **m_ppServerlist; int *m_pSortedServerlist; std::unordered_map m_ByAddr; std::vector m_vCommunities; std::unordered_map m_CommunityServersByAddr; int m_OwnLocation = CServerInfo::LOC_UNKNOWN; CFavoriteCommunityFilterList m_FavoriteCommunitiesFilter; CExcludedCommunityFilterList m_CommunitiesFilter; CExcludedCommunityCountryFilterList m_CountriesFilter; CExcludedCommunityTypeFilterList m_TypesFilter; json_value *m_pDDNetInfo; int64_t m_DDNetInfoUpdateTime; CServerEntry *m_pFirstReqServer; // request list CServerEntry *m_pLastReqServer; int m_NumRequests; bool m_NeedResort; int m_Sorthash; // used instead of g_Config.br_max_requests to get more servers int m_CurrentMaxRequests; int m_NumSortedServers; int m_NumSortedServersCapacity; int m_NumSortedPlayers; int m_NumServers; int m_NumServerCapacity; int m_ServerlistType; int64_t m_BroadcastTime; unsigned char m_aTokenSeed[16]; int GenerateToken(const NETADDR &Addr) const; static int GetBasicToken(int Token); static int GetExtraToken(int Token); // sorting criteria bool SortCompareName(int Index1, int Index2) const; bool SortCompareMap(int Index1, int Index2) const; bool SortComparePing(int Index1, int Index2) const; bool SortCompareGametype(int Index1, int Index2) const; bool SortCompareNumPlayers(int Index1, int Index2) const; bool SortCompareNumClients(int Index1, int Index2) const; bool SortCompareNumPlayersAndPing(int Index1, int Index2) const; // void Filter(); void Sort(); int SortHash() const; void CleanUp(); void UpdateFromHttp(); CServerEntry *Add(const NETADDR *pAddrs, int NumAddrs); void RemoveRequest(CServerEntry *pEntry); void RequestImpl(const NETADDR &Addr, CServerEntry *pEntry, int *pBasicToken, int *pToken, bool RandomToken) const; void RegisterCommands(); static void ConfigSaveCallback(IConfigManager *pConfigManager, void *pUserData); static void Con_AddFavoriteCommunity(IConsole::IResult *pResult, void *pUserData); static void Con_RemoveFavoriteCommunity(IConsole::IResult *pResult, void *pUserData); static void Con_AddExcludedCommunity(IConsole::IResult *pResult, void *pUserData); static void Con_RemoveExcludedCommunity(IConsole::IResult *pResult, void *pUserData); static void Con_AddExcludedCountry(IConsole::IResult *pResult, void *pUserData); static void Con_RemoveExcludedCountry(IConsole::IResult *pResult, void *pUserData); static void Con_AddExcludedType(IConsole::IResult *pResult, void *pUserData); static void Con_RemoveExcludedType(IConsole::IResult *pResult, void *pUserData); static void Con_LeakIpAddress(IConsole::IResult *pResult, void *pUserData); bool ValidateCommunityId(const char *pCommunityId) const; bool ValidateCountryName(const char *pCountryName) const; bool ValidateTypeName(const char *pTypeName) const; void SetInfo(CServerEntry *pEntry, const CServerInfo &Info) const; void SetLatency(NETADDR Addr, int Latency); static bool ParseCommunityFinishes(CCommunity *pCommunity, const json_value &Finishes); static bool ParseCommunityServers(CCommunity *pCommunity, const json_value &Servers); }; #endif