Compare commits

...

8 commits

Author SHA1 Message Date
KebsCS 102d03ef35
Merge 34871095dc into 66fb5d5d7f 2024-09-12 03:11:56 +02: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
KebsCS 34871095dc
Add /unspec command 2024-09-10 00:16:55 +02:00
14 changed files with 128 additions and 138 deletions

View file

@ -2929,6 +2929,24 @@ void CClient::Run()
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
m_pGraphics = CreateEngineGraphicsThreaded();
Kernel()->RegisterInterface(m_pGraphics); // IEngineGraphics
@ -2952,24 +2970,6 @@ void CClient::Run()
CVideo::Init();
#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
m_pTextRender = Kernel()->RequestInterface<IEngineTextRender>();
m_pTextRender->Init();

View file

@ -70,18 +70,18 @@ void CEcon::Init(CConfig *pConfig, IConsole *pConsole, CNetBan *pNetBan)
}
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];
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);
return;
}
BindAddr.type = NETTYPE_ALL;
BindAddr.port = g_Config.m_EcPort;
if(m_NetConsole.Open(BindAddr, pNetBan))
{

View file

@ -1397,22 +1397,10 @@ void CMenus::RenderDemoBrowserButtons(CUIRect ButtonsView, bool WasListboxItemAc
// quick search
{
SetIconMode(true);
CUIRect DemoSearch, SearchIcon;
CUIRect DemoSearch;
ButtonBarTop.VSplitLeft(ButtonBarBottom.h * 21.0f, &DemoSearch, &ButtonBarTop);
ButtonBarTop.VSplitLeft(ButtonBarTop.h / 2.0f, nullptr, &ButtonBarTop);
DemoSearch.VSplitLeft(TextRender()->TextWidth(14.0f, FONT_ICON_MAGNIFYING_GLASS), &SearchIcon, &DemoSearch);
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))
if(Ui()->DoEditBox_Search(&m_DemoSearchInput, &DemoSearch, 14.0f, !Ui()->IsPopupOpen() && m_pClient->m_GameConsole.IsClosed()))
{
RefreshFilteredDemos();
DemolistOnUpdate(false);

View file

@ -683,26 +683,15 @@ void CMenus::RenderServerControl(CUIRect MainView)
// render quick search
CUIRect QuickSearch;
Bottom.VSplitLeft(5.0f, 0, &Bottom);
Bottom.VSplitLeft(5.0f, nullptr, &Bottom);
Bottom.VSplitLeft(250.0f, &QuickSearch, &Bottom);
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);
if(m_ControlPageOpening || (Input()->KeyPress(KEY_F) && Input()->ModifierIsPressed()))
if(m_ControlPageOpening)
{
Ui()->SetActiveItem(&m_FilterInput);
m_ControlPageOpening = false;
Ui()->SetActiveItem(&m_FilterInput);
m_FilterInput.SelectAll();
}
m_FilterInput.SetEmptyText(Localize("Search"));
Ui()->DoClearableEditBox(&m_FilterInput, &QuickSearch, 14.0f);
Ui()->DoEditBox_Search(&m_FilterInput, &QuickSearch, 14.0f, !Ui()->IsPopupOpen() && m_pClient->m_GameConsole.IsClosed());
// call vote
Bottom.VSplitRight(10.0f, &Bottom, 0);

View file

@ -257,7 +257,7 @@ void CMenus::SetNeedSendInfo()
void CMenus::RenderSettingsPlayer(CUIRect MainView)
{
CUIRect TabBar, PlayerTab, DummyTab, ChangeInfo, QuickSearch, QuickSearchClearButton;
CUIRect TabBar, PlayerTab, DummyTab, ChangeInfo, QuickSearch;
MainView.HSplitTop(20.0f, &TabBar, &MainView);
TabBar.VSplitMid(&TabBar, &ChangeInfo, 20.f);
TabBar.VSplitMid(&PlayerTab, &DummyTab);
@ -340,7 +340,10 @@ void CMenus::RenderSettingsPlayer(CUIRect 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;
static CListBox s_ListBox;
s_ListBox.DoStart(48.0f, vpFilteredFlags.size(), 10, 3, OldSelected, &MainView);
@ -378,30 +381,7 @@ void CMenus::RenderSettingsPlayer(CUIRect MainView)
SetNeedSendInfo();
}
// render quick search
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);
Ui()->DoEditBox_Search(&s_FlagFilterInput, &QuickSearch, 14.0f, !Ui()->IsPopupOpen() && m_pClient->m_GameConsole.IsClosed());
}
struct CUISkin
@ -770,8 +750,8 @@ void CMenus::RenderSettingsTee(CUIRect MainView)
CUIRect QuickSearch, DatabaseButton, DirectoryButton, RefreshButton;
MainView.HSplitBottom(20.0f, &MainView, &QuickSearch);
MainView.HSplitBottom(5.0f, &MainView, nullptr);
QuickSearch.VSplitLeft(240.0f, &QuickSearch, &DatabaseButton);
QuickSearch.VSplitRight(10.0f, &QuickSearch, nullptr);
QuickSearch.VSplitLeft(220.0f, &QuickSearch, &DatabaseButton);
DatabaseButton.VSplitLeft(10.0f, nullptr, &DatabaseButton);
DatabaseButton.VSplitLeft(150.0f, &DatabaseButton, &DirectoryButton);
DirectoryButton.VSplitRight(175.0f, nullptr, &DirectoryButton);
DirectoryButton.VSplitRight(25.0f, &DirectoryButton, &RefreshButton);
@ -904,24 +884,10 @@ void CMenus::RenderSettingsTee(CUIRect MainView)
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);
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;
m_SkinListNeedsUpdate = true;
}
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);
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;
m_SkinListNeedsUpdate = true;
}
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)
{
CUIRect TabBar, CustomList, QuickSearch, QuickSearchClearButton, DirectoryButton, ReloadButton;
CUIRect TabBar, CustomList, QuickSearch, DirectoryButton, ReloadButton;
MainView.HSplitTop(20.0f, &TabBar, &MainView);
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);
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;
gs_aInitCustomList[s_CurCustomTab] = true;
}
DirectoryButton.HSplitTop(5.0f, 0, &DirectoryButton);

View file

@ -1004,6 +1004,25 @@ bool CUi::DoClearableEditBox(CLineInput *pLineInput, const CUIRect *pRect, float
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)
{
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 = {});
/**
* 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 = {});
// 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);

View file

@ -376,6 +376,37 @@ void CGameContext::ConToggleSpec(IConsole::IResult *pResult, void *pUserData)
ToggleSpecPause(pResult, pUserData, g_Config.m_SvPauseable ? CPlayer::PAUSE_SPEC : CPlayer::PAUSE_PAUSED);
}
void CGameContext::ConUnspec(IConsole::IResult *pResult, void *pUserData)
{
if(!CheckClientId(pResult->m_ClientId))
return;
CGameContext *pSelf = (CGameContext *)pUserData;
CPlayer *pPlayer = pSelf->m_apPlayers[pResult->m_ClientId];
if(!pPlayer)
return;
int PauseState = pPlayer->IsPaused();
int PauseType = g_Config.m_SvPauseable ? CPlayer::PAUSE_SPEC : CPlayer::PAUSE_PAUSED;
if(PauseState > 0)
{
IServer *pServ = pSelf->Server();
char aBuf[128];
str_format(aBuf, sizeof(aBuf), "You are force-paused for %d seconds.", (PauseState - pServ->Tick()) / pServ->TickSpeed());
pSelf->Console()->Print(IConsole::OUTPUT_LEVEL_STANDARD, "chatresp", aBuf);
}
else
{
if(-PauseState != CPlayer::PAUSE_NONE && PauseType != CPlayer::PAUSE_NONE)
{
pPlayer->Pause(CPlayer::PAUSE_NONE, false);
if(pPlayer->m_SpectatorId != pResult->m_ClientId)
pPlayer->SpectateFreeView();
}
}
}
void CGameContext::ConToggleSpecVoted(IConsole::IResult *pResult, void *pUserData)
{
ToggleSpecPauseVoted(pResult, pUserData, g_Config.m_SvPauseable ? CPlayer::PAUSE_SPEC : CPlayer::PAUSE_PAUSED);

View file

@ -3747,6 +3747,7 @@ void CGameContext::RegisterChatCommands()
Console()->Register("converse", "r[message]", CFGFLAG_CHAT | CFGFLAG_SERVER | CFGFLAG_NONTEEHISTORIC, ConConverse, this, "Converse with the last person you whispered to (private message)");
Console()->Register("pause", "?r[player name]", CFGFLAG_CHAT | CFGFLAG_SERVER, ConTogglePause, this, "Toggles pause");
Console()->Register("spec", "?r[player name]", CFGFLAG_CHAT | CFGFLAG_SERVER, ConToggleSpec, this, "Toggles spec (if not available behaves as /pause)");
Console()->Register("unspec", "", CFGFLAG_CHAT | CFGFLAG_SERVER, ConUnspec, this, "Stops spectating the current player and returns to free view mode");
Console()->Register("pausevoted", "", CFGFLAG_CHAT | CFGFLAG_SERVER, ConTogglePauseVoted, this, "Toggles pause on the currently voted player");
Console()->Register("specvoted", "", CFGFLAG_CHAT | CFGFLAG_SERVER, ConToggleSpecVoted, this, "Toggles spec on the currently voted player");
Console()->Register("dnd", "?i['0'|'1']", CFGFLAG_CHAT | CFGFLAG_SERVER | CFGFLAG_NONTEEHISTORIC, ConDND, this, "Toggle Do Not Disturb (no chat and server messages)");

View file

@ -426,6 +426,7 @@ private:
static void ConTogglePause(IConsole::IResult *pResult, void *pUserData);
static void ConTogglePauseVoted(IConsole::IResult *pResult, void *pUserData);
static void ConToggleSpec(IConsole::IResult *pResult, void *pUserData);
static void ConUnspec(IConsole::IResult *pResult, void *pUserData);
static void ConToggleSpecVoted(IConsole::IResult *pResult, void *pUserData);
static void ConForcePause(IConsole::IResult *pResult, void *pUserData);
static void ConTeamTop5(IConsole::IResult *pResult, void *pUserData);

View file

@ -867,6 +867,12 @@ void CPlayer::SpectatePlayerName(const char *pName)
}
}
void CPlayer::SpectateFreeView()
{
if(m_SpectatorId >= 0)
m_SpectatorId = SPEC_FREEVIEW;
}
void CPlayer::ProcessScoreResult(CScorePlayerResult &Result)
{
if(Result.m_Success) // SQL request was successful

View file

@ -67,6 +67,7 @@ public:
const CCharacter *GetCharacter() const;
void SpectatePlayerName(const char *pName);
void SpectateFreeView();
//---------------------------------------------------------
// this is used for snapping so we know how we can clip the view for the player