Skip to content

Commit 1421111

Browse files
committed
Add process priority settings and handlers
Add client config options to control process priorities: ClHighProcessPriority (set DDNet process/thread to high) and ClDiscordNormalProcessPriority (lower Discord processes to normal). Implement Windows-specific logic to apply/reset the DDNet process/thread priority and to scan/process Discord executables and set their priority via a background thread. Expose a new component callback OnFocusChange and wire GameClient to detect window focus changes and notify components so priority can be reapplied on focus. Add UI controls in the settings (Performance) to toggle these options and a console chain handler to apply changes immediately. Threading and atomic flags are used to manage the Discord-priority worker; behavior is guarded by platform-specific (Windows) includes and APIs.
1 parent d9f05e4 commit 1421111

8 files changed

Lines changed: 197 additions & 14 deletions

File tree

src/engine/shared/config_variables_entity.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -416,6 +416,9 @@ MACRO_CONFIG_STR(ClPhysicBallsSkin, ec_physic_balls_skin, 24, "volleyball", CFGF
416416
// Moving Tiles
417417
MACRO_CONFIG_INT(ClShowMovingTilesEntities, ec_show_moving_tiles_entities, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Show server-side moving tiles in entities")
418418

419+
MACRO_CONFIG_INT(ClHighProcessPriority, ec_high_process_priority, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Set DDNets process priority to High")
420+
MACRO_CONFIG_INT(ClDiscordNormalProcessPriority, ec_discord_normal_process_priority, 1, 0, 1, CFGFLAG_CLIENT | CFGFLAG_SAVE, "Set Discord process priority to normal")
421+
419422
// Custom variables from my server for the editor
420423
// You can use these if you get my server from https://github.com/FoxNet-DDNet/FoxNet
421424

src/game/client/component.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -305,6 +305,12 @@ class CComponent : public CComponentInterfaces
305305
virtual void OnSelfDeath()
306306
{
307307
}
308+
/*
309+
* Called when the current focus of the window changes, for example when the user alt-tabs out of the game.
310+
*/
311+
virtual void OnFocusChange(bool Focused)
312+
{
313+
}
308314
};
309315

310316
#endif

src/game/client/components/entity/commands.cpp

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -434,11 +434,6 @@ void CEClient::ConReplyLast(IConsole::IResult *pResult, void *pUserData)
434434
pSelf->GameClient()->m_Chat.SendChat(0, Text);
435435
}
436436

437-
void CEClient::ConCrash(IConsole::IResult *pResult, void *pUserData)
438-
{
439-
exit(666);
440-
}
441-
442437
void CEClient::ConSpectateId(IConsole::IResult *pResult, void *pUserData)
443438
{
444439
CEClient *pSelf = (CEClient *)pUserData;
@@ -449,6 +444,11 @@ void CEClient::ConSpectateId(IConsole::IResult *pResult, void *pUserData)
449444
pSelf->GameClient()->m_Chat.SendChat(0, pCmd);
450445
}
451446

447+
void CEClient::ConCrash(IConsole::IResult *pResult, void *pUserData)
448+
{
449+
exit(666);
450+
}
451+
452452
void CEClient::OnConsoleInit()
453453
{
454454
IConfigManager *pConfigManager = Kernel()->RequestInterface<IConfigManager>();
@@ -498,7 +498,7 @@ void CEClient::OnConsoleInit()
498498
Console()->Chain("ec_discord_rpc", ConchainDiscordUpdate, this);
499499
Console()->Chain("ec_discord_map_status", ConchainDiscordUpdate, this);
500500
Console()->Chain("ec_discord_online_status", ConchainDiscordUpdate, this);
501-
Console()->Chain("ec_discord_offline_status", ConchainDiscordUpdate, this);
501+
Console()->Chain("ec_high_process_priority", ConchainDDNetProcessPriority, this);
502502
}
503503

504504
void CEClient::ConchainGoresMode(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData)
@@ -527,6 +527,17 @@ void CEClient::ConchainDiscordUpdate(IConsole::IResult *pResult, void *pUserData
527527
pSelf->Client()->DiscordRPCchange();
528528
}
529529

530+
void CEClient::ConchainDDNetProcessPriority(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData)
531+
{
532+
pfnCallback(pResult, pCallbackUserData);
533+
CEClient *pSelf = (CEClient *)pUserData;
534+
if(pResult->NumArguments())
535+
{
536+
bool Value = pResult->GetInteger(0) != 0;
537+
pSelf->SetDDNetProcessPriority(Value);
538+
}
539+
}
540+
530541
void CEClient::ConfigSaveCallback(IConfigManager *pConfigManager, void *pUserData)
531542
{
532543
CEClient *pThis = (CEClient *)pUserData;

src/game/client/components/entity/entity.cpp

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,23 @@
2828
#include <algorithm>
2929
#include <cmath>
3030
#include <cstring>
31+
#if defined(CONF_FAMILY_WINDOWS)
32+
#include <Windows.h>
33+
#endif
34+
35+
#if defined(CONF_FAMILY_WINDOWS)
36+
#include <TlHelp32.h>
37+
#include <processthreadsapi.h>
38+
#include <base/thread.h>
39+
40+
static bool IsDiscordProcessName(const wchar_t *pProcessName)
41+
{
42+
return _wcsicmp(pProcessName, L"Discord.exe") == 0 ||
43+
_wcsicmp(pProcessName, L"DiscordCanary.exe") == 0 ||
44+
_wcsicmp(pProcessName, L"DiscordPTB.exe") == 0 ||
45+
_wcsicmp(pProcessName, L"DiscordSystemHelper.exe") == 0;
46+
}
47+
#endif
3148

3249
void CEClient::OnChatMessage(int ClientId, int Team, const char *pMsg)
3350
{
@@ -481,8 +498,97 @@ void CEClient::OnShutdown()
481498
g_Config.m_ClKillCounter = m_KillCount;
482499
}
483500

501+
void CEClient::SetDDNetProcessPriority(bool Set)
502+
{
503+
#if defined(CONF_FAMILY_WINDOWS)
504+
if(!SetPriorityClass(GetCurrentProcess(), Set ? HIGH_PRIORITY_CLASS : NORMAL_PRIORITY_CLASS))
505+
{
506+
log_info("entity-client", Set ? "Failed to set process priority" : "Failed to reset process priority");
507+
return;
508+
}
509+
if(!SetThreadPriority(GetCurrentThread(), Set ? THREAD_PRIORITY_HIGHEST : THREAD_PRIORITY_NORMAL))
510+
{
511+
log_info("entity-client", Set ? "Failed to set thread priority" : "Failed to reset thread priority");
512+
return;
513+
}
514+
#endif
515+
}
516+
517+
void CEClient::DiscordPriorityThread(void *pUserData)
518+
{
519+
CEClient *pSelf = (CEClient *)pUserData;
520+
pSelf->SetDiscordProcessesNormalPriority();
521+
pSelf->m_DiscordPriorityDelay.store(time_get() + time_freq() * 30);
522+
pSelf->m_DiscordPriorityThreadRunning.store(false);
523+
}
524+
525+
void CEClient::StartDiscordPriorityThread()
526+
{
527+
// Don't start the thread if it's already running
528+
if(m_DiscordPriorityThreadRunning.load())
529+
return;
530+
531+
if(m_pDiscordPriorityThread)
532+
{
533+
thread_wait(m_pDiscordPriorityThread);
534+
m_pDiscordPriorityThread = nullptr;
535+
}
536+
537+
m_DiscordPriorityDelay.store(0);
538+
m_DiscordPriorityThreadRunning.store(true);
539+
m_pDiscordPriorityThread = thread_init(DiscordPriorityThread, this, "discord-priority");
540+
}
541+
542+
void CEClient::SetDiscordProcessesNormalPriority()
543+
{
544+
#if defined(CONF_FAMILY_WINDOWS)
545+
HANDLE hSnapshot = CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0);
546+
if(hSnapshot == INVALID_HANDLE_VALUE)
547+
{
548+
log_info("entity-client", "Failed to create process snapshot");
549+
return;
550+
}
551+
552+
PROCESSENTRY32 Entry;
553+
mem_zero(&Entry, sizeof(Entry));
554+
Entry.dwSize = sizeof(Entry);
555+
556+
int Changed = 0;
557+
int Failed = 0;
558+
559+
if(Process32First(hSnapshot, &Entry))
560+
{
561+
do
562+
{
563+
if(!IsDiscordProcessName(Entry.szExeFile))
564+
continue;
565+
566+
HANDLE hProcess = OpenProcess(PROCESS_SET_INFORMATION | PROCESS_QUERY_LIMITED_INFORMATION, FALSE, Entry.th32ProcessID);
567+
if(!hProcess)
568+
{
569+
Failed++;
570+
continue;
571+
}
572+
573+
if(SetPriorityClass(hProcess, NORMAL_PRIORITY_CLASS))
574+
Changed++;
575+
else
576+
Failed++;
577+
578+
CloseHandle(hProcess);
579+
} while(Process32Next(hSnapshot, &Entry));
580+
}
581+
582+
CloseHandle(hSnapshot);
583+
#endif
584+
}
585+
484586
void CEClient::OnInit()
485587
{
588+
SetDDNetProcessPriority(g_Config.m_ClHighProcessPriority);
589+
if(g_Config.m_ClDiscordNormalProcessPriority)
590+
StartDiscordPriorityThread();
591+
486592
// On client load
487593
TextRender()->SetCustomFace(g_Config.m_ClCustomFont);
488594

@@ -527,6 +633,12 @@ void CEClient::OnStateChange(int NewState, int OldState)
527633

528634
void CEClient::OnRender()
529635
{
636+
const int64_t DiscordPriorityDelay = m_DiscordPriorityDelay.load();
637+
if(g_Config.m_ClDiscordNormalProcessPriority && !m_DiscordPriorityThreadRunning.load() && DiscordPriorityDelay < time_get())
638+
{
639+
StartDiscordPriorityThread();
640+
}
641+
530642
UpdateRainbow();
531643

532644
if(Client()->State() == CClient::STATE_DEMOPLAYBACK)
@@ -545,3 +657,8 @@ void CEClient::OnSelfDeath()
545657
{
546658
m_KillCount++;
547659
}
660+
661+
void CEClient::OnFocusChange(bool IsFocused)
662+
{
663+
SetDDNetProcessPriority(g_Config.m_ClHighProcessPriority);
664+
}

src/game/client/components/entity/entity.h

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88

99
#include <game/client/component.h>
1010

11+
#include <atomic>
1112
#include <vector>
1213

1314
class CEClient : public CComponent
@@ -58,13 +59,16 @@ class CEClient : public CComponent
5859

5960
static void ConReplyLast(IConsole::IResult *pResult, void *pUserData);
6061

61-
static void ConCrash(IConsole::IResult *pResult, void *pUserData);
62-
6362
static void ConSpectateId(IConsole::IResult *pResult, void *pUserData);
6463

64+
static void ConCrash(IConsole::IResult *pResult, void *pUserData);
65+
6566
static void ConchainGoresMode(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
6667
static void ConchainFastInputs(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
6768
static void ConchainDiscordUpdate(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
69+
static void ConchainDDNetProcessPriority(IConsole::IResult *pResult, void *pUserData, IConsole::FCommandCallback pfnCallback, void *pCallbackUserData);
70+
71+
static void DiscordPriorityThread(void *pUserData);
6872

6973
public:
7074
int m_KillCount;
@@ -131,6 +135,13 @@ class CEClient : public CComponent
131135

132136
bool m_FirstLaunch = false;
133137

138+
void SetDDNetProcessPriority(bool Set);
139+
std::atomic<int64_t> m_DiscordPriorityDelay{0};
140+
std::atomic_bool m_DiscordPriorityThreadRunning{false};
141+
void *m_pDiscordPriorityThread = nullptr;
142+
void StartDiscordPriorityThread();
143+
void SetDiscordProcessesNormalPriority();
144+
134145
private:
135146
int Sizeof() const override { return sizeof(*this); }
136147
void OnInit() override;
@@ -139,6 +150,7 @@ class CEClient : public CComponent
139150
void OnNewSnapshot() override;
140151
void OnShutdown() override;
141152
void OnSelfDeath() override;
153+
void OnFocusChange(bool IsFocused) override;
142154
};
143155

144-
#endif // GAME_CLIENT_COMPONENTS_ENTITY_ENTITY_H
156+
#endif // GAME_CLIENT_COMPONENTS_ENTITY_ENTITY_H

src/game/client/components/entity/menus_entity.cpp

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
21
#include <base/color.h>
32
#include <base/math.h>
43
#include <base/str.h>
@@ -2185,9 +2184,9 @@ void CMenus::RenderSettingsEClient(CUIRect MainView)
21852184
CUIRect Label, Button;
21862185
// left side in settings menu
21872186

2188-
CUIRect Automation, FreezeKill, ChatSettings, GoresMode,
2189-
MenuSettings, FastInput, AntiLatency, FrozenTeeHud, AntiPingSmoothing, GhostTools;
2190-
MainView.VSplitMid(&Automation, &GoresMode);
2187+
CUIRect Automation, FreezeKill, ChatSettings,
2188+
Performance, GoresMode, MenuSettings, FastInput, AntiLatency, FrozenTeeHud, AntiPingSmoothing, GhostTools;
2189+
MainView.VSplitMid(&Automation, &Performance);
21912190

21922191
/* Automation */
21932192
{
@@ -2555,9 +2554,32 @@ void CMenus::RenderSettingsEClient(CUIRect MainView)
25552554
}
25562555
// right side
25572556

2557+
/* Performance */
2558+
{
2559+
Performance.VMargin(5.0f, &Performance);
2560+
Performance.HSplitTop(80.0f, &Performance, &GoresMode);
2561+
if(s_ScrollRegion.AddRect(Performance))
2562+
{
2563+
Performance.Draw(BackgroundColor, IGraphics::CORNER_ALL, CornerRoundness);
2564+
Performance.VMargin(Margin, &Performance);
2565+
2566+
Performance.HSplitTop(HeaderHeight, &Button, &Performance);
2567+
Ui()->DoLabel(&Button, Localize("Performance"), HeaderSize, HeaderAlignment);
2568+
2569+
if(DoButton_CheckBoxAutoVMarginAndSet(&g_Config.m_ClHighProcessPriority, ("High DDNet Process Priority"), &g_Config.m_ClHighProcessPriority, &Performance, LineSize))
2570+
GameClient()->m_EClient.SetDDNetProcessPriority(g_Config.m_ClHighProcessPriority);
2571+
2572+
if(DoButton_CheckBoxAutoVMarginAndSet(&g_Config.m_ClDiscordNormalProcessPriority, ("Lower Discords Process Priority"), &g_Config.m_ClDiscordNormalProcessPriority, &Performance, LineSize))
2573+
{
2574+
if(g_Config.m_ClDiscordNormalProcessPriority)
2575+
GameClient()->m_EClient.StartDiscordPriorityThread();
2576+
}
2577+
}
2578+
}
2579+
25582580
/* Gores Mode */
25592581
{
2560-
GoresMode.VMargin(5.0f, &GoresMode);
2582+
GoresMode.HSplitTop(Margin, nullptr, &GoresMode);
25612583
GoresMode.HSplitTop(120.0f, &GoresMode, &FastInput);
25622584
if(s_ScrollRegion.AddRect(GoresMode))
25632585
{

src/game/client/gameclient.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -870,6 +870,16 @@ void CGameClient::OnRender()
870870
// render all systems
871871
for(auto &pComponent : m_vpAll)
872872
pComponent->OnRender();
873+
IEngineGraphics *pGraphics = ((IEngineGraphics *)Kernel()->RequestInterface<IEngineGraphics>());
874+
if (pGraphics)
875+
{
876+
if(m_WasWindowActive != pGraphics->WindowActive())
877+
{
878+
for(auto &pComponent : m_vpAll)
879+
pComponent->OnFocusChange(pGraphics->WindowActive());
880+
m_WasWindowActive = pGraphics->WindowActive();
881+
}
882+
}
873883

874884
// clear all events/input for this frame
875885
Input()->Clear();

src/game/client/gameclient.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1092,6 +1092,8 @@ class CGameClient : public IGameClient
10921092
int GetClientId(const char *pName) override;
10931093
const char *GetClientName(int ClientId) override { return m_aClients[ClientId].m_aName; }
10941094
vec2 GetCursorWorldPos() const;
1095+
1096+
int m_WasWindowActive = 1;
10951097
};
10961098

10971099
ColorRGBA CalculateNameColor(ColorHSLA TextColorHSL);

0 commit comments

Comments
 (0)