Added late loading option for ASI files

This commit is contained in:
cdozdil committed 2026-06-03 17:08:39 +03:00
1 parent 5e73f8ecd0
commit f5dfe066ae
5 files changed
+79 -4

No files matched your search

+5
View File
@@ -929,6 +929,11 @@ Path=auto
; true or false - Default (auto) is false
LoadAsiPlugins=auto
; Delay before loading late-load *.asi files in plugins folder
; To set an ASI plugin to load late, add -loadlate to the it's filename before the extension, for example "myplugin-loadlate.asi"
; Integer value in seconds - Default (auto) is 30
LateAsiPluginsDelay=auto
; Loads SpecialK64.dll from game's exe folder
; Please create an empty SpecialK.dxgi file next to SpecialK64.dll
; to set SpecialK's working mode, otherwise it will not be activated
+3
View File
@@ -652,6 +652,7 @@ bool Config::Reload(std::filesystem::path iniPath)
LoadSpecialK.set_from_config(readBool("Plugins", "LoadSpecialK"));
LoadReShade.set_from_config(readBool("Plugins", "LoadReShade"));
LoadAsiPlugins.set_from_config(readBool("Plugins", "LoadAsiPlugins"));
LateAsiPluginsDelay.set_from_config(readInt("Plugins", "LateAsiPluginsDelay"));
}
// HDR
@@ -1322,6 +1323,8 @@ bool Config::SaveIni()
ini.SetValue("Plugins", "LoadSpecialK", GetBoolValue(Instance()->LoadSpecialK.value_for_config()).c_str());
ini.SetValue("Plugins", "LoadReShade", GetBoolValue(Instance()->LoadReShade.value_for_config()).c_str());
ini.SetValue("Plugins", "LoadAsiPlugins", GetBoolValue(Instance()->LoadAsiPlugins.value_for_config()).c_str());
ini.SetValue("Plugins", "LateAsiPluginsDelay",
GetIntValue(Instance()->LateAsiPluginsDelay.value_for_config()).c_str());
}
// inputs
+1
View File
@@ -462,6 +462,7 @@ class Config
CustomOptional<bool> LoadSpecialK { false };
CustomOptional<bool> LoadReShade { false };
CustomOptional<bool> LoadAsiPlugins { false };
CustomOptional<int> LateAsiPluginsDelay { 30 };
// Frame Generation
CustomOptional<FGInput> FGInput { FGInput::NoFG };
+68 -1
View File
@@ -49,6 +49,7 @@
#include <version_check.h>
static std::vector<HMODULE> _asiHandles;
static std::vector<std::filesystem::directory_entry> _lateLoadingEntries;
static bool _passThruMode = false;
typedef const char*(CDECL* PFN_wine_get_version)(void);
@@ -226,7 +227,16 @@ void LoadAsiPlugins()
if (ext == L".asi")
{
HMODULE hMod = NtdllProxy::LoadLibraryExW_Ldr(entry.path().c_str(), NULL, 0);
std::wstring fileName = entry.path().filename().wstring();
std::transform(fileName.begin(), fileName.end(), fileName.begin(),
[](wchar_t c) { return std::towlower(c); });
HMODULE hMod = nullptr;
if (fileName.rfind(L"-loadlate") != std::wstring::npos)
_lateLoadingEntries.push_back(entry);
else
hMod = NtdllProxy::LoadLibraryExW_Ldr(entry.path().c_str(), NULL, 0);
if (hMod != nullptr)
{
@@ -266,6 +276,63 @@ void LoadAsiPlugins()
DWORD err = GetLastError();
LOG_ERROR(L"Failed to load: {}, error {:X}", entry.path().wstring(), err);
}
if (_lateLoadingEntries.size() > 0)
{
std::thread(
[]()
{
auto delay = Config::Instance()->LateAsiPluginsDelay.value_or_default();
LOG_INFO("Waiting {} seconds before loading late-load plugins...", delay);
std::this_thread::sleep_for(std::chrono::seconds(delay));
for (const auto& entry : _lateLoadingEntries)
{
HMODULE hMod = NtdllProxy::LoadLibraryExW_Ldr(entry.path().c_str(), NULL, 0);
if (hMod != nullptr)
{
LOG_INFO(L"Loaded late: {}", entry.path().wstring());
_asiHandles.push_back(hMod);
auto init =
(PFN_InitializeASI) KernelBaseProxy::GetProcAddress_()(hMod, "InitializeASI");
auto patchResult =
(PFN_PatchResult) KernelBaseProxy::GetProcAddress_()(hMod, "PatchResult");
if (init != nullptr)
init();
if (patchResult != nullptr)
{
auto pr = patchResult();
if (pr)
{
LOG_INFO("Game patching is successful");
State::Instance().isOptiPatcherSucceed = true;
LOG_INFO("Disabling spoofing");
if (!Config::Instance()->DxgiSpoofing.has_value())
Config::Instance()->DxgiSpoofing.set_volatile_value(false);
if (!Config::Instance()->VulkanSpoofing.has_value())
Config::Instance()->VulkanSpoofing.set_volatile_value(false);
if (!Config::Instance()->VulkanExtensionSpoofing.has_value())
Config::Instance()->VulkanExtensionSpoofing.set_volatile_value(false);
}
}
}
else
{
DWORD err = GetLastError();
LOG_ERROR(L"Failed to load: {}, error {:X}", entry.path().wstring(), err);
}
}
})
.detach();
}
}
}
}
@@ -129,7 +129,7 @@ bool Sl_Inputs_Dx12::setConstants(const sl::Constants& values, uint32_t frameId)
if (!config->FGEnabled.value_or_default())
{
LOG_TRACE("FG not active or paused");
LOG_TRACE("FG not enabled");
return true;
}
else
@@ -140,13 +140,12 @@ bool Sl_Inputs_Dx12::setConstants(const sl::Constants& values, uint32_t frameId)
}
else if (!fgOutput->IsActive() || fgOutput->IsPaused())
{
LOG_TRACE("FG not active or paused");
LOG_TRACE("FG not active or paused (A:{}, P:{})", fgOutput->IsActive(), fgOutput->IsPaused());
return true;
}
}
// Frame data part
// Nukem's function, licensed under GPLv3
auto loadCameraMatrix = [&]()
{