Skip to content

Instantly share code, notes, and snippets.

@Kaldaien
Last active May 2, 2020 11:46
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Kaldaien/104cee045671e2b65a8b003ffd9bfa33 to your computer and use it in GitHub Desktop.
Save Kaldaien/104cee045671e2b65a8b003ffd9bfa33 to your computer and use it in GitHub Desktop.
Pre-release source code for Sekiro Special K plug-in
#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", &current_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