diff --git a/datasrc/network.py b/datasrc/network.py index 6b6849703..237d5d16a 100644 --- a/datasrc/network.py +++ b/datasrc/network.py @@ -6,7 +6,7 @@ Emoticons = Enum("EMOTICON", ["OOP", "EXCLAMATION", "HEARTS", "DROP", "DOTDOT", Votes = Enum("VOTE", ["UNKNOWN", "START_OP", "START_KICK", "START_SPEC", "END_ABORT", "END_PASS", "END_FAIL"]) ChatModes = Enum("CHAT", ["NONE", "ALL", "TEAM", "WHISPER"]) -PlayerFlags = Flags("PLAYERFLAG", ["ADMIN", "CHATTING", "SCOREBOARD", "READY", "DEAD", "WATCHING"]) +PlayerFlags = Flags("PLAYERFLAG", ["ADMIN", "CHATTING", "SCOREBOARD", "READY", "DEAD", "WATCHING", "BOT"]) GameFlags = Flags("GAMEFLAG", ["TEAMS", "FLAGS", "SURVIVAL"]) GameStateFlags = Flags("GAMESTATEFLAG", ["WARMUP", "SUDDENDEATH", "ROUNDOVER", "GAMEOVER", "PAUSED", "STARTCOUNTDOWN"]) CoreEventFlags = Flags("COREEVENTFLAG", ["GROUND_JUMP", "AIR_JUMP", "HOOK_ATTACH_PLAYER", "HOOK_ATTACH_GROUND", "HOOK_HIT_NOHOOK"]) diff --git a/src/engine/client/client.cpp b/src/engine/client/client.cpp index bc7a9d3fd..1a77525b8 100644 --- a/src/engine/client/client.cpp +++ b/src/engine/client/client.cpp @@ -828,9 +828,9 @@ int CClient::PlayerScoreComp(const void *a, const void *b) { CServerInfo::CClient *p0 = (CServerInfo::CClient *)a; CServerInfo::CClient *p1 = (CServerInfo::CClient *)b; - if(p0->m_Player && !p1->m_Player) + if(!(p0->m_PlayerType&CServerInfo::CClient::PLAYERFLAG_SPEC) && (p1->m_PlayerType&CServerInfo::CClient::PLAYERFLAG_SPEC)) return -1; - if(!p0->m_Player && p1->m_Player) + if((p0->m_PlayerType&CServerInfo::CClient::PLAYERFLAG_SPEC) && !(p1->m_PlayerType&CServerInfo::CClient::PLAYERFLAG_SPEC)) return 1; if(p0->m_Score == p1->m_Score) return 0; @@ -857,6 +857,8 @@ int CClient::UnpackServerInfo(CUnpacker *pUnpacker, CServerInfo *pInfo, int *pTo pInfo->m_MaxPlayers = pUnpacker->GetInt(); pInfo->m_NumClients = pUnpacker->GetInt(); pInfo->m_MaxClients = pUnpacker->GetInt(); + pInfo->m_NumBotPlayers = 0; + pInfo->m_NumBotSpectators = 0; // don't add invalid info to the server browser list if(pInfo->m_NumClients < 0 || pInfo->m_NumClients > MAX_CLIENTS || pInfo->m_MaxClients < 0 || pInfo->m_MaxClients > MAX_CLIENTS || @@ -867,14 +869,30 @@ int CClient::UnpackServerInfo(CUnpacker *pUnpacker, CServerInfo *pInfo, int *pTo if(!pToken) return 0; + int NumPlayers = 0; + int NumClients = 0; for(int i = 0; i < pInfo->m_NumClients; i++) { str_copy(pInfo->m_aClients[i].m_aName, pUnpacker->GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES), sizeof(pInfo->m_aClients[i].m_aName)); str_copy(pInfo->m_aClients[i].m_aClan, pUnpacker->GetString(CUnpacker::SANITIZE_CC|CUnpacker::SKIP_START_WHITESPACES), sizeof(pInfo->m_aClients[i].m_aClan)); pInfo->m_aClients[i].m_Country = pUnpacker->GetInt(); pInfo->m_aClients[i].m_Score = pUnpacker->GetInt(); - pInfo->m_aClients[i].m_Player = pUnpacker->GetInt() != 0 ? true : false; + pInfo->m_aClients[i].m_PlayerType = pUnpacker->GetInt()&CServerInfo::CClient::PLAYERFLAG_MASK; + + if(pInfo->m_aClients[i].m_PlayerType&CServerInfo::CClient::PLAYERFLAG_BOT) + { + if(pInfo->m_aClients[i].m_PlayerType&CServerInfo::CClient::PLAYERFLAG_SPEC) + pInfo->m_NumBotSpectators++; + else + pInfo->m_NumBotPlayers++; + } + + NumClients++; + if(!(pInfo->m_aClients[i].m_PlayerType&CServerInfo::CClient::PLAYERFLAG_SPEC)) + NumPlayers++; } + pInfo->m_NumPlayers = NumPlayers; + pInfo->m_NumClients = NumClients; return 0; } diff --git a/src/engine/client/serverbrowser.cpp b/src/engine/client/serverbrowser.cpp index 411bfb701..4be770acc 100644 --- a/src/engine/client/serverbrowser.cpp +++ b/src/engine/client/serverbrowser.cpp @@ -44,6 +44,7 @@ void CServerBrowser::CServerlist::Clear() m_ServerlistHeap.Reset(); m_NumServers = 0; m_NumPlayers = 0; + m_NumClients = 0; mem_zero(m_aServerlistIp, sizeof(m_aServerlistIp)); } @@ -545,6 +546,7 @@ void CServerBrowser::SetInfo(int ServerlistType, CServerEntry *pEntry, const CSe pEntry->m_Info.m_NetAddr = pEntry->m_Addr; m_aServerlist[ServerlistType].m_NumPlayers += pEntry->m_Info.m_NumPlayers; + m_aServerlist[ServerlistType].m_NumClients += pEntry->m_Info.m_NumClients; pEntry->m_InfoState = CServerEntry::STATE_READY; } diff --git a/src/engine/client/serverbrowser.h b/src/engine/client/serverbrowser.h index 079c49ef9..80ce06f3f 100644 --- a/src/engine/client/serverbrowser.h +++ b/src/engine/client/serverbrowser.h @@ -32,6 +32,7 @@ public: int NumServers() const { return m_aServerlist[m_ActServerlistType].m_NumServers; } int NumPlayers() const { return m_aServerlist[m_ActServerlistType].m_NumPlayers; } + int NumClients() const { return m_aServerlist[m_ActServerlistType].m_NumClients; } const CServerInfo *Get(int Index) const { return &m_aServerlist[m_ActServerlistType].m_ppServerlist[Index]->m_Info; }; int NumSortedServers(int FilterIndex) const { return m_ServerBrowserFilter.GetNumSortedServers(FilterIndex); } @@ -72,6 +73,7 @@ private: public: class CHeap m_ServerlistHeap; + int m_NumClients; int m_NumPlayers; int m_NumServers; int m_NumServerCapacity; diff --git a/src/engine/client/serverbrowser_filter.cpp b/src/engine/client/serverbrowser_filter.cpp index daecfd792..9bb987f6c 100644 --- a/src/engine/client/serverbrowser_filter.cpp +++ b/src/engine/client/serverbrowser_filter.cpp @@ -201,7 +201,15 @@ void CServerBrowserFilter::CServerFilter::Filter() if(!(m_FilterInfo.m_SortHash&IServerBrowser::FILTER_FRIENDS) || m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_FriendState != IFriends::FRIEND_NO) { m_pSortedServerlist[m_NumSortedServers++] = i; - m_NumSortedPlayers += (m_FilterInfo.m_SortHash&IServerBrowser::FILTER_SPECTATORS) ? m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_NumPlayers : m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_NumClients; + + int Count = (m_FilterInfo.m_SortHash&IServerBrowser::FILTER_SPECTATORS) ? m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_NumPlayers : m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_NumClients; + if(m_FilterInfo.m_SortHash&IServerBrowser::FILTER_BOTS) + { + Count -= m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_NumBotPlayers; + if(!(m_FilterInfo.m_SortHash&IServerBrowser::FILTER_SPECTATORS)) + Count -= m_pServerBrowserFilter->m_ppServerlist[i]->m_Info.m_NumBotSpectators; + } + m_NumSortedPlayers += Count; } } } @@ -209,8 +217,9 @@ void CServerBrowserFilter::CServerFilter::Filter() int CServerBrowserFilter::CServerFilter::GetSortHash() const { - int i = g_Config.m_BrSort&0xf; - i |= g_Config.m_BrSortOrder<<4; + int i = g_Config.m_BrSort&0x7; + i |= g_Config.m_BrSortOrder<<3; + if(m_FilterInfo.m_SortHash&IServerBrowser::FILTER_BOTS) i |= 1 << 4; if(m_FilterInfo.m_SortHash&IServerBrowser::FILTER_EMPTY) i |= 1<<5; if(m_FilterInfo.m_SortHash&IServerBrowser::FILTER_FULL) i |= 1<<6; if(m_FilterInfo.m_SortHash&IServerBrowser::FILTER_SPECTATORS) i |= 1<<7; diff --git a/src/engine/server/server.cpp b/src/engine/server/server.cpp index 9bfeb0ec5..620aab87a 100644 --- a/src/engine/server/server.cpp +++ b/src/engine/server/server.cpp @@ -1100,7 +1100,7 @@ void CServer::GenerateServerInfo(CPacker *pPacker, int Token) pPacker->AddString(ClientClan(i), MAX_CLAN_LENGTH); // client clan pPacker->AddInt(m_aClients[i].m_Country); // client country pPacker->AddInt(m_aClients[i].m_Score); // client score - pPacker->AddInt(GameServer()->IsClientPlayer(i)?1:0); // is player? + pPacker->AddInt(GameServer()->IsClientPlayer(i)?0:1); // flag spectator=1, bot=2 (player=0) } } } diff --git a/src/engine/serverbrowser.h b/src/engine/serverbrowser.h index ec4481d8e..6fdbe1353 100644 --- a/src/engine/serverbrowser.h +++ b/src/engine/serverbrowser.h @@ -23,9 +23,16 @@ public: char m_aClan[MAX_CLAN_LENGTH]; int m_Country; int m_Score; - bool m_Player; + int m_PlayerType; int m_FriendState; + + enum + { + PLAYERFLAG_SPEC=1, + PLAYERFLAG_BOT=2, + PLAYERFLAG_MASK=3, + }; }; //int m_SortedIndex; @@ -40,6 +47,8 @@ public: int m_NumClients; int m_MaxPlayers; int m_NumPlayers; + int m_NumBotPlayers; + int m_NumBotSpectators; int m_Flags; int m_ServerLevel; int m_Favorite; @@ -102,6 +111,7 @@ public: FLAG_PURE=2, FLAG_PUREMAP=4, + FILTER_BOTS=16, FILTER_EMPTY=32, FILTER_FULL=64, FILTER_SPECTATORS=128, @@ -123,6 +133,7 @@ public: virtual int NumServers() const = 0; virtual int NumPlayers() const = 0; + virtual int NumClients() const = 0; virtual const CServerInfo *Get(int Index) const = 0; virtual int NumSortedServers(int Index) const = 0; diff --git a/src/game/client/components/menus_browser.cpp b/src/game/client/components/menus_browser.cpp index 2aa193a2a..bc997305b 100644 --- a/src/game/client/components/menus_browser.cpp +++ b/src/game/client/components/menus_browser.cpp @@ -507,10 +507,26 @@ int CMenus::DoBrowserEntry(const void *pID, CUIRect View, const CServerInfo *pEn CServerFilterInfo FilterInfo; pFilter->GetFilter(&FilterInfo); + int Num = (FilterInfo.m_SortHash&IServerBrowser::FILTER_SPECTATORS) ? pEntry->m_NumPlayers : pEntry->m_NumClients; + int Max = (FilterInfo.m_SortHash&IServerBrowser::FILTER_SPECTATORS) ? pEntry->m_MaxPlayers : pEntry->m_MaxClients; if(FilterInfo.m_SortHash&IServerBrowser::FILTER_SPECTATORS) - str_format(aTemp, sizeof(aTemp), "%d/%d", pEntry->m_NumPlayers, pEntry->m_MaxPlayers); - else - str_format(aTemp, sizeof(aTemp), "%d/%d", pEntry->m_NumClients, pEntry->m_MaxClients); + { + int SpecNum = pEntry->m_NumClients - pEntry->m_NumPlayers; + if(pEntry->m_MaxClients - pEntry->m_MaxPlayers < SpecNum) + Max -= SpecNum; + } + if(FilterInfo.m_SortHash&IServerBrowser::FILTER_BOTS) + { + Num -= pEntry->m_NumBotPlayers; + Max -= pEntry->m_NumBotPlayers; + if(!(FilterInfo.m_SortHash&IServerBrowser::FILTER_SPECTATORS)) + { + Num -= pEntry->m_NumBotSpectators; + Max -= pEntry->m_NumBotSpectators; + } + + } + str_format(aTemp, sizeof(aTemp), "%d/%d", Num, Max); if(g_Config.m_BrFilterString[0] && (pEntry->m_QuickSearchHit&IServerBrowser::QUICK_PLAYER)) TextRender()->TextColor(0.4f, 0.4f, 1.0f, TextAlpha); Button.y += 2.0f; @@ -797,7 +813,7 @@ void CMenus::RenderServerbrowserOverlay() Name.VSplitRight(40.0f, &Name, &Clan); // score - if(pInfo->m_aClients[i].m_Player) + if(!(pInfo->m_aClients[i].m_PlayerType&CServerInfo::CClient::PLAYERFLAG_SPEC)) { char aTemp[16]; str_format(aTemp, sizeof(aTemp), "%d", pInfo->m_aClients[i].m_Score); @@ -1141,7 +1157,7 @@ void CMenus::RenderServerbrowserServerList(CUIRect View) CUIRect OriginalView = View; View.y -= s_ScrollValue*ScrollNum*LineH; - int NumPlayers = ServerBrowser()->NumPlayers(); + int NumPlayers = ServerBrowser()->NumClients(); for(int s = 0; s < m_lFilters.size(); s++) { @@ -1362,7 +1378,7 @@ void CMenus::RenderServerbrowserFriendTab(CUIRect View) FriendItem.m_pServerInfo = pEntry; str_copy(FriendItem.m_aName, pEntry->m_aClients[j].m_aName, sizeof(FriendItem.m_aName)); str_copy(FriendItem.m_aClan, pEntry->m_aClients[j].m_aClan, sizeof(FriendItem.m_aClan)); - FriendItem.m_IsPlayer = pEntry->m_aClients[j].m_Player; + FriendItem.m_IsPlayer = !(pEntry->m_aClients[j].m_PlayerType&CServerInfo::CClient::PLAYERFLAG_SPEC); if(pEntry->m_aClients[j].m_FriendState == IFriends::FRIEND_PLAYER) m_lFriendList[0].add(FriendItem); @@ -1596,6 +1612,11 @@ void CMenus::RenderServerbrowserFilterTab(CUIRect View) if(DoButton_CheckBox(&s_BrFilterFriends, Localize("Show friends only"), FilterInfo.m_SortHash&IServerBrowser::FILTER_FRIENDS, &Button)) NewSortHash = FilterInfo.m_SortHash^IServerBrowser::FILTER_FRIENDS; + ServerFilter.HSplitTop(LineSize, &Button, &ServerFilter); + static int s_BrFilterBots = 0; + if(DoButton_CheckBox(&s_BrFilterBots, Localize("Hide Bots"), FilterInfo.m_SortHash&IServerBrowser::FILTER_BOTS, &Button)) + NewSortHash = FilterInfo.m_SortHash^IServerBrowser::FILTER_BOTS; + ServerFilter.HSplitTop(LineSize, &Button, &ServerFilter); static int s_BrFilterPw = 0; if(DoButton_CheckBox(&s_BrFilterPw, Localize("No password"), FilterInfo.m_SortHash&IServerBrowser::FILTER_PW, &Button)) @@ -1900,8 +1921,23 @@ void CMenus::RenderDetailInfo(CUIRect View, const CServerInfo *pInfo) void CMenus::RenderDetailScoreboard(CUIRect View, const CServerInfo *pInfo, int Column) { + // slected filter + CBrowserFilter *pFilter = 0; + for(int i = 0; i < m_lFilters.size(); ++i) + { + if(m_lFilters[i].Extended()) + { + pFilter = &m_lFilters[i]; + m_SelectedFilter = i; + break; + } + } + if(!pFilter) + return; + CServerFilterInfo FilterInfo; + pFilter->GetFilter(&FilterInfo); + // server scoreboard - // CUIRect ServerHeader; CTextCursor Cursor; const float FontSize = 10.0f; int ActColumn = 0; @@ -1911,17 +1947,21 @@ void CMenus::RenderDetailScoreboard(CUIRect View, const CServerInfo *pInfo, int if(pInfo) { CUIRect Row = View; + int Count = 0; for(int i = 0; i < pInfo->m_NumClients; i++) { + if((FilterInfo.m_SortHash&IServerBrowser::FILTER_BOTS) && (pInfo->m_aClients[i].m_PlayerType&CServerInfo::CClient::PLAYERFLAG_BOT)) + continue; + CUIRect Name, Clan, Score, Flag, Icon; - if(i % (16 / Column) == 0) + if(Count % (16 / Column) == 0) { View.VSplitLeft(View.w / (Column - ActColumn), &Row, &View); ActColumn++; } Row.HSplitTop(20.0f, &Name, &Row); - RenderTools()->DrawUIRect(&Name, vec4(1.0f, 1.0f, 1.0f, (i % 2 + 1)*0.05f), CUI::CORNER_ALL, 4.0f); + RenderTools()->DrawUIRect(&Name, vec4(1.0f, 1.0f, 1.0f, (Count % 2 + 1)*0.05f), CUI::CORNER_ALL, 4.0f); // friend if(UI()->DoButtonLogic(&pInfo->m_aClients[i], "", 0, &Name)) @@ -1945,7 +1985,7 @@ void CMenus::RenderDetailScoreboard(CUIRect View, const CServerInfo *pInfo, int Name.HSplitTop(10.0f, &Name, &Clan); // score - if(pInfo->m_aClients[i].m_Player) + if(!(pInfo->m_aClients[i].m_PlayerType&CServerInfo::CClient::PLAYERFLAG_SPEC)) { char aTemp[16]; str_format(aTemp, sizeof(aTemp), "%d", pInfo->m_aClients[i].m_Score); @@ -2002,6 +2042,8 @@ void CMenus::RenderDetailScoreboard(CUIRect View, const CServerInfo *pInfo, int Flag.w = Flag.h*2; vec4 Color(1.0f, 1.0f, 1.0f, 0.5f); m_pClient->m_pCountryFlags->Render(pInfo->m_aClients[i].m_Country, &Color, Flag.x, Flag.y, Flag.w, Flag.h); + + ++Count; } } }