Last active
May 2, 2020 11:46
-
-
Save Kaldaien/104cee045671e2b65a8b003ffd9bfa33 to your computer and use it in GitHub Desktop.
Pre-release source code for Sekiro Special K plug-in
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define __SK_SUBSYSTEM__ L"Sekiro Fix" | |
#include <WinSock2.h> | |
#include <ws2tcpip.h> | |
#include <SpecialK/hooks.h> | |
#include <SpecialK/utility.h> | |
#include <SpecialK/parameter.h> | |
sk::ParameterFactory factory; | |
sk::ParameterBool* disable_netcode = nullptr; | |
sk::ParameterBool* uncap_framerate = nullptr; | |
static bool disable_network_code = true; | |
static bool no_frame_limit = false; | |
typedef int (WSAAPI *WSAStartup_pfn)( | |
WORD wVersionRequired, | |
LPWSADATA lpWSAData | |
); | |
WSAStartup_pfn WSAStartup_Original = nullptr; | |
typedef SOCKET (WSAAPI *WSASocketW_pfn)( | |
int af, | |
int type, | |
int protocol, | |
LPWSAPROTOCOL_INFOW lpProtocolInfo, | |
GROUP g, | |
DWORD dwFlags | |
); | |
WSASocketW_pfn WSASocketW_Original = nullptr; | |
typedef DWORD (WSAAPI *WSAWaitForMultipleEvents_pfn)( | |
DWORD cEvents, | |
const WSAEVENT* lphEvents, | |
BOOL fWaitAll, | |
DWORD dwTimeout, | |
BOOL fAlertable | |
); | |
WSAWaitForMultipleEvents_pfn WSAWaitForMultipleEvents_Original = nullptr; | |
typedef INT (WSAAPI *getnameinfo_pfn)( | |
const SOCKADDR* pSockaddr, | |
socklen_t SockaddrLength, | |
PCHAR pNodeBuffer, | |
DWORD NodeBufferSize, | |
PCHAR pServiceBuffer, | |
DWORD ServiceBufferSize, | |
INT Flags | |
); | |
getnameinfo_pfn getnameinfo_Original = nullptr; | |
typedef int (WSAAPI *WSAEnumNetworkEvents_pfn)( | |
SOCKET s, | |
WSAEVENT hEventObject, | |
LPWSANETWORKEVENTS lpNetworkEvents | |
); | |
INT | |
WSAAPI getnameinfo_Detour ( | |
const SOCKADDR* pSockaddr, | |
socklen_t SockaddrLength, | |
PCHAR pNodeBuffer, | |
DWORD NodeBufferSize, | |
PCHAR pServiceBuffer, | |
DWORD ServiceBufferSize, | |
INT Flags ) | |
{ | |
SK_LOG_FIRST_CALL | |
INT iRet = | |
getnameinfo_Original (pSockaddr, SockaddrLength, pNodeBuffer, NodeBufferSize, pServiceBuffer, ServiceBufferSize, Flags); | |
extern void SK_ImGui_Warning (const wchar_t* wszMessage); | |
SK_RunOnce (SK_ImGui_Warning (SK_UTF8ToWideChar (pNodeBuffer).c_str ())); | |
dll_log->Log (L"(Sekiro) : getnameinfo [%hs]", pNodeBuffer); | |
return iRet; | |
} | |
DWORD | |
WSAAPI WSAWaitForMultipleEvents_Detour ( | |
DWORD cEvents, | |
const WSAEVENT* lphEvents, | |
BOOL fWaitAll, | |
DWORD dwTimeout, | |
BOOL fAlertable | |
) | |
{ | |
SK_LOG_FIRST_CALL | |
if (!disable_network_code) | |
dll_log->Log (L" >> Calling Thread for Network Activity: %s", SK_Thread_GetName (GetCurrentThreadId ()).c_str ()); | |
UNREFERENCED_PARAMETER (cEvents); | |
UNREFERENCED_PARAMETER (lphEvents); | |
UNREFERENCED_PARAMETER (fWaitAll); | |
UNREFERENCED_PARAMETER (dwTimeout); | |
UNREFERENCED_PARAMETER (fAlertable); | |
if (disable_network_code) | |
{ | |
return | |
WSA_WAIT_IO_COMPLETION; | |
} | |
return | |
WSAWaitForMultipleEvents_Original ( cEvents, lphEvents, | |
fWaitAll, dwTimeout, | |
fAlertable ); | |
} | |
SOCKET | |
WSAAPI WSASocketW_Detour ( | |
int af, | |
int type, | |
int protocol, | |
LPWSAPROTOCOL_INFOW lpProtocolInfo, | |
GROUP g, | |
DWORD dwFlags) | |
{ | |
SK_LOG_FIRST_CALL | |
if (! disable_network_code) | |
dll_log->Log (L" >> Calling Thread for Network Activity: %s", SK_Thread_GetName (GetCurrentThreadId ()).c_str ()); | |
UNREFERENCED_PARAMETER (af); | |
UNREFERENCED_PARAMETER (type); | |
UNREFERENCED_PARAMETER (protocol); | |
UNREFERENCED_PARAMETER (lpProtocolInfo); | |
UNREFERENCED_PARAMETER (g); | |
UNREFERENCED_PARAMETER (dwFlags); | |
if (disable_network_code) | |
{ | |
return | |
WSAENETDOWN; | |
} | |
return | |
WSASocketW_Original ( af, type, protocol, lpProtocolInfo, | |
g, dwFlags ); | |
} | |
int | |
WSAAPI WSAStartup_Detour ( | |
WORD wVersionRequired, | |
LPWSADATA lpWSAData ) | |
{ | |
SK_LOG_FIRST_CALL | |
if (disable_network_code) | |
{ | |
//WSACleanup (); | |
return WSASYSNOTREADY; | |
} | |
return | |
WSAStartup_Original (wVersionRequired, lpWSAData); | |
} | |
static void* _SK_Sekiro_FOVBase = nullptr; | |
//auto __SK_Sekiro_FOV15 = "\xF3\x0F\x10\x08\xF3\x0F\x59\x0D\x10\xE7\x9B\x02"; | |
//auto __SK_Sekiro_FOV40 = "\xF3\x0F\x10\x08\xF3\x0F\x59\x0D\x14\xE7\x9B\x02"; | |
//auto __SK_Sekiro_FOV75 = "\xF3\x0F\x10\x08\xF3\x0F\x59\x0D\x18\xE7\x9B\x02"; | |
//auto __SK_Sekiro_FOV90 = "\xF3\x0F\x10\x08\xF3\x0F\x59\x0D\x1C\xE7\x9B\x02"; | |
constexpr | |
unsigned char | |
_FrameLockPattern0 [] = | |
{ 0x48, 0x8B, 0xC4, 0x55, 0x53, 0x56, 0x57, 0x41, 0x54, 0x41, 0x55, 0x41, 0x56, 0x41, 0x57, | |
0x48, 0x8D, 0x68, 0xA1, 0x48, 0x81, 0xEC, 0xC8, 0x00, 0x00, 0x00, 0x48, 0xC7, 0x44, 0x24, | |
0x20, 0xFE }; | |
static void* _SK_Sekiro_FrameLockAddr = nullptr; | |
bool SK_Sekiro_UnlimitFramerate (bool set) | |
{ | |
if (_SK_Sekiro_FrameLockAddr != nullptr) | |
{ | |
DWORD dwProtect; | |
// Address is 32-byte aligned; we're good to go and can do this atomically. | |
// | |
VirtualProtect (_SK_Sekiro_FrameLockAddr, 4, PAGE_EXECUTE_READWRITE, &dwProtect); | |
if (set) | |
InterlockedExchange ( (volatile LONG *)_SK_Sekiro_FrameLockAddr, | |
*((uint32_t *)"\xC3\x90\x90\x55") ); | |
else | |
InterlockedExchange ( (volatile LONG *)_SK_Sekiro_FrameLockAddr, | |
*((uint32_t *)"\x48\x8B\xC4\x55") ); | |
VirtualProtect (_SK_Sekiro_FrameLockAddr, 4, dwProtect, &dwProtect); | |
return set; | |
} | |
else | |
return false; | |
} | |
#include <ImGui/ImGui.h> | |
HRESULT | |
STDMETHODCALLTYPE | |
SK_Sekiro_PresentFirstFrame (IDXGISwapChain* pSwapChain, UINT SyncInterval, UINT Flags) | |
{ | |
_SK_Sekiro_FrameLockAddr = | |
SK_ScanAligned (_FrameLockPattern0, 32, nullptr, 32); | |
uncap_framerate = (sk::ParameterBool*) | |
factory.create_parameter <bool> (L"Remove Framerate Limit"); | |
uncap_framerate->register_to_ini ( | |
SK_GetDLLConfig (), | |
L"Sekiro.Framerate", | |
L"Unlimited" | |
); | |
if (! uncap_framerate->load (no_frame_limit)) | |
{ | |
no_frame_limit = false; | |
uncap_framerate->store (false); | |
} | |
SK_Sekiro_UnlimitFramerate (no_frame_limit); | |
} | |
bool | |
SK_Sekiro_PlugInCfg (void) | |
{ | |
ImGui::PushStyleColor (ImGuiCol_Header, ImVec4 (0.90f, 0.40f, 0.40f, 0.45f)); | |
ImGui::PushStyleColor (ImGuiCol_HeaderHovered, ImVec4 (0.90f, 0.45f, 0.45f, 0.80f)); | |
ImGui::PushStyleColor (ImGuiCol_HeaderActive, ImVec4 (0.87f, 0.53f, 0.53f, 0.80f)); | |
if (ImGui::CollapsingHeader (u8"Sekiro™: Shadows Die Twice", ImGuiTreeNodeFlags_DefaultOpen)) | |
{ | |
ImGui::TreePush (""); | |
if (ImGui::Checkbox ("Disable Network Access to Game", &disable_network_code)) | |
{ | |
disable_netcode->store (disable_network_code); | |
SK_GetDLLConfig ()->write ( | |
SK_GetDLLConfig ()->get_filename () | |
); | |
} | |
if (_SK_Sekiro_FrameLockAddr != nullptr) | |
{ | |
ImGui::SameLine (); | |
bool toggle_cap = | |
ImGui::Checkbox ("Uncap Framerate", &no_frame_limit); | |
if (ImGui::IsItemHovered ()) ImGui::SetTooltip ("WARNING: You might break something!"); | |
if (toggle_cap) | |
{ | |
no_frame_limit | |
= SK_Sekiro_UnlimitFramerate (no_frame_limit); | |
uncap_framerate->store (no_frame_limit); | |
SK_GetDLLConfig ()->write ( | |
SK_GetDLLConfig ()->get_filename () | |
); | |
} | |
if (no_frame_limit) | |
{ | |
static auto& rb = | |
SK_GetCurrentRenderBackend (); | |
static UINT num_modes = 0; | |
static std::vector <DXGI_MODE_DESC> | |
modes; | |
static std::string combo_str; | |
static std::vector <int> nominal_refresh; | |
static int current_item = -1; | |
if (num_modes == 0) | |
{ | |
SK_ComPtr <IDXGIOutput> pContainer; | |
IDXGISwapChain* pSwapChain = | |
reinterpret_cast <IDXGISwapChain*> (rb.swapchain.p); | |
if (SUCCEEDED (pSwapChain->GetContainingOutput (&pContainer))) | |
{ | |
DXGI_SWAP_CHAIN_DESC swapDesc = { }; | |
pSwapChain->GetDesc (&swapDesc); | |
pContainer->GetDisplayModeList ( swapDesc.BufferDesc.Format, 0x0, | |
&num_modes, nullptr ); | |
modes.resize (num_modes); | |
if ( SUCCEEDED ( pContainer->GetDisplayModeList ( swapDesc.BufferDesc.Format, 0x0, | |
&num_modes, modes.data () ) ) ) | |
{ | |
int idx = 1; | |
combo_str += "Don't Care"; | |
combo_str += '\0'; | |
for ( auto& mode : modes ) | |
{ | |
if ( mode.Format == swapDesc.BufferDesc.Format && | |
mode.Width == swapDesc.BufferDesc.Width && | |
mode.Height == swapDesc.BufferDesc.Height ) | |
{ | |
combo_str += | |
SK_FormatString ("%6.02f Hz", gsl::narrow_cast <double> (mode.RefreshRate.Numerator) / | |
gsl::narrow_cast <double> (mode.RefreshRate.Denominator)); | |
combo_str += '\0'; | |
nominal_refresh.push_back ( | |
gsl::narrow_cast <UINT> ( | |
std::ceil ( | |
gsl::narrow_cast <double> (mode.RefreshRate.Numerator) / | |
gsl::narrow_cast <double> (mode.RefreshRate.Denominator) | |
) | |
) | |
); | |
if ( config.render.framerate.refresh_rate >= (nominal_refresh.back () - 1) && | |
config.render.framerate.refresh_rate <= (nominal_refresh.back () + 1) ) | |
{ | |
current_item = idx; | |
} | |
++idx; | |
} | |
} | |
combo_str += '\0'; | |
} | |
} | |
} | |
ImGui::SameLine (); | |
bool refresh_change = | |
ImGui::Combo ("Refresh Rate Override###Sekiro_Refresh", ¤t_item, combo_str.c_str ()); | |
if (ImGui::IsItemHovered ()) | |
ImGui::SetTooltip ("You should also enable Special K's framerate limiter..."); | |
if (refresh_change) | |
{ | |
if (current_item > 0) | |
{ | |
int override_rate = | |
nominal_refresh [current_item - 1]; | |
config.render.framerate.refresh_rate = override_rate; | |
} | |
else | |
config.render.framerate.refresh_rate = -1; | |
SK_SaveConfig (); | |
} | |
} | |
} | |
ImGui::TreePop ( ); | |
} | |
ImGui::PopStyleColor (3); | |
return true; | |
} | |
#include <SpecialK/utility.h> | |
void | |
SK_Sekiro_InitPlugin (void) | |
{ | |
//void* pFOVBase = | |
// SK_Scan ( "\xF3\x0F\x10\x08\xF3\x0F\x59\x0D\x0C\xE7\x9B\x02", strlen ( | |
// "\xF3\x0F\x10\x08\xF3\x0F\x59\x0D\x0C\xE7\x9B\x02" ), nullptr ); | |
disable_netcode = (sk::ParameterBool*) | |
factory.create_parameter <bool> (L"Disable Netcode"); | |
disable_netcode->register_to_ini ( | |
SK_GetDLLConfig (), | |
L"Sekiro.Network", | |
L"DisableNetcode" ); | |
if (! disable_netcode->load (disable_network_code)) | |
{ disable_network_code = true; | |
disable_netcode->store (true); | |
} | |
SK_CreateDLLHook2 (L"Ws2_32.dll", "getnameinfo", getnameinfo_Detour, (void **)&getnameinfo_Original); | |
SK_CreateDLLHook2 (L"Ws2_32.dll", "WSAWaitForMultipleEvents", WSAWaitForMultipleEvents_Detour, (void **)&WSAWaitForMultipleEvents_Original); | |
SK_CreateDLLHook2 (L"Ws2_32.dll", "WSASocketW", WSASocketW_Detour, (void **)&WSASocketW_Original); | |
SK_CreateDLLHook2 (L"Ws2_32.dll", "WSAStartup", WSAStartup_Detour, (void **)&WSAStartup_Original); | |
SK_ApplyQueuedHooks (); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment