Compare commits

...

10 commits

Author SHA1 Message Date
furo b0db1159f8
Merge e9a2ffde38 into 8d431f8feb 2024-09-12 15:13:49 +02:00
Dennis Felsing 8d431f8feb
Merge pull request #8934 from sjrc6/pr_freeze_stars
Add client setting to restore old freeze stars
2024-09-12 12:31:54 +00:00
Tater 80e2de13da Add client side freeze stars 2024-09-12 04:48:46 -05:00
Dennis Felsing 66fb5d5d7f
Merge pull request #8933 from Robyt3/UI-EditText-Searchable
Extract `CUi::DoEditBox_Search` function for quick search
2024-09-11 21:55:25 +00:00
Robert Müller d3f0c2a156 Extract CUi::DoEditBox_Search function for quick search
Reduce duplicate and inconsistent code for rendering quick search for the demo browser, ingame vote list, player flag, skin, skin 0.7 and asset search.

The quick search and exclude in the server browser are not refactored, as they have additional labels and different alignment, which would make a general function complicated.
2024-09-11 21:33:08 +02:00
Jupeyy d5e81ca78d
Merge pull request #8932 from Robyt3/Client-Network-Before-Graphics
Initialize client networking before graphics
2024-09-11 18:07:20 +00:00
Robert Müller 128ffd2313 Initialize client networking before graphics
Avoid Vulkan crash if the backend is destroyed immediately after being created.

Slightly decreases time of initial black screen before loading menu is rendered.
2024-09-11 19:34:31 +02:00
Dennis Felsing af1b32d296
Merge pull request #8930 from timakro/pr-fix-econ-listening-publicly
Fixes a bug where econ was exposed publicly when ec_bindaddr was set to localhost
2024-09-11 16:50:42 +00:00
Tim Schumacher 0ad1c08c22 Fixes a bug where econ was exposed publicly when ec_bindaddr was set to localhost
Also implements the original intention of 85f5e9c that is to disable
econ if ec_binaddr is invalid.
2024-09-11 18:28:07 +02:00
furo e9a2ffde38 Add verify_url field to master for automatic verification 2024-09-06 16:32:56 +02:00
15 changed files with 141 additions and 138 deletions

View file

@ -621,6 +621,18 @@ void CClient::Connect(const char *pAddress, const char *pPassword)
else else
m_aNetClient[CONN_MAIN].Connect(aConnectAddrs, NumConnectAddrs); m_aNetClient[CONN_MAIN].Connect(aConnectAddrs, NumConnectAddrs);
const CServerBrowser::CServerEntry *pEntry = m_ServerBrowser.Find(aConnectAddrs[0]);
if(pEntry != nullptr && pEntry->m_GotInfo)
{
if(str_length(pEntry->m_Info.m_aVerifyUrl))
{
std::shared_ptr<CHttpRequest> pVerifyGet = HttpGet(pEntry->m_Info.m_aVerifyUrl);
pVerifyGet->Timeout(CTimeout{10000, 0, 500, 10});
pVerifyGet->IpResolve(aConnectAddrs[0].type == NETTYPE_IPV4 ? IPRESOLVE::V4 : IPRESOLVE::V6);
Http()->Run(pVerifyGet);
}
}
m_aNetClient[CONN_MAIN].RefreshStun(); m_aNetClient[CONN_MAIN].RefreshStun();
SetState(IClient::STATE_CONNECTING); SetState(IClient::STATE_CONNECTING);
@ -2929,6 +2941,24 @@ void CClient::Run()
g_UuidManager.DebugDump(); g_UuidManager.DebugDump();
} }
#ifndef CONF_WEBASM
char aNetworkError[256];
if(!InitNetworkClient(aNetworkError, sizeof(aNetworkError)))
{
log_error("client", "%s", aNetworkError);
ShowMessageBox("Network Error", aNetworkError);
return;
}
#endif
if(!m_Http.Init(std::chrono::seconds{1}))
{
const char *pErrorMessage = "Failed to initialize the HTTP client.";
log_error("client", "%s", pErrorMessage);
ShowMessageBox("HTTP Error", pErrorMessage);
return;
}
// init graphics // init graphics
m_pGraphics = CreateEngineGraphicsThreaded(); m_pGraphics = CreateEngineGraphicsThreaded();
Kernel()->RegisterInterface(m_pGraphics); // IEngineGraphics Kernel()->RegisterInterface(m_pGraphics); // IEngineGraphics
@ -2952,24 +2982,6 @@ void CClient::Run()
CVideo::Init(); CVideo::Init();
#endif #endif
#ifndef CONF_WEBASM
char aNetworkError[256];
if(!InitNetworkClient(aNetworkError, sizeof(aNetworkError)))
{
log_error("client", "%s", aNetworkError);
ShowMessageBox("Network Error", aNetworkError);
return;
}
#endif
if(!m_Http.Init(std::chrono::seconds{1}))
{
const char *pErrorMessage = "Failed to initialize the HTTP client.";
log_error("client", "%s", pErrorMessage);
ShowMessageBox("HTTP Error", pErrorMessage);
return;
}
// init text render // init text render
m_pTextRender = Kernel()->RequestInterface<IEngineTextRender>(); m_pTextRender = Kernel()->RequestInterface<IEngineTextRender>();
m_pTextRender->Init(); m_pTextRender->Init();

View file

@ -2357,6 +2357,10 @@ void CServer::UpdateRegisterServerInfo()
JsonWriter.WriteAttribute("requires_login"); JsonWriter.WriteAttribute("requires_login");
JsonWriter.WriteBoolValue(false); JsonWriter.WriteBoolValue(false);
// Client will send a HTTP GET request to the url of sv_verify_url upon connecting
JsonWriter.WriteAttribute("verify_url");
JsonWriter.WriteStrValue(g_Config.m_SvVerifyUrl);
JsonWriter.WriteAttribute("clients"); JsonWriter.WriteAttribute("clients");
JsonWriter.BeginArray(); JsonWriter.BeginArray();

View file

@ -118,6 +118,7 @@ public:
CClient m_aClients[SERVERINFO_MAX_CLIENTS]; CClient m_aClients[SERVERINFO_MAX_CLIENTS];
int m_NumFilteredPlayers; int m_NumFilteredPlayers;
bool m_RequiresLogin; bool m_RequiresLogin;
char m_aVerifyUrl[128];
static int EstimateLatency(int Loc1, int Loc2); static int EstimateLatency(int Loc1, int Loc2);
static bool ParseLocation(int *pResult, const char *pString); static bool ParseLocation(int *pResult, const char *pString);

View file

@ -73,6 +73,7 @@ MACRO_CONFIG_INT(ClShowfps, cl_showfps, 0, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE,
MACRO_CONFIG_INT(ClShowpred, cl_showpred, 0, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show ingame prediction time in milliseconds") MACRO_CONFIG_INT(ClShowpred, cl_showpred, 0, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show ingame prediction time in milliseconds")
MACRO_CONFIG_INT(ClEyeWheel, cl_eye_wheel, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show eye wheel along together with emotes") MACRO_CONFIG_INT(ClEyeWheel, cl_eye_wheel, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show eye wheel along together with emotes")
MACRO_CONFIG_INT(ClEyeDuration, cl_eye_duration, 999999, 1, 999999, CFGFLAG_CLIENT | CFGFLAG_SAVE, "How long the eyes emotes last") MACRO_CONFIG_INT(ClEyeDuration, cl_eye_duration, 999999, 1, 999999, CFGFLAG_CLIENT | CFGFLAG_SAVE, "How long the eyes emotes last")
MACRO_CONFIG_INT(ClFreezeStars, cl_freeze_stars, 0, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show old star particles for frozen tees")
MACRO_CONFIG_INT(ClAirjumpindicator, cl_airjumpindicator, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show the air jump indicator") MACRO_CONFIG_INT(ClAirjumpindicator, cl_airjumpindicator, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show the air jump indicator")
MACRO_CONFIG_INT(ClThreadsoundloading, cl_threadsoundloading, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Load sound files threaded") MACRO_CONFIG_INT(ClThreadsoundloading, cl_threadsoundloading, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Load sound files threaded")
@ -444,6 +445,7 @@ MACRO_CONFIG_INT(SvDnsblBan, sv_dnsbl_ban, 0, 0, 1, CFGFLAG_SERVER, "Automatical
MACRO_CONFIG_STR(SvDnsblBanReason, sv_dnsbl_ban_reason, 128, "VPN detected, try connecting without. Contact admin if mistaken", CFGFLAG_SERVER, "Ban reason for 'sv_dnsbl_ban'") MACRO_CONFIG_STR(SvDnsblBanReason, sv_dnsbl_ban_reason, 128, "VPN detected, try connecting without. Contact admin if mistaken", CFGFLAG_SERVER, "Ban reason for 'sv_dnsbl_ban'")
MACRO_CONFIG_INT(SvDnsblChat, sv_dnsbl_chat, 0, 0, 1, CFGFLAG_SERVER, "Don't allow chat from blacklisted addresses") MACRO_CONFIG_INT(SvDnsblChat, sv_dnsbl_chat, 0, 0, 1, CFGFLAG_SERVER, "Don't allow chat from blacklisted addresses")
MACRO_CONFIG_INT(SvRconVote, sv_rcon_vote, 0, 0, 1, CFGFLAG_SERVER, "Only allow authed clients to call votes") MACRO_CONFIG_INT(SvRconVote, sv_rcon_vote, 0, 0, 1, CFGFLAG_SERVER, "Only allow authed clients to call votes")
MACRO_CONFIG_STR(SvVerifyUrl, sv_verify_url, 128, "", CFGFLAG_SERVER, "A URL which the client will send a HTTP GET request to upon connecting")
MACRO_CONFIG_INT(SvPlayerDemoRecord, sv_player_demo_record, 0, 0, 1, CFGFLAG_SERVER, "Automatically record demos for each player") MACRO_CONFIG_INT(SvPlayerDemoRecord, sv_player_demo_record, 0, 0, 1, CFGFLAG_SERVER, "Automatically record demos for each player")
MACRO_CONFIG_INT(SvDemoChat, sv_demo_chat, 0, 0, 1, CFGFLAG_SERVER, "Record chat for demos") MACRO_CONFIG_INT(SvDemoChat, sv_demo_chat, 0, 0, 1, CFGFLAG_SERVER, "Record chat for demos")

View file

@ -70,18 +70,18 @@ void CEcon::Init(CConfig *pConfig, IConsole *pConsole, CNetBan *pNetBan)
} }
NETADDR BindAddr; NETADDR BindAddr;
if(g_Config.m_EcBindaddr[0] == '\0') if(g_Config.m_EcBindaddr[0] && net_host_lookup(g_Config.m_EcBindaddr, &BindAddr, NETTYPE_ALL) == 0)
{ {
mem_zero(&BindAddr, sizeof(BindAddr)); // got bindaddr
BindAddr.port = g_Config.m_EcPort;
} }
else if(net_host_lookup(g_Config.m_EcBindaddr, &BindAddr, NETTYPE_ALL) != 0) else
{ {
char aBuf[256]; char aBuf[256];
str_format(aBuf, sizeof(aBuf), "The configured bindaddr '%s' cannot be resolved.", g_Config.m_Bindaddr); str_format(aBuf, sizeof(aBuf), "The configured bindaddr '%s' cannot be resolved.", g_Config.m_EcBindaddr);
Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "econ", aBuf); Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "econ", aBuf);
return;
} }
BindAddr.type = NETTYPE_ALL;
BindAddr.port = g_Config.m_EcPort;
if(m_NetConsole.Open(BindAddr, pNetBan)) if(m_NetConsole.Open(BindAddr, pNetBan))
{ {

View file

@ -72,6 +72,7 @@ bool CServerInfo2::FromJsonRaw(CServerInfo2 *pOut, const json_value *pJson)
const json_value &Version = ServerInfo["version"]; const json_value &Version = ServerInfo["version"];
const json_value &Clients = ServerInfo["clients"]; const json_value &Clients = ServerInfo["clients"];
const json_value &RequiresLogin = ServerInfo["requires_login"]; const json_value &RequiresLogin = ServerInfo["requires_login"];
const json_value &VerifyUrl = ServerInfo["verify_url"];
Error = false; Error = false;
Error = Error || MaxClients.type != json_integer; Error = Error || MaxClients.type != json_integer;
@ -103,6 +104,11 @@ bool CServerInfo2::FromJsonRaw(CServerInfo2 *pOut, const json_value *pJson)
{ {
pOut->m_RequiresLogin = RequiresLogin; pOut->m_RequiresLogin = RequiresLogin;
} }
str_copy(pOut->m_aVerifyUrl, "");
if(VerifyUrl.type == json_string)
{
str_copy(pOut->m_aVerifyUrl, VerifyUrl);
}
pOut->m_Passworded = Passworded; pOut->m_Passworded = Passworded;
str_copy(pOut->m_aGameType, GameType); str_copy(pOut->m_aGameType, GameType);
str_copy(pOut->m_aName, Name); str_copy(pOut->m_aName, Name);
@ -239,6 +245,7 @@ CServerInfo2::operator CServerInfo() const
str_copy(Result.m_aName, m_aName); str_copy(Result.m_aName, m_aName);
str_copy(Result.m_aMap, m_aMapName); str_copy(Result.m_aMap, m_aMapName);
str_copy(Result.m_aVersion, m_aVersion); str_copy(Result.m_aVersion, m_aVersion);
str_copy(Result.m_aVerifyUrl, m_aVerifyUrl);
for(int i = 0; i < minimum(m_NumClients, (int)SERVERINFO_MAX_CLIENTS); i++) for(int i = 0; i < minimum(m_NumClients, (int)SERVERINFO_MAX_CLIENTS); i++)
{ {

View file

@ -39,6 +39,7 @@ public:
char m_aMapName[MAX_MAP_LENGTH]; char m_aMapName[MAX_MAP_LENGTH];
char m_aVersion[32]; char m_aVersion[32];
bool m_RequiresLogin; bool m_RequiresLogin;
char m_aVerifyUrl[128];
bool operator==(const CServerInfo2 &Other) const; bool operator==(const CServerInfo2 &Other) const;
bool operator!=(const CServerInfo2 &Other) const { return !(*this == Other); } bool operator!=(const CServerInfo2 &Other) const { return !(*this == Other); }

View file

@ -1397,22 +1397,10 @@ void CMenus::RenderDemoBrowserButtons(CUIRect ButtonsView, bool WasListboxItemAc
// quick search // quick search
{ {
SetIconMode(true); CUIRect DemoSearch;
CUIRect DemoSearch, SearchIcon;
ButtonBarTop.VSplitLeft(ButtonBarBottom.h * 21.0f, &DemoSearch, &ButtonBarTop); ButtonBarTop.VSplitLeft(ButtonBarBottom.h * 21.0f, &DemoSearch, &ButtonBarTop);
ButtonBarTop.VSplitLeft(ButtonBarTop.h / 2.0f, nullptr, &ButtonBarTop); ButtonBarTop.VSplitLeft(ButtonBarTop.h / 2.0f, nullptr, &ButtonBarTop);
DemoSearch.VSplitLeft(TextRender()->TextWidth(14.0f, FONT_ICON_MAGNIFYING_GLASS), &SearchIcon, &DemoSearch); if(Ui()->DoEditBox_Search(&m_DemoSearchInput, &DemoSearch, 14.0f, !Ui()->IsPopupOpen() && m_pClient->m_GameConsole.IsClosed()))
DemoSearch.VSplitLeft(5.0f, nullptr, &DemoSearch);
Ui()->DoLabel(&SearchIcon, FONT_ICON_MAGNIFYING_GLASS, 14.0f, TEXTALIGN_ML);
SetIconMode(false);
m_DemoSearchInput.SetEmptyText(Localize("Search"));
if(Input()->KeyPress(KEY_F) && Input()->ModifierIsPressed())
{
Ui()->SetActiveItem(&m_DemoSearchInput);
m_DemoSearchInput.SelectAll();
}
if(Ui()->DoClearableEditBox(&m_DemoSearchInput, &DemoSearch, 12.0f))
{ {
RefreshFilteredDemos(); RefreshFilteredDemos();
DemolistOnUpdate(false); DemolistOnUpdate(false);

View file

@ -683,26 +683,15 @@ void CMenus::RenderServerControl(CUIRect MainView)
// render quick search // render quick search
CUIRect QuickSearch; CUIRect QuickSearch;
Bottom.VSplitLeft(5.0f, 0, &Bottom); Bottom.VSplitLeft(5.0f, nullptr, &Bottom);
Bottom.VSplitLeft(250.0f, &QuickSearch, &Bottom); Bottom.VSplitLeft(250.0f, &QuickSearch, &Bottom);
TextRender()->SetFontPreset(EFontPreset::ICON_FONT); if(m_ControlPageOpening)
TextRender()->SetRenderFlags(ETextRenderFlags::TEXT_RENDER_FLAG_ONLY_ADVANCE_WIDTH | ETextRenderFlags::TEXT_RENDER_FLAG_NO_X_BEARING | ETextRenderFlags::TEXT_RENDER_FLAG_NO_Y_BEARING | ETextRenderFlags::TEXT_RENDER_FLAG_NO_PIXEL_ALIGMENT | ETextRenderFlags::TEXT_RENDER_FLAG_NO_OVERSIZE);
Ui()->DoLabel(&QuickSearch, FONT_ICON_MAGNIFYING_GLASS, 14.0f, TEXTALIGN_ML);
float SearchWidth = TextRender()->TextWidth(14.0f, FONT_ICON_MAGNIFYING_GLASS, -1, -1.0f);
TextRender()->SetRenderFlags(0);
TextRender()->SetFontPreset(EFontPreset::DEFAULT_FONT);
QuickSearch.VSplitLeft(SearchWidth, 0, &QuickSearch);
QuickSearch.VSplitLeft(5.0f, 0, &QuickSearch);
if(m_ControlPageOpening || (Input()->KeyPress(KEY_F) && Input()->ModifierIsPressed()))
{ {
Ui()->SetActiveItem(&m_FilterInput);
m_ControlPageOpening = false; m_ControlPageOpening = false;
Ui()->SetActiveItem(&m_FilterInput);
m_FilterInput.SelectAll(); m_FilterInput.SelectAll();
} }
m_FilterInput.SetEmptyText(Localize("Search")); Ui()->DoEditBox_Search(&m_FilterInput, &QuickSearch, 14.0f, !Ui()->IsPopupOpen() && m_pClient->m_GameConsole.IsClosed());
Ui()->DoClearableEditBox(&m_FilterInput, &QuickSearch, 14.0f);
// call vote // call vote
Bottom.VSplitRight(10.0f, &Bottom, 0); Bottom.VSplitRight(10.0f, &Bottom, 0);

View file

@ -257,7 +257,7 @@ void CMenus::SetNeedSendInfo()
void CMenus::RenderSettingsPlayer(CUIRect MainView) void CMenus::RenderSettingsPlayer(CUIRect MainView)
{ {
CUIRect TabBar, PlayerTab, DummyTab, ChangeInfo, QuickSearch, QuickSearchClearButton; CUIRect TabBar, PlayerTab, DummyTab, ChangeInfo, QuickSearch;
MainView.HSplitTop(20.0f, &TabBar, &MainView); MainView.HSplitTop(20.0f, &TabBar, &MainView);
TabBar.VSplitMid(&TabBar, &ChangeInfo, 20.f); TabBar.VSplitMid(&TabBar, &ChangeInfo, 20.f);
TabBar.VSplitMid(&PlayerTab, &DummyTab); TabBar.VSplitMid(&PlayerTab, &DummyTab);
@ -340,7 +340,10 @@ void CMenus::RenderSettingsPlayer(CUIRect MainView)
} }
MainView.HSplitTop(10.0f, nullptr, &MainView); MainView.HSplitTop(10.0f, nullptr, &MainView);
MainView.HSplitBottom(25.0f, &MainView, &QuickSearch); MainView.HSplitBottom(20.0f, &MainView, &QuickSearch);
MainView.HSplitBottom(5.0f, &MainView, nullptr);
QuickSearch.VSplitLeft(220.0f, &QuickSearch, nullptr);
int OldSelected = -1; int OldSelected = -1;
static CListBox s_ListBox; static CListBox s_ListBox;
s_ListBox.DoStart(48.0f, vpFilteredFlags.size(), 10, 3, OldSelected, &MainView); s_ListBox.DoStart(48.0f, vpFilteredFlags.size(), 10, 3, OldSelected, &MainView);
@ -378,30 +381,7 @@ void CMenus::RenderSettingsPlayer(CUIRect MainView)
SetNeedSendInfo(); SetNeedSendInfo();
} }
// render quick search Ui()->DoEditBox_Search(&s_FlagFilterInput, &QuickSearch, 14.0f, !Ui()->IsPopupOpen() && m_pClient->m_GameConsole.IsClosed());
QuickSearch.VSplitLeft(240.0f, &QuickSearch, nullptr);
QuickSearch.HSplitTop(5.0f, nullptr, &QuickSearch);
TextRender()->SetFontPreset(EFontPreset::ICON_FONT);
TextRender()->SetRenderFlags(ETextRenderFlags::TEXT_RENDER_FLAG_ONLY_ADVANCE_WIDTH | ETextRenderFlags::TEXT_RENDER_FLAG_NO_X_BEARING | ETextRenderFlags::TEXT_RENDER_FLAG_NO_Y_BEARING | ETextRenderFlags::TEXT_RENDER_FLAG_NO_PIXEL_ALIGMENT | ETextRenderFlags::TEXT_RENDER_FLAG_NO_OVERSIZE);
Ui()->DoLabel(&QuickSearch, FONT_ICON_MAGNIFYING_GLASS, 14.0f, TEXTALIGN_ML);
TextRender()->SetRenderFlags(0);
TextRender()->SetFontPreset(EFontPreset::DEFAULT_FONT);
float SearchWidth = TextRender()->TextWidth(14.0f, FONT_ICON_MAGNIFYING_GLASS, -1, -1.0f);
QuickSearch.VSplitLeft(SearchWidth - 1.5f, nullptr, &QuickSearch);
QuickSearch.VSplitLeft(5.0f, nullptr, &QuickSearch);
QuickSearch.VSplitLeft(QuickSearch.w - 10.0f, &QuickSearch, &QuickSearchClearButton);
TextRender()->SetRenderFlags(0);
TextRender()->SetFontPreset(EFontPreset::DEFAULT_FONT);
if(Input()->KeyPress(KEY_F) && Input()->ModifierIsPressed())
{
Ui()->SetActiveItem(&s_FlagFilterInput);
s_FlagFilterInput.SelectAll();
}
s_FlagFilterInput.SetEmptyText(Localize("Search"));
Ui()->DoClearableEditBox(&s_FlagFilterInput, &QuickSearch, 14.0f);
} }
struct CUISkin struct CUISkin
@ -770,8 +750,8 @@ void CMenus::RenderSettingsTee(CUIRect MainView)
CUIRect QuickSearch, DatabaseButton, DirectoryButton, RefreshButton; CUIRect QuickSearch, DatabaseButton, DirectoryButton, RefreshButton;
MainView.HSplitBottom(20.0f, &MainView, &QuickSearch); MainView.HSplitBottom(20.0f, &MainView, &QuickSearch);
MainView.HSplitBottom(5.0f, &MainView, nullptr); MainView.HSplitBottom(5.0f, &MainView, nullptr);
QuickSearch.VSplitLeft(240.0f, &QuickSearch, &DatabaseButton); QuickSearch.VSplitLeft(220.0f, &QuickSearch, &DatabaseButton);
QuickSearch.VSplitRight(10.0f, &QuickSearch, nullptr); DatabaseButton.VSplitLeft(10.0f, nullptr, &DatabaseButton);
DatabaseButton.VSplitLeft(150.0f, &DatabaseButton, &DirectoryButton); DatabaseButton.VSplitLeft(150.0f, &DatabaseButton, &DirectoryButton);
DirectoryButton.VSplitRight(175.0f, nullptr, &DirectoryButton); DirectoryButton.VSplitRight(175.0f, nullptr, &DirectoryButton);
DirectoryButton.VSplitRight(25.0f, &DirectoryButton, &RefreshButton); DirectoryButton.VSplitRight(25.0f, &DirectoryButton, &RefreshButton);
@ -904,24 +884,10 @@ void CMenus::RenderSettingsTee(CUIRect MainView)
SetNeedSendInfo(); SetNeedSendInfo();
} }
// Quick search static CLineInput s_SkinFilterInput(g_Config.m_ClSkinFilterString, sizeof(g_Config.m_ClSkinFilterString));
if(Ui()->DoEditBox_Search(&s_SkinFilterInput, &QuickSearch, 14.0f, !Ui()->IsPopupOpen() && m_pClient->m_GameConsole.IsClosed()))
{ {
TextRender()->SetFontPreset(EFontPreset::ICON_FONT); m_SkinListNeedsUpdate = true;
TextRender()->SetRenderFlags(ETextRenderFlags::TEXT_RENDER_FLAG_ONLY_ADVANCE_WIDTH | ETextRenderFlags::TEXT_RENDER_FLAG_NO_X_BEARING | ETextRenderFlags::TEXT_RENDER_FLAG_NO_Y_BEARING | ETextRenderFlags::TEXT_RENDER_FLAG_NO_PIXEL_ALIGMENT | ETextRenderFlags::TEXT_RENDER_FLAG_NO_OVERSIZE);
Ui()->DoLabel(&QuickSearch, FONT_ICON_MAGNIFYING_GLASS, 14.0f, TEXTALIGN_ML);
float SearchWidth = TextRender()->TextWidth(14.0f, FONT_ICON_MAGNIFYING_GLASS, -1, -1.0f);
TextRender()->SetRenderFlags(0);
TextRender()->SetFontPreset(EFontPreset::DEFAULT_FONT);
QuickSearch.VSplitLeft(SearchWidth + 5.0f, nullptr, &QuickSearch);
static CLineInput s_SkinFilterInput(g_Config.m_ClSkinFilterString, sizeof(g_Config.m_ClSkinFilterString));
if(Input()->KeyPress(KEY_F) && Input()->ModifierIsPressed())
{
Ui()->SetActiveItem(&s_SkinFilterInput);
s_SkinFilterInput.SelectAll();
}
s_SkinFilterInput.SetEmptyText(Localize("Search"));
if(Ui()->DoClearableEditBox(&s_SkinFilterInput, &QuickSearch, 14.0f))
m_SkinListNeedsUpdate = true;
} }
static CButtonContainer s_SkinDatabaseButton; static CButtonContainer s_SkinDatabaseButton;

View file

@ -282,24 +282,10 @@ void CMenus::RenderSettingsTee7(CUIRect MainView)
} }
} }
// Quick search static CLineInput s_SkinFilterInput(g_Config.m_ClSkinFilterString, sizeof(g_Config.m_ClSkinFilterString));
if(Ui()->DoEditBox_Search(&s_SkinFilterInput, &QuickSearch, 14.0f, !Ui()->IsPopupOpen() && m_pClient->m_GameConsole.IsClosed()))
{ {
TextRender()->SetFontPreset(EFontPreset::ICON_FONT); m_SkinListNeedsUpdate = true;
TextRender()->SetRenderFlags(ETextRenderFlags::TEXT_RENDER_FLAG_ONLY_ADVANCE_WIDTH | ETextRenderFlags::TEXT_RENDER_FLAG_NO_X_BEARING | ETextRenderFlags::TEXT_RENDER_FLAG_NO_Y_BEARING | ETextRenderFlags::TEXT_RENDER_FLAG_NO_PIXEL_ALIGMENT | ETextRenderFlags::TEXT_RENDER_FLAG_NO_OVERSIZE);
Ui()->DoLabel(&QuickSearch, FontIcons::FONT_ICON_MAGNIFYING_GLASS, 14.0f, TEXTALIGN_ML);
float SearchWidth = TextRender()->TextWidth(14.0f, FontIcons::FONT_ICON_MAGNIFYING_GLASS, -1, -1.0f);
TextRender()->SetRenderFlags(0);
TextRender()->SetFontPreset(EFontPreset::DEFAULT_FONT);
QuickSearch.VSplitLeft(SearchWidth + 5.0f, nullptr, &QuickSearch);
static CLineInput s_SkinFilterInput(g_Config.m_ClSkinFilterString, sizeof(g_Config.m_ClSkinFilterString));
if(Input()->KeyPress(KEY_F) && Input()->ModifierIsPressed())
{
Ui()->SetActiveItem(&s_SkinFilterInput);
s_SkinFilterInput.SelectAll();
}
s_SkinFilterInput.SetEmptyText(Localize("Search"));
if(Ui()->DoClearableEditBox(&s_SkinFilterInput, &QuickSearch, 14.0f))
m_SkinListNeedsUpdate = true;
} }
static CButtonContainer s_DirectoryButton; static CButtonContainer s_DirectoryButton;

View file

@ -352,7 +352,7 @@ int InitSearchList(std::vector<const TName *> &vpSearchList, std::vector<TName>
void CMenus::RenderSettingsCustom(CUIRect MainView) void CMenus::RenderSettingsCustom(CUIRect MainView)
{ {
CUIRect TabBar, CustomList, QuickSearch, QuickSearchClearButton, DirectoryButton, ReloadButton; CUIRect TabBar, CustomList, QuickSearch, DirectoryButton, ReloadButton;
MainView.HSplitTop(20.0f, &TabBar, &MainView); MainView.HSplitTop(20.0f, &TabBar, &MainView);
const float TabWidth = TabBar.w / NUMBER_OF_ASSETS_TABS; const float TabWidth = TabBar.w / NUMBER_OF_ASSETS_TABS;
@ -599,29 +599,13 @@ void CMenus::RenderSettingsCustom(CUIRect MainView)
} }
} }
// render quick search // Quick search
MainView.HSplitBottom(ms_ButtonHeight, &MainView, &QuickSearch);
QuickSearch.VSplitLeft(220.0f, &QuickSearch, &DirectoryButton);
QuickSearch.HSplitTop(5.0f, nullptr, &QuickSearch);
if(Ui()->DoEditBox_Search(&s_aFilterInputs[s_CurCustomTab], &QuickSearch, 14.0f, !Ui()->IsPopupOpen() && m_pClient->m_GameConsole.IsClosed()))
{ {
MainView.HSplitBottom(ms_ButtonHeight, &MainView, &QuickSearch); gs_aInitCustomList[s_CurCustomTab] = true;
QuickSearch.VSplitLeft(240.0f, &QuickSearch, &DirectoryButton);
QuickSearch.HSplitTop(5.0f, 0, &QuickSearch);
TextRender()->SetFontPreset(EFontPreset::ICON_FONT);
TextRender()->SetRenderFlags(ETextRenderFlags::TEXT_RENDER_FLAG_ONLY_ADVANCE_WIDTH | ETextRenderFlags::TEXT_RENDER_FLAG_NO_X_BEARING | ETextRenderFlags::TEXT_RENDER_FLAG_NO_Y_BEARING | ETextRenderFlags::TEXT_RENDER_FLAG_NO_PIXEL_ALIGMENT | ETextRenderFlags::TEXT_RENDER_FLAG_NO_OVERSIZE);
Ui()->DoLabel(&QuickSearch, FONT_ICON_MAGNIFYING_GLASS, 14.0f, TEXTALIGN_ML);
float SearchWidth = TextRender()->TextWidth(14.0f, FONT_ICON_MAGNIFYING_GLASS, -1, -1.0f);
TextRender()->SetRenderFlags(0);
TextRender()->SetFontPreset(EFontPreset::DEFAULT_FONT);
QuickSearch.VSplitLeft(SearchWidth, 0, &QuickSearch);
QuickSearch.VSplitLeft(5.0f, 0, &QuickSearch);
QuickSearch.VSplitLeft(QuickSearch.w - 10.0f, &QuickSearch, &QuickSearchClearButton);
if(Input()->KeyPress(KEY_F) && Input()->ModifierIsPressed())
{
Ui()->SetActiveItem(&s_aFilterInputs[s_CurCustomTab]);
s_aFilterInputs[s_CurCustomTab].SelectAll();
}
s_aFilterInputs[s_CurCustomTab].SetEmptyText(Localize("Search"));
if(Ui()->DoClearableEditBox(&s_aFilterInputs[s_CurCustomTab], &QuickSearch, 14.0f))
gs_aInitCustomList[s_CurCustomTab] = true;
} }
DirectoryButton.HSplitTop(5.0f, 0, &DirectoryButton); DirectoryButton.HSplitTop(5.0f, 0, &DirectoryButton);

View file

@ -2071,6 +2071,32 @@ void CGameClient::OnNewSnapshot()
m_Effects.AirJump(Pos, Alpha); m_Effects.AirJump(Pos, Alpha);
} }
if(g_Config.m_ClFreezeStars && !m_SuppressEvents)
{
for(auto &Character : m_Snap.m_aCharacters)
{
if(Character.m_Active && Character.m_HasExtendedData && Character.m_PrevExtendedData)
{
int FreezeTimeNow = Character.m_ExtendedData.m_FreezeEnd - Client()->GameTick(g_Config.m_ClDummy);
int FreezeTimePrev = Character.m_PrevExtendedData->m_FreezeEnd - Client()->PrevGameTick(g_Config.m_ClDummy);
vec2 Pos = vec2(Character.m_Cur.m_X, Character.m_Cur.m_Y);
int StarsNow = (FreezeTimeNow + 1) / Client()->GameTickSpeed();
int StarsPrev = (FreezeTimePrev + 1) / Client()->GameTickSpeed();
if(StarsNow < StarsPrev || (StarsPrev == 0 && StarsNow > 0))
{
int Amount = StarsNow + 1;
float Mid = 3 * pi / 2;
float Min = Mid - pi / 3;
float Max = Mid + pi / 3;
for(int j = 0; j < Amount; j++)
{
float Angle = mix(Min, Max, (j + 1) / (float)(Amount + 2));
m_Effects.DamageIndicator(Pos, direction(Angle));
}
}
}
}
}
if(m_Snap.m_LocalClientId != m_PrevLocalId) if(m_Snap.m_LocalClientId != m_PrevLocalId)
m_PredictedDummyId = m_PrevLocalId; m_PredictedDummyId = m_PrevLocalId;
m_PrevLocalId = m_Snap.m_LocalClientId; m_PrevLocalId = m_Snap.m_LocalClientId;

View file

@ -1004,6 +1004,25 @@ bool CUi::DoClearableEditBox(CLineInput *pLineInput, const CUIRect *pRect, float
return ReturnValue; return ReturnValue;
} }
bool CUi::DoEditBox_Search(CLineInput *pLineInput, const CUIRect *pRect, float FontSize, bool HotkeyEnabled)
{
CUIRect QuickSearch = *pRect;
TextRender()->SetFontPreset(EFontPreset::ICON_FONT);
TextRender()->SetRenderFlags(ETextRenderFlags::TEXT_RENDER_FLAG_ONLY_ADVANCE_WIDTH | ETextRenderFlags::TEXT_RENDER_FLAG_NO_X_BEARING | ETextRenderFlags::TEXT_RENDER_FLAG_NO_Y_BEARING | ETextRenderFlags::TEXT_RENDER_FLAG_NO_PIXEL_ALIGMENT | ETextRenderFlags::TEXT_RENDER_FLAG_NO_OVERSIZE);
DoLabel(&QuickSearch, FONT_ICON_MAGNIFYING_GLASS, FontSize, TEXTALIGN_ML);
const float SearchWidth = TextRender()->TextWidth(FontSize, FONT_ICON_MAGNIFYING_GLASS);
TextRender()->SetRenderFlags(0);
TextRender()->SetFontPreset(EFontPreset::DEFAULT_FONT);
QuickSearch.VSplitLeft(SearchWidth + 5.0f, nullptr, &QuickSearch);
if(HotkeyEnabled && Input()->ModifierIsPressed() && Input()->KeyPress(KEY_F))
{
SetActiveItem(pLineInput);
pLineInput->SelectAll();
}
pLineInput->SetEmptyText(Localize("Search"));
return DoClearableEditBox(pLineInput, &QuickSearch, FontSize);
}
int CUi::DoButton_Menu(CUIElement &UIElement, const CButtonContainer *pId, const std::function<const char *()> &GetTextLambda, const CUIRect *pRect, const SMenuButtonProperties &Props) int CUi::DoButton_Menu(CUIElement &UIElement, const CButtonContainer *pId, const std::function<const char *()> &GetTextLambda, const CUIRect *pRect, const SMenuButtonProperties &Props)
{ {
CUIRect Text = *pRect, DropDownIcon; CUIRect Text = *pRect, DropDownIcon;

View file

@ -603,6 +603,24 @@ public:
*/ */
bool DoClearableEditBox(CLineInput *pLineInput, const CUIRect *pRect, float FontSize, int Corners = IGraphics::CORNER_ALL, const std::vector<STextColorSplit> &vColorSplits = {}); bool DoClearableEditBox(CLineInput *pLineInput, const CUIRect *pRect, float FontSize, int Corners = IGraphics::CORNER_ALL, const std::vector<STextColorSplit> &vColorSplits = {});
/**
* Creates an input field with a search icon and a clear [x] button attached to it.
* The input will have default text "Search" and the hotkey Ctrl+F can be used to activate the input.
*
* @see DoEditBox
*
* @param pLineInput This pointer will be stored and written to on next user input.
* So you can not pass in a pointer that goes out of scope such as a local variable.
* Pass in either a member variable of the current class or a static variable.
* For example ```static CLineInputBuffered<IO_MAX_PATH_LENGTH> s_MyInput;```
* @param pRect the UI rect it will attach to
* @param FontSize Size of the font (`10.0f`, `12.0f` and `14.0f` are commonly used here)
* @param HotkeyEnabled Whether the hotkey to enable this editbox is currently enabled.
*
* @return true if the value of the input field changed since the last call.
*/
bool DoEditBox_Search(CLineInput *pLineInput, const CUIRect *pRect, float FontSize, bool HotkeyEnabled);
int DoButton_Menu(CUIElement &UIElement, const CButtonContainer *pId, const std::function<const char *()> &GetTextLambda, const CUIRect *pRect, const SMenuButtonProperties &Props = {}); int DoButton_Menu(CUIElement &UIElement, const CButtonContainer *pId, const std::function<const char *()> &GetTextLambda, const CUIRect *pRect, const SMenuButtonProperties &Props = {});
// only used for popup menus // only used for popup menus
int DoButton_PopupMenu(CButtonContainer *pButtonContainer, const char *pText, const CUIRect *pRect, float Size, int Align, float Padding = 0.0f, bool TransparentInactive = false, bool Enabled = true); int DoButton_PopupMenu(CButtonContainer *pButtonContainer, const char *pText, const CUIRect *pRect, float Size, int Align, float Padding = 0.0f, bool TransparentInactive = false, bool Enabled = true);