diff --git a/src/Client/Module/Manager.cpp b/src/Client/Module/Manager.cpp index 74bda20a6..041295e0f 100644 --- a/src/Client/Module/Manager.cpp +++ b/src/Client/Module/Manager.cpp @@ -133,6 +133,7 @@ #include "Modules/PitchDisplay/PitchDisplay.hpp" #include "Modules/ExperienceInfo/ExperienceInfo.hpp" #include "Modules/DurabilityWarning/DurabilityWarning.hpp" +#include "Modules/Misc/DynamicFPS/DynamicFPS.hpp" // #include "Modules/PanoramaShader/PanoramaShader.hpp" // Uses CubemapBackgroundScreenRenderHook (render thread safe) #ifdef COMPILE_DOOM diff --git a/src/Client/Module/Modules/Misc/DynamicFPS/DynamicFPS.cpp b/src/Client/Module/Modules/Misc/DynamicFPS/DynamicFPS.cpp new file mode 100644 index 000000000..908b1aae9 --- /dev/null +++ b/src/Client/Module/Modules/Misc/DynamicFPS/DynamicFPS.cpp @@ -0,0 +1,61 @@ +// Updated 1:52 UTC+8 by Leqixn + +#include "DynamicFPS.hpp" +#include "SDK/SDK.hpp" +#include + +void DynamicFPS::onTick() { + if (!enabled.boolValue) return; + + auto context = GameContext::getInstance(); + if (!context || !context->getClientInstance()) return; + + auto options = context->getClientInstance()->getOptions(); + if (!options) return; + + HWND foreground = GetForegroundWindow(); + char className[256]; + if (GetClassNameA(foreground, className, sizeof(className))) { + + bool isGameFocused = (strcmp(className, "ApplicationFrameWindow") == 0 || + strcmp(className, "Windows.UI.Core.CoreWindow") == 0); + + bool shouldThrottle = !isGameFocused || isAFK(); + + if (shouldThrottle) { + if (!isThrottled) { + originalLimit = options->framerateLimit; + isThrottled = true; + } + options->framerateLimit = !isGameFocused ? (int)unfocusedFPS.floatValue : (int)afkFPS.floatValue; + } + else if (isThrottled) { + if (originalLimit.has_value()) { + options->framerateLimit = originalLimit.value(); + } + isThrottled = false; + } + } +} + +bool DynamicFPS::isAFK() const { + LASTINPUTINFO lii = { sizeof(LASTINPUTINFO) }; + if (GetLastInputInfo(&lii)) { + uint64_t idleSeconds = (GetTickCount64() - lii.dwTime) / 1000; + return idleSeconds >= static_cast(afkTimeout.floatValue); + } + return false; +} + +void DynamicFPS::onDisable() { + if (isThrottled && originalLimit.has_value()) { + auto context = GameContext::getInstance(); + if (context && context->getClientInstance()) { + auto options = context->getClientInstance()->getOptions(); + if (options) { + options->framerateLimit = originalLimit.value(); + } + } + } + isThrottled = false; +} diff --git a/src/Client/Module/Modules/Misc/DynamicFPS/DynamicFPS.hpp b/src/Client/Module/Modules/Misc/DynamicFPS/DynamicFPS.hpp new file mode 100644 index 000000000..027cff3b2 --- /dev/null +++ b/src/Client/Module/Modules/Misc/DynamicFPS/DynamicFPS.hpp @@ -0,0 +1,31 @@ +// Updated 1:54 UTC+8 by Leqixn + +#pragma once +#include "Modules/Module.hpp" +#include + +class DynamicFPS : public Module { +public: + DynamicFPS() : Module("DynamicFPS", "Misc", "Reduces FPS while AFK or on other Tab") { + this->name = "DynamicFPS"; + + addSetting(&enabled); + addSetting(&unfocusedFPS); + addSetting(&afkFPS); + addSetting(&afkTimeout); + } + + Setting enabled = Setting("Enabled", true); + Setting unfocusedFPS = Setting("Unfocused FPS", 20.0f, 1.0f, 60.0f); + Setting afkFPS = Setting("AFK FPS", 30.0f, 1.0f, 60.0f); + Setting afkTimeout = Setting("AFK Timeout", 60.0f, 5.0f, 300.0f); + + void onTick() override; + void onDisable() override; + +private: + bool isAFK() const; + + std::optional originalLimit; + bool isThrottled = false; +};