diff --git a/dist/config.toml b/dist/config.toml index 0b05ab5..8677ce1 100644 --- a/dist/config.toml +++ b/dist/config.toml @@ -8,9 +8,6 @@ country_code = "JPN" [patches] version = "auto" -res = { x = 1920, y = 1080 } -windowed = false -vsync = false unlock_songs = true [patches.chn00] @@ -19,6 +16,12 @@ unlock_songs = true mode_collabo025 = false mode_collabo026 = false +[graphics] +res = { x = 1920, y = 1080 } +windowed = false +vsync = false +fpslimit = 120 + [audio] wasapi_shared = true asio = false diff --git a/meson.build b/meson.build index 93aa265..c3ce6f4 100644 --- a/meson.build +++ b/meson.build @@ -78,9 +78,12 @@ library( 'src/helpers.cpp', 'src/poll.cpp', 'src/bnusio.cpp', + 'src/patches/amauth.cpp', + 'src/patches/dxgi.cpp', + 'src/patches/fpslimiter.cpp', 'src/patches/audio.cpp', 'src/patches/qr.cpp', - 'src/patches/amauth.cpp', + 'src/patches/layeredfs.cpp', 'src/patches/versions/JPN00.cpp', 'src/patches/versions/JPN08.cpp', 'src/patches/versions/JPN39.cpp', diff --git a/src/constants.h b/src/constants.h index 78063c3..33222f1 100644 --- a/src/constants.h +++ b/src/constants.h @@ -1,8 +1,6 @@ #pragma once #include -#define crcPOLY 0x82f63b78 - enum class GameVersion : XXH64_hash_t { UNKNOWN = 0, JPN00 = 0x4C07355966D815FB, diff --git a/src/dllmain.cpp b/src/dllmain.cpp index 98985ec..181c5e3 100644 --- a/src/dllmain.cpp +++ b/src/dllmain.cpp @@ -3,185 +3,58 @@ #include "helpers.h" #include "patches/patches.h" #include "poll.h" -#include -#include GameVersion gameVersion = GameVersion::UNKNOWN; std::vector plugins; u64 song_data_size = 1024 * 1024 * 64; void *song_data; -std::string server = "127.0.0.1"; -std::string port = "54430"; -std::string chassisId = "284111080000"; -std::string shopId = "TAIKO ARCADE LOADER"; -std::string gameVerNum = "00.00"; -std::string countryCode = "JPN"; -char fullAddress[256] = {'\0'}; -char placeId[16] = {'\0'}; -char accessCode1[21] = "00000000000000000001"; -char accessCode2[21] = "00000000000000000002"; -char chipId1[33] = "00000000000000000000000000000001"; -char chipId2[33] = "00000000000000000000000000000002"; -bool autoIME = false; -bool jpLayout = false; -bool useLayeredFs = false; +std::string server = "127.0.0.1"; +std::string port = "54430"; +std::string chassisId = "284111080000"; +std::string shopId = "TAIKO ARCADE LOADER"; +std::string gameVerNum = "00.00"; +std::string countryCode = "JPN"; +char fullAddress[256] = {'\0'}; +char placeId[16] = {'\0'}; +char accessCode1[21] = "00000000000000000001"; +char accessCode2[21] = "00000000000000000002"; +char chipId1[33] = "00000000000000000000000000000001"; +char chipId2[33] = "00000000000000000000000000000002"; +bool windowed = false; +bool autoIME = false; +bool jpLayout = false; +bool useLayeredFS = false; std::string datatableKey = "0000000000000000000000000000000000000000000000000000000000000000"; std::string fumenKey = "0000000000000000000000000000000000000000000000000000000000000000"; -uint32_t crc32c(uint32_t crc, const unsigned char *buf, size_t len) -{ - int k; - - crc = ~crc; - while (len--) { - crc ^= *buf++; - for (k = 0; k < 8; k++) - crc = (crc >> 1) ^ (crcPOLY & (0 - (crc & 1))); - } - return ~crc; -} - -bool checkCRC(const std::string &path, uint32_t crc){ - if (std::filesystem::exists(path)){ - std::filesystem::path crc_path = path; - crc_path.replace_extension(".crc"); - std::ifstream crc_file(crc_path, std::ios::binary); - std::string crc_content((std::istreambuf_iterator(crc_file)), std::istreambuf_iterator()); - return std::stoul(crc_content) != crc; - } - return 1; -} - -void create_directories(const std::string &path) { - size_t pos = 0; - std::string delimiter = "\\"; - std::string current_path; - - while ((pos = path.find(delimiter, pos)) != std::string::npos) { - current_path = path.substr(0, pos++); - if (!current_path.empty() && !CreateDirectory(current_path.c_str(), NULL) && GetLastError() != ERROR_ALREADY_EXISTS) { - throw std::runtime_error("Error creating directory: " + current_path); - } - } - if (!path.empty() && !CreateDirectory(path.c_str(), NULL) && GetLastError() != ERROR_ALREADY_EXISTS) { - throw std::runtime_error("Error creating directory: " + path); - } -} - -void write_file(const std::string &filename, const std::vector &data, uint32_t original_crc) { - std::string::size_type pos = filename.find_last_of("\\"); - if (pos != std::string::npos) { - std::string directory = filename.substr(0, pos); - create_directories(directory); - } - - std::filesystem::path crc_path = filename; - crc_path.replace_extension(".crc"); - std::ofstream crc_file(crc_path.string()); - crc_file << std::to_string(original_crc); - crc_file.close(); - - std::ofstream file(filename, std::ios::binary); - file.write(reinterpret_cast(data.data()), data.size()); -} - -std::vector gzip_compress(const std::vector& data) { - z_stream deflate_stream; - deflate_stream.zalloc = Z_NULL; - deflate_stream.zfree = Z_NULL; - deflate_stream.opaque = Z_NULL; - deflate_stream.avail_in = data.size(); - deflate_stream.next_in = const_cast(data.data()); - - deflateInit2(&deflate_stream, Z_BEST_COMPRESSION, Z_DEFLATED, 15 + 16, 8, Z_DEFAULT_STRATEGY); - - std::vector compressed_data; - compressed_data.resize(deflateBound(&deflate_stream, data.size())); - - deflate_stream.avail_out = compressed_data.size(); - deflate_stream.next_out = compressed_data.data(); - - deflate(&deflate_stream, Z_FINISH); - deflateEnd(&deflate_stream); - - compressed_data.resize(deflate_stream.total_out); - return compressed_data; -} - -// Function to pad data according to PKCS7 -std::vector pad_data(const std::vector &data, size_t block_size) { - size_t padding = block_size - (data.size() % block_size); - std::vector padded_data = data; - padded_data.insert(padded_data.end(), padding, static_cast(padding)); - return padded_data; -} - -std::vector hex_to_bytes(const std::string &hex) { - std::vector bytes; - for (size_t i = 0; i < hex.length(); i += 2) { - uint8_t byte = static_cast(std::stoi(hex.substr(i, 2), nullptr, 16)); - bytes.push_back(byte); - } - return bytes; -} - -std::vector encrypt_file(const std::string &input_file, const std::string &hex_key) { - // Convert the key from hex to bytes - std::vector key = hex_to_bytes(hex_key); - - // Generate the 128 bits IV - std::vector iv(16); - for (size_t i = 0; i < iv.size(); ++i) iv[i] = static_cast(i); - - // Read the entire file into memory - std::ifstream file(input_file, std::ios::binary); - - std::vector data((std::istreambuf_iterator(file)), std::istreambuf_iterator()); - - // Compress the data - std::vector compressed_data = gzip_compress(data); - - // Pad the compressed data - std::vector padded_data = pad_data(compressed_data, 16); - - // Encrypt the data - symmetric_CBC cbc; - if (cbc_start(find_cipher("aes"), iv.data(), key.data(), key.size(), 0, &cbc) != CRYPT_OK) { - throw std::runtime_error("Error initializing CBC"); - } - - std::vector encrypted_data(padded_data.size()); - if (cbc_encrypt(padded_data.data(), encrypted_data.data(), padded_data.size(), &cbc) != CRYPT_OK) { - throw std::runtime_error("Error during encryption"); - } - - cbc_done(&cbc); - - // Return IV concatenated with the encrypted data - encrypted_data.insert(encrypted_data.begin(), iv.begin(), iv.end()); - return encrypted_data; -} - -bool is_fumen_encrypted(const std::string& filename) { - std::ifstream file(filename, std::ios::binary); - file.seekg(0x210, std::ios::beg); - std::vector buffer(32); - file.read(reinterpret_cast(buffer.data()), buffer.size()); - - // Check if the read bytes match the expected pattern - std::vector expected_bytes = { - 0x00, 0x01, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, - 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00 - }; - - return buffer != expected_bytes; -} - +HWND hGameWnd; HOOK (i32, ShowMouse, PROC_ADDRESS ("user32.dll", "ShowCursor"), bool) { return originalShowMouse (true); } HOOK (i32, ExitWindows, PROC_ADDRESS ("user32.dll", "ExitWindowsEx")) { ExitProcess (0); } +HOOK (HWND, CreateWindow, PROC_ADDRESS ("user32.dll", "CreateWindowExW"), DWORD dwExStyle, LPCWSTR lpClassName, LPCWSTR lpWindowName, DWORD dwStyle, + i32 X, i32 Y, i32 nWidth, i32 nHeight, HWND hWndParent, HMENU hMenu, HINSTANCE hInstance, LPVOID lpParam) { + if (lpWindowName != NULL) { + if (wcscmp (lpWindowName, L"Taiko") == 0) { + if (windowed) dwStyle = WS_TILEDWINDOW ^ WS_MAXIMIZEBOX ^ WS_THICKFRAME; + + hGameWnd + = originalCreateWindow (dwExStyle, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam); + return hGameWnd; + } + } + return originalCreateWindow (dwExStyle, lpClassName, lpWindowName, dwStyle, X, Y, nWidth, nHeight, hWndParent, hMenu, hInstance, lpParam); +} +HOOK (bool, SetWindowPosition, PROC_ADDRESS ("user32.dll", "SetWindowPos"), HWND hWnd, HWND hWndInsertAfter, i32 X, i32 Y, i32 cx, i32 cy, + u32 uFlags) { + if (hWnd == hGameWnd) { + RECT rw, rc; + GetWindowRect (hWnd, &rw); + GetClientRect (hWnd, &rc); + cx = (rw.right - rw.left) - (rc.right - rc.left) + cx; + cy = (rw.bottom - rw.top) - (rc.bottom - rc.top) + cy; + } + return originalSetWindowPosition (hWnd, hWndInsertAfter, X, Y, cx, cy, uFlags); +} HOOK (i32, XinputGetState, PROC_ADDRESS ("xinput9_1_0.dll", "XInputGetState")) { return ERROR_DEVICE_NOT_CONNECTED; } HOOK (i32, XinputSetState, PROC_ADDRESS ("xinput9_1_0.dll", "XInputSetState")) { return ERROR_DEVICE_NOT_CONNECTED; } @@ -200,109 +73,6 @@ HOOK (i32, ws2_getaddrinfo, PROC_ADDRESS ("ws2_32.dll", "getaddrinfo"), const ch return originalws2_getaddrinfo (server.c_str (), service, hints, out); } -HOOK (HANDLE, CreateFileAHook, PROC_ADDRESS ("kernel32.dll", "CreateFileA"), LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, - LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) { - std::filesystem::path path (lpFileName); - if (!path.is_absolute ()) path = std::filesystem::absolute (path); - auto originalDataFolder = std::filesystem::current_path ().parent_path ().parent_path () / "Data" / "x64"; - auto originalLayeredFsFolder = std::filesystem::current_path ().parent_path ().parent_path () / "Data_mods" / "x64"; - auto encryptedLayeredFsFolder = std::filesystem::current_path ().parent_path ().parent_path () / "Data_mods" / "x64_enc"; - - if (path.string ().find (originalDataFolder.string ()) == 0) { - auto newPath = path.string (); - auto encPath = path.string (); - newPath.replace (0, originalDataFolder.string ().length (), originalLayeredFsFolder.string ()); - encPath.replace (0, originalDataFolder.string ().length (), encryptedLayeredFsFolder.string ()); - - //The following code handles file redirection and if need be, file encryption. - //It's a bit of a mess but it works well ! -Kit - - if (std::filesystem::exists (newPath)) { //If a file exists in the datamod folder - if(is_fumen_encrypted(newPath)){ //And if it's an encrypted fumen or a different type of file, use it. - std::cout << "Redirecting " << std::filesystem::relative (path).string() << std::endl; - return originalCreateFileAHook (newPath.c_str (), dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, - dwFlagsAndAttributes, hTemplateFile); - } - else{ //Otherwise if it's an unencrypted fumen. - if (!std::filesystem::exists(encPath)) { //We check if we don't already have a cached file. - if(fumenKey.length() == 64){ - std::cout << "Encrypting " << std::filesystem::relative (newPath) << std::endl; // If we don't we encrypt the file - std::ifstream crc_file(newPath, std::ios::binary); - std::vector crc_vector((std::istreambuf_iterator(crc_file)), std::istreambuf_iterator()); - uint32_t crc = crc32c(0, crc_vector.data(), crc_vector.size()); - write_file(encPath, encrypt_file(newPath, fumenKey), crc); // And we save it - } else { - std::cout << "Missing or invalid fumen key : " << std::filesystem::relative (newPath) << " couldn't be encrypted." << std::endl; - encPath = path.string(); - } - } else std::cout << "Using cached file for " << std::filesystem::relative (newPath) << std::endl; - return originalCreateFileAHook (encPath.c_str (), dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, - dwFlagsAndAttributes, hTemplateFile); - } - } - - //We check separately for unencrypted json files. - std::filesystem::path json_path = newPath; - json_path.replace_extension(".json"); - if (std::filesystem::exists(json_path)) { //If a json file exists in the folder - bool crcBool = false; - - if (std::filesystem::exists(encPath)){ - std::ifstream crc_file(json_path, std::ios::binary); - std::vector crc_vector((std::istreambuf_iterator(crc_file)), std::istreambuf_iterator()); - uint32_t crc = crc32c(0, crc_vector.data(), crc_vector.size()); - crcBool = checkCRC(encPath, crc); - } - - if (!std::filesystem::exists(encPath) || crcBool) { //And if it hasn't been encrypted before - if(datatableKey.length() == 64){ - std::cout << "Encrypting " << std::filesystem::relative (json_path) << std::endl; //Encrypt the file - std::ifstream crc_file(json_path.string(), std::ios::binary); - std::vector crc_vector((std::istreambuf_iterator(crc_file)), std::istreambuf_iterator()); - uint32_t crc = crc32c(0, crc_vector.data(), crc_vector.size()); - write_file(encPath, encrypt_file(json_path.string(), datatableKey), crc); //And save it - } else { - std::cout << "Missing or invalid datatable key : " << std::filesystem::relative (newPath) << " couldn't be encrypted." << std::endl; - encPath = path.string(); - } - } - else std::cout << "Using cached file for " << std::filesystem::relative (json_path) << std::endl; //Otherwise use the already encrypted file. - return originalCreateFileAHook (encPath.c_str (), dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, - dwFlagsAndAttributes, hTemplateFile); - } - } - - return originalCreateFileAHook (lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, - hTemplateFile); -} - -// HOOK (HANDLE, CreateFileWHook, PROC_ADDRESS ("kernel32.dll", "CreateFileW"), LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, -// LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) { -// std::wstring_convert, wchar_t> converter; -// std::string strFileName = converter.to_bytes (lpFileName); - -// std::filesystem::path path (strFileName); -// if (!path.is_absolute ()) path = std::filesystem::absolute (path); - -// auto originalDataFolder = std::filesystem::current_path ().parent_path ().parent_path () / "Data" / "x64"; -// auto originalLayeredFsFolder = std::filesystem::current_path ().parent_path ().parent_path () / "Data_mods" / "x64"; - -// if (path.string ().find (originalDataFolder.string ()) != std::string::npos) { -// auto newPath = path.string (); -// newPath.replace (0, originalDataFolder.string ().length (), originalLayeredFsFolder.string ()); - -// if (std::filesystem::exists (newPath)) { -// std::wstring wNewPath = converter.from_bytes (newPath); -// std::wcout << L"Redirecting " << lpFileName << L" to " << wNewPath << std::endl; -// return originalCreateFileWHook (wNewPath.c_str (), dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, -// dwFlagsAndAttributes, hTemplateFile); -// } -// } - -// return originalCreateFileWHook (lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, -// hTemplateFile); -// } - void GetGameVersion () { wchar_t w_path[MAX_PATH]; @@ -378,25 +148,28 @@ DllMain (HMODULE module, DWORD reason, LPVOID reserved) { countryCode = readConfigString (amauth, "country_code", countryCode); std::strcat (fullAddress, server.c_str ()); - std::strcat (fullAddress, ":"); - std::strcat (fullAddress, port.c_str ()); + if (port != "") { + std::strcat (fullAddress, ":"); + std::strcat (fullAddress, port.c_str ()); + } std::strcat (placeId, countryCode.c_str ()); std::strcat (placeId, "0FF0"); } auto patches = openConfigSection (config, "patches"); if (patches) version = readConfigString (patches, "version", version); + auto graphics = openConfigSection (config, "graphics"); + if (graphics) windowed = readConfigBool (graphics, "windowed", windowed); auto keyboard = openConfigSection (config, "keyboard"); if (keyboard) { autoIME = readConfigBool (keyboard, "auto_ime", autoIME); jpLayout = readConfigBool (keyboard, "jp_layout", jpLayout); } - - auto layeredFs = openConfigSection (config, "layeredfs"); - if (layeredFs) { - useLayeredFs = readConfigBool (layeredFs, "enabled", useLayeredFs); - datatableKey = readConfigString (layeredFs, "datatable_key", datatableKey); - fumenKey = readConfigString (layeredFs, "fumen_key", fumenKey); + auto layeredFS = openConfigSection (config, "layeredfs"); + if (layeredFS) { + useLayeredFS = readConfigBool (layeredFS, "enabled", useLayeredFS); + datatableKey = readConfigString (layeredFS, "datatable_key", datatableKey); + fumenKey = readConfigString (layeredFS, "fumen_key", fumenKey); } } @@ -441,6 +214,8 @@ DllMain (HMODULE module, DWORD reason, LPVOID reserved) { INSTALL_HOOK (ShowMouse); INSTALL_HOOK (ExitWindows); + INSTALL_HOOK (CreateWindow); + INSTALL_HOOK (SetWindowPosition); INSTALL_HOOK (XinputGetState); INSTALL_HOOK (XinputSetState); @@ -454,13 +229,6 @@ DllMain (HMODULE module, DWORD reason, LPVOID reserved) { INSTALL_HOOK (ws2_getaddrinfo); - if (useLayeredFs) { - std::wcout << "Using LayeredFs!" << std::endl; - register_cipher(&aes_desc); - INSTALL_HOOK (CreateFileAHook); - // INSTALL_HOOK (CreateFileWHook); - } - bnusio::Init (); switch (gameVersion) { @@ -470,6 +238,10 @@ DllMain (HMODULE module, DWORD reason, LPVOID reserved) { case GameVersion::JPN39: patches::JPN39::Init (); break; case GameVersion::CHN00: patches::CHN00::Init (); break; } + + if (useLayeredFS) patches::LayeredFS::Init (); + + patches::Dxgi::Init (); } return true; } diff --git a/src/patches/dxgi.cpp b/src/patches/dxgi.cpp new file mode 100644 index 0000000..66b1eba --- /dev/null +++ b/src/patches/dxgi.cpp @@ -0,0 +1,257 @@ +#define CINTERFACE +#define D3D11_NO_HELPERS +#define INITGUID +#pragma optimize("", off) + +#include "d3d11.h" +#include "dxgi1_2.h" +#include "dxgi1_3.h" +#include "dxgi1_4.h" +#include "dxgi1_5.h" +#include "dxgi1_6.h" +#include "helpers.h" +#include +#pragma comment(lib, "d3d11.lib") +#include "d3d12.h" +#pragma comment(lib, "d3d12.lib") + +#include "patches.h" +#include + +/* + * Reference: https://github.com/teknogods/OpenParrot/blob/master/OpenParrot/src/Functions/WindowedDxgi.cpp + */ + +namespace patches::Dxgi { + +// Local variables +static bool FpsLimiterEnable = false; +static bool DisableVSync = false; + +// Prototypes +static HRESULT (STDMETHODCALLTYPE *g_oldSetFullscreenState) (IDXGISwapChain *This, BOOL Fullscreen, IDXGIOutput *pTarget); +static HRESULT (STDMETHODCALLTYPE *g_oldCreateSwapChain) (IDXGIFactory *This, IUnknown *pDevice, DXGI_SWAP_CHAIN_DESC *pDesc, + IDXGISwapChain **ppSwapChain); +static HRESULT (STDMETHODCALLTYPE *g_oldSetFullscreenState1) (IDXGISwapChain1 *This, BOOL Fullscreen, IDXGIOutput *pTarget); +static HRESULT (STDMETHODCALLTYPE *g_oldCreateSwapChainForHwnd) (IDXGIFactory2 *This, IUnknown *pDevice, HWND hWnd, + const DXGI_SWAP_CHAIN_DESC1 *pDesc, + const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *pFullscreenDesc, + IDXGIOutput *pRestrictToOutput, IDXGISwapChain1 **ppSwapChain); +static HRESULT (STDMETHODCALLTYPE *g_oldPresentWrap) (IDXGISwapChain *pSwapChain, UINT SyncInterval, UINT Flags); +static HRESULT (STDMETHODCALLTYPE *g_oldPresent1Wrap) (IDXGISwapChain1 *pSwapChain, UINT SyncInterval, UINT Flags); +static HRESULT (STDMETHODCALLTYPE *g_oldCreateSwapChain2) (IDXGIFactory2 *This, IUnknown *pDevice, DXGI_SWAP_CHAIN_DESC *pDesc, + IDXGISwapChain **ppSwapChain); +static HRESULT (WINAPI *g_origCreateDXGIFactory2) (UINT Flags, REFIID riid, void **ppFactory); +static HRESULT (WINAPI *g_origCreateDXGIFactory) (REFIID, void **); +static HRESULT (WINAPI *g_origD3D11CreateDeviceAndSwapChain) (IDXGIAdapter *pAdapter, D3D_DRIVER_TYPE DriverType, HMODULE Software, UINT Flags, + const D3D_FEATURE_LEVEL *pFeatureLevels, UINT FeatureLevels, UINT SDKVersion, + /*const*/ DXGI_SWAP_CHAIN_DESC *pSwapChainDesc, IDXGISwapChain **ppSwapChain, + ID3D11Device **ppDevice, D3D_FEATURE_LEVEL *pFeatureLevel, + ID3D11DeviceContext **ppImmediateContext); + +static HRESULT STDMETHODCALLTYPE SetFullscreenStateWrap (IDXGISwapChain *This, BOOL Fullscreen, IDXGIOutput *pTarget); +static HRESULT STDMETHODCALLTYPE CreateSwapChainWrap (IDXGIFactory *This, IUnknown *pDevice, DXGI_SWAP_CHAIN_DESC *pDesc, + IDXGISwapChain **ppSwapChain); +static HRESULT STDMETHODCALLTYPE SetFullscreenState1Wrap (IDXGISwapChain1 *This, BOOL Fullscreen, IDXGIOutput *pTarget); +static HRESULT STDMETHODCALLTYPE CreateSwapChainForHwndWrap (IDXGIFactory2 *This, IUnknown *pDevice, HWND hWnd, const DXGI_SWAP_CHAIN_DESC1 *pDesc, + const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *pFullscreenDesc, IDXGIOutput *pRestrictToOutput, + IDXGISwapChain1 **ppSwapChain); +static HRESULT STDMETHODCALLTYPE PresentWrap (IDXGISwapChain *pSwapChain, UINT SyncInterval, UINT Flags); +static HRESULT STDMETHODCALLTYPE Present1Wrap (IDXGISwapChain1 *pSwapChain, UINT SyncInterval, UINT Flags); +static HRESULT STDMETHODCALLTYPE CreateSwapChain2Wrap (IDXGIFactory2 *This, IUnknown *pDevice, DXGI_SWAP_CHAIN_DESC *pDesc, + IDXGISwapChain **ppSwapChain); +static HRESULT WINAPI CreateDXGIFactory2Wrap (UINT Flags, REFIID riid, void **ppFactory); +static HRESULT WINAPI CreateDXGIFactoryWrap (REFIID riid, _COM_Outptr_ void **ppFactory); +static HRESULT WINAPI D3D11CreateDeviceAndSwapChainWrap (IDXGIAdapter *pAdapter, D3D_DRIVER_TYPE DriverType, HMODULE Software, UINT Flags, + const D3D_FEATURE_LEVEL *pFeatureLevels, UINT FeatureLevels, UINT SDKVersion, + /*const*/ DXGI_SWAP_CHAIN_DESC *pSwapChainDesc, IDXGISwapChain **ppSwapChain, + ID3D11Device **ppDevice, D3D_FEATURE_LEVEL *pFeatureLevel, + ID3D11DeviceContext **ppImmediateContext); + +// Functions +template +inline T +HookVtableFunction (T *functionPtr, T target) { + if (*functionPtr == target) return nullptr; + + auto old = *functionPtr; + WRITE_MEMORY (functionPtr, T, target); + // injector::WriteMemory (functionPtr, target, true); + + return old; +} + +static HRESULT STDMETHODCALLTYPE +SetFullscreenStateWrap (IDXGISwapChain *This, BOOL Fullscreen, IDXGIOutput *pTarget) { + return S_OK; +} + +static HRESULT STDMETHODCALLTYPE +CreateSwapChainWrap (IDXGIFactory *This, IUnknown *pDevice, DXGI_SWAP_CHAIN_DESC *pDesc, IDXGISwapChain **ppSwapChain) { + HRESULT hr = g_oldCreateSwapChain (This, pDevice, pDesc, ppSwapChain); + + if (*ppSwapChain) { + if (FpsLimiterEnable || DisableVSync) { + auto old2 = HookVtableFunction (&(*ppSwapChain)->lpVtbl->Present, PresentWrap); + g_oldPresentWrap = (old2) ? old2 : g_oldPresentWrap; + } + } + + return hr; +} + +static HRESULT STDMETHODCALLTYPE +SetFullscreenState1Wrap (IDXGISwapChain1 *This, BOOL Fullscreen, IDXGIOutput *pTarget) { + return S_OK; +} + +static HRESULT STDMETHODCALLTYPE +CreateSwapChainForHwndWrap (IDXGIFactory2 *This, IUnknown *pDevice, HWND hWnd, const DXGI_SWAP_CHAIN_DESC1 *pDesc, + const DXGI_SWAP_CHAIN_FULLSCREEN_DESC *pFullscreenDesc, IDXGIOutput *pRestrictToOutput, IDXGISwapChain1 **ppSwapChain) { + HRESULT hr = g_oldCreateSwapChainForHwnd (This, pDevice, hWnd, pDesc, NULL, pRestrictToOutput, ppSwapChain); + + if (*ppSwapChain) { + if (FpsLimiterEnable || DisableVSync) { + auto old2 = HookVtableFunction (&(*ppSwapChain)->lpVtbl->Present, Present1Wrap); + g_oldPresent1Wrap = (old2) ? old2 : g_oldPresent1Wrap; + } + } + + return hr; +} + +static HRESULT STDMETHODCALLTYPE +PresentWrap (IDXGISwapChain *pSwapChain, UINT SyncInterval, UINT Flags) { + if (DisableVSync) SyncInterval = 0; + + if (FpsLimiterEnable) patches::FpsLimiter::Update (); + + return g_oldPresentWrap (pSwapChain, SyncInterval, Flags); +} + +static HRESULT STDMETHODCALLTYPE +Present1Wrap (IDXGISwapChain1 *pSwapChain, UINT SyncInterval, UINT Flags) { + if (DisableVSync) SyncInterval = 0; + + if (FpsLimiterEnable) patches::FpsLimiter::Update (); + + return g_oldPresent1Wrap (pSwapChain, SyncInterval, Flags); +} + +static HRESULT STDMETHODCALLTYPE +CreateSwapChain2Wrap (IDXGIFactory2 *This, IUnknown *pDevice, DXGI_SWAP_CHAIN_DESC *pDesc, IDXGISwapChain **ppSwapChain) { + HRESULT hr = g_oldCreateSwapChain2 (This, pDevice, pDesc, ppSwapChain); + + if (*ppSwapChain) { + if (FpsLimiterEnable || DisableVSync) { + auto old2 = HookVtableFunction (&(*ppSwapChain)->lpVtbl->Present, PresentWrap); + g_oldPresentWrap = (old2) ? old2 : g_oldPresentWrap; + } + } + + return hr; +} + +static HRESULT WINAPI +CreateDXGIFactory2Wrap (UINT Flags, REFIID riid, void **ppFactory) { + HRESULT hr = g_origCreateDXGIFactory2 (Flags, riid, ppFactory); + + if (SUCCEEDED (hr)) { + int factoryType = 0; + + if (IsEqualIID (riid, IID_IDXGIFactory1)) factoryType = 1; + else if (IsEqualIID (riid, IID_IDXGIFactory2)) factoryType = 2; + else if (IsEqualIID (riid, IID_IDXGIFactory3)) factoryType = 3; + else if (IsEqualIID (riid, IID_IDXGIFactory4)) factoryType = 4; + else if (IsEqualIID (riid, IID_IDXGIFactory5)) factoryType = 5; + else if (IsEqualIID (riid, IID_IDXGIFactory6)) factoryType = 6; + else if (IsEqualIID (riid, IID_IDXGIFactory7)) factoryType = 7; + + IDXGIFactory2 *factory = (IDXGIFactory2 *)*ppFactory; + + auto old = HookVtableFunction (&factory->lpVtbl->CreateSwapChain, CreateSwapChain2Wrap); + g_oldCreateSwapChain2 = (old) ? old : g_oldCreateSwapChain2; + } + + return hr; +} + +static HRESULT WINAPI +CreateDXGIFactoryWrap (REFIID riid, _COM_Outptr_ void **ppFactory) { + HRESULT hr = g_origCreateDXGIFactory (riid, ppFactory); + + if (SUCCEEDED (hr)) { + int factoryType = 0; + + if (IsEqualIID (riid, IID_IDXGIFactory1)) factoryType = 1; + else if (IsEqualIID (riid, IID_IDXGIFactory2)) factoryType = 2; + else if (IsEqualIID (riid, IID_IDXGIFactory3)) factoryType = 3; + else if (IsEqualIID (riid, IID_IDXGIFactory4)) factoryType = 4; + else if (IsEqualIID (riid, IID_IDXGIFactory5)) factoryType = 5; + else if (IsEqualIID (riid, IID_IDXGIFactory6)) factoryType = 6; + else if (IsEqualIID (riid, IID_IDXGIFactory7)) factoryType = 7; + + if (factoryType >= 0) { + IDXGIFactory *factory = (IDXGIFactory *)*ppFactory; + + auto old = HookVtableFunction (&factory->lpVtbl->CreateSwapChain, CreateSwapChainWrap); + g_oldCreateSwapChain = (old) ? old : g_oldCreateSwapChain; + } + + if (factoryType >= 2) { + IDXGIFactory2 *factory = (IDXGIFactory2 *)*ppFactory; + + auto old = HookVtableFunction (&factory->lpVtbl->CreateSwapChainForHwnd, CreateSwapChainForHwndWrap); + g_oldCreateSwapChainForHwnd = (old) ? old : g_oldCreateSwapChainForHwnd; + } + } + + return hr; +} + +static HRESULT WINAPI +D3D11CreateDeviceAndSwapChainWrap (IDXGIAdapter *pAdapter, D3D_DRIVER_TYPE DriverType, HMODULE Software, UINT Flags, + const D3D_FEATURE_LEVEL *pFeatureLevels, UINT FeatureLevels, UINT SDKVersion, + /*const*/ DXGI_SWAP_CHAIN_DESC *pSwapChainDesc, IDXGISwapChain **ppSwapChain, ID3D11Device **ppDevice, + D3D_FEATURE_LEVEL *pFeatureLevel, ID3D11DeviceContext **ppImmediateContext) { + HRESULT hr = g_origD3D11CreateDeviceAndSwapChain (pAdapter, DriverType, Software, Flags, pFeatureLevels, FeatureLevels, SDKVersion, + pSwapChainDesc, ppSwapChain, ppDevice, pFeatureLevel, ppImmediateContext); + + if (ppSwapChain) { + if (FpsLimiterEnable) { + auto old2 = HookVtableFunction (&(*ppSwapChain)->lpVtbl->Present, PresentWrap); + g_oldPresentWrap = (old2) ? old2 : g_oldPresentWrap; + } + } + + return hr; +} + +void +Init () { + bool vsync = false; + i32 fpsLimit = 120; + + auto configPath = std::filesystem::current_path () / "config.toml"; + std::unique_ptr config_ptr (openConfig (configPath), toml_free); + if (config_ptr) { + auto graphics = openConfigSection (config_ptr.get (), "graphics"); + if (graphics) { + vsync = readConfigBool (graphics, "vsync", vsync); + fpsLimit = readConfigInt (graphics, "fpslimit", fpsLimit); + } + } + + DisableVSync = !vsync; + FpsLimiterEnable = fpsLimit > 0; + patches::FpsLimiter::Init ((float)fpsLimit); + + MH_Initialize (); + MH_CreateHookApi (L"dxgi.dll", "CreateDXGIFactory", (LPVOID)CreateDXGIFactoryWrap, (void **)&g_origCreateDXGIFactory); + MH_CreateHookApi (L"dxgi.dll", "CreateDXGIFactory2", (LPVOID)CreateDXGIFactory2Wrap, (void **)&g_origCreateDXGIFactory2); + MH_CreateHookApi (L"d3d11.dll", "D3D11CreateDeviceAndSwapChain", (LPVOID)D3D11CreateDeviceAndSwapChainWrap, + (void **)&g_origD3D11CreateDeviceAndSwapChain); + MH_EnableHook (MH_ALL_HOOKS); +} + +} // namespace patches::Dxgi \ No newline at end of file diff --git a/src/patches/fpslimiter.cpp b/src/patches/fpslimiter.cpp new file mode 100644 index 0000000..02b0ffc --- /dev/null +++ b/src/patches/fpslimiter.cpp @@ -0,0 +1,65 @@ +#include "helpers.h" +#include "patches.h" + +namespace patches::FpsLimiter { + +/* + * Reference: https://github.com/teknogods/OpenParrot/blob/master/OpenParrot/src/Functions/FpsLimiter.cpp + */ + +static LARGE_INTEGER PerformanceCount1; +static LARGE_INTEGER PerformanceCount2; +static bool bOnce1 = false; +static double targetFrameTime = 1000.0 / 60.0; +static double t = 0.0; +static u32 i = 0; + +void +Init (float fpsLimit) { + targetFrameTime = 1000.0 / fpsLimit; +} + +void +Update () { + if (!bOnce1) { + bOnce1 = true; + QueryPerformanceCounter (&PerformanceCount1); + PerformanceCount1.QuadPart = PerformanceCount1.QuadPart >> i; + } + + while (true) { + QueryPerformanceCounter (&PerformanceCount2); + + if (t == 0.0) { + LARGE_INTEGER PerformanceCount3; + static bool bOnce2 = false; + + if (!bOnce2) { + bOnce2 = true; + QueryPerformanceFrequency (&PerformanceCount3); + i = 0; + t = 1000.0 / (double)PerformanceCount3.QuadPart; + auto v = t * 2147483648.0; + if (60000.0 > v) { + while (true) { + ++i; + v *= 2.0; + t *= 2.0; + if (60000.0 <= v) break; + } + } + } + SleepEx (0, 1); + break; + } + + if (((double)((PerformanceCount2.QuadPart >> i) - PerformanceCount1.QuadPart) * t) >= targetFrameTime) break; + + SleepEx (0, 1); + } + + QueryPerformanceCounter (&PerformanceCount2); + PerformanceCount1.QuadPart = PerformanceCount2.QuadPart >> i; +} + +} \ No newline at end of file diff --git a/src/patches/layeredfs.cpp b/src/patches/layeredfs.cpp new file mode 100644 index 0000000..f8b97db --- /dev/null +++ b/src/patches/layeredfs.cpp @@ -0,0 +1,277 @@ +#include "helpers.h" +#include +#include + +extern std::string datatableKey; +extern std::string fumenKey; + +#define CRCPOLY 0x82F63B78 + +namespace patches::LayeredFS { + +uint32_t +CRC32C (uint32_t crc, const unsigned char *buf, size_t len) { + int k; + + crc = ~crc; + while (len--) { + crc ^= *buf++; + for (k = 0; k < 8; k++) + crc = (crc >> 1) ^ (CRCPOLY & (0 - (crc & 1))); + } + return ~crc; +} + +bool +CheckCRC (const std::string &path, uint32_t crc) { + if (std::filesystem::exists (path)) { + std::filesystem::path crc_path = path; + crc_path.replace_extension (".crc"); + std::ifstream crc_file (crc_path, std::ios::binary); + std::string crc_content ((std::istreambuf_iterator (crc_file)), std::istreambuf_iterator ()); + return std::stoul (crc_content) != crc; + } + return 1; +} + +void +CreateDirectories (const std::string &path) { + size_t pos = 0; + std::string delimiter = "\\"; + std::string current_path; + + while ((pos = path.find (delimiter, pos)) != std::string::npos) { + current_path = path.substr (0, pos++); + if (!current_path.empty () && !CreateDirectory (current_path.c_str (), NULL) && GetLastError () != ERROR_ALREADY_EXISTS) + throw std::runtime_error ("Error creating directory: " + current_path); + } + if (!path.empty () && !CreateDirectory (path.c_str (), NULL) && GetLastError () != ERROR_ALREADY_EXISTS) + throw std::runtime_error ("Error creating directory: " + path); +} + +void +WriteFile (const std::string &filename, const std::vector &data, uint32_t original_crc) { + std::string::size_type pos = filename.find_last_of ("\\"); + if (pos != std::string::npos) { + std::string directory = filename.substr (0, pos); + CreateDirectories (directory); + } + + std::filesystem::path crc_path = filename; + crc_path.replace_extension (".crc"); + std::ofstream crc_file (crc_path.string ()); + crc_file << std::to_string (original_crc); + crc_file.close (); + + std::ofstream file (filename, std::ios::binary); + file.write (reinterpret_cast (data.data ()), data.size ()); +} + +std::vector +GZip_Compress (const std::vector &data) { + z_stream deflate_stream; + deflate_stream.zalloc = Z_NULL; + deflate_stream.zfree = Z_NULL; + deflate_stream.opaque = Z_NULL; + deflate_stream.avail_in = data.size (); + deflate_stream.next_in = const_cast (data.data ()); + + deflateInit2 (&deflate_stream, Z_BEST_COMPRESSION, Z_DEFLATED, 15 + 16, 8, Z_DEFAULT_STRATEGY); + + std::vector compressed_data; + compressed_data.resize (deflateBound (&deflate_stream, data.size ())); + + deflate_stream.avail_out = compressed_data.size (); + deflate_stream.next_out = compressed_data.data (); + + deflate (&deflate_stream, Z_FINISH); + deflateEnd (&deflate_stream); + + compressed_data.resize (deflate_stream.total_out); + return compressed_data; +} + +// Function to pad data according to PKCS7 +std::vector +Pad_Data (const std::vector &data, size_t block_size) { + size_t padding = block_size - (data.size () % block_size); + std::vector padded_data = data; + padded_data.insert (padded_data.end (), padding, static_cast (padding)); + return padded_data; +} + +std::vector +Hex_To_Bytes (const std::string &hex) { + std::vector bytes; + for (size_t i = 0; i < hex.length (); i += 2) { + uint8_t byte = static_cast (std::stoi (hex.substr (i, 2), nullptr, 16)); + bytes.push_back (byte); + } + return bytes; +} + +std::vector +EncryptFile (const std::string &input_file, const std::string &hex_key) { + // Convert the key from hex to bytes + std::vector key = Hex_To_Bytes (hex_key); + + // Generate the 128 bits IV + std::vector iv (16); + for (size_t i = 0; i < iv.size (); ++i) + iv[i] = static_cast (i); + + // Read the entire file into memory + std::ifstream file (input_file, std::ios::binary); + + std::vector data ((std::istreambuf_iterator (file)), std::istreambuf_iterator ()); + + // Compress the data + std::vector compressed_data = GZip_Compress (data); + + // Pad the compressed data + std::vector padded_data = Pad_Data (compressed_data, 16); + + // Encrypt the data + symmetric_CBC cbc; + if (cbc_start (find_cipher ("aes"), iv.data (), key.data (), key.size (), 0, &cbc) != CRYPT_OK) + throw std::runtime_error ("Error initializing CBC"); + + std::vector encrypted_data (padded_data.size ()); + if (cbc_encrypt (padded_data.data (), encrypted_data.data (), padded_data.size (), &cbc) != CRYPT_OK) + throw std::runtime_error ("Error during encryption"); + + cbc_done (&cbc); + + // Return IV concatenated with the encrypted data + encrypted_data.insert (encrypted_data.begin (), iv.begin (), iv.end ()); + return encrypted_data; +} + +bool +IsFumenEncrypted (const std::string &filename) { + std::ifstream file (filename, std::ios::binary); + file.seekg (0x210, std::ios::beg); + std::vector buffer (32); + file.read (reinterpret_cast (buffer.data ()), buffer.size ()); + + // Check if the read bytes match the expected pattern + std::vector expected_bytes = {0x00, 0x01, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00}; + + return buffer != expected_bytes; +} + +HOOK (HANDLE, CreateFileAHook, PROC_ADDRESS ("kernel32.dll", "CreateFileA"), LPCSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, + LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) { + std::filesystem::path path (lpFileName); + if (!path.is_absolute ()) path = std::filesystem::absolute (path); + auto originalDataFolder = std::filesystem::current_path ().parent_path ().parent_path () / "Data" / "x64"; + auto originalLayeredFsFolder = std::filesystem::current_path ().parent_path ().parent_path () / "Data_mods" / "x64"; + auto encryptedLayeredFsFolder = std::filesystem::current_path ().parent_path ().parent_path () / "Data_mods" / "x64_enc"; + + if (path.string ().find (originalDataFolder.string ()) == 0) { + auto newPath = path.string (); + auto encPath = path.string (); + newPath.replace (0, originalDataFolder.string ().length (), originalLayeredFsFolder.string ()); + encPath.replace (0, originalDataFolder.string ().length (), encryptedLayeredFsFolder.string ()); + + // The following code handles file redirection and if need be, file encryption. + // It's a bit of a mess but it works well ! -Kit + + if (std::filesystem::exists (newPath)) { // If a file exists in the datamod folder + if (IsFumenEncrypted (newPath)) { // And if it's an encrypted fumen or a different type of file, use it. + std::cout << "Redirecting " << std::filesystem::relative (path).string () << std::endl; + return originalCreateFileAHook (newPath.c_str (), dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, + dwFlagsAndAttributes, hTemplateFile); + } else { // Otherwise if it's an unencrypted fumen. + if (!std::filesystem::exists (encPath)) { // We check if we don't already have a cached file. + if (fumenKey.length () == 64) { + std::cout << "Encrypting " << std::filesystem::relative (newPath) << std::endl; // If we don't we encrypt the file + std::ifstream crc_file (newPath, std::ios::binary); + std::vector crc_vector ((std::istreambuf_iterator (crc_file)), std::istreambuf_iterator ()); + uint32_t crc = CRC32C (0, crc_vector.data (), crc_vector.size ()); + WriteFile (encPath, EncryptFile (newPath, fumenKey), crc); // And we save it + } else { + std::cout << "Missing or invalid fumen key : " << std::filesystem::relative (newPath) << " couldn't be encrypted." + << std::endl; + encPath = path.string (); + } + } else std::cout << "Using cached file for " << std::filesystem::relative (newPath) << std::endl; + return originalCreateFileAHook (encPath.c_str (), dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, + dwFlagsAndAttributes, hTemplateFile); + } + } + + // We check separately for unencrypted json files. + std::filesystem::path json_path = newPath; + json_path.replace_extension (".json"); + if (std::filesystem::exists (json_path)) { // If a json file exists in the folder + bool crcBool = false; + + if (std::filesystem::exists (encPath)) { + std::ifstream crc_file (json_path, std::ios::binary); + std::vector crc_vector ((std::istreambuf_iterator (crc_file)), std::istreambuf_iterator ()); + uint32_t crc = CRC32C (0, crc_vector.data (), crc_vector.size ()); + crcBool = CheckCRC (encPath, crc); + } + + if (!std::filesystem::exists (encPath) || crcBool) { // And if it hasn't been encrypted before + if (datatableKey.length () == 64) { + std::cout << "Encrypting " << std::filesystem::relative (json_path) << std::endl; // Encrypt the file + std::ifstream crc_file (json_path.string (), std::ios::binary); + std::vector crc_vector ((std::istreambuf_iterator (crc_file)), std::istreambuf_iterator ()); + uint32_t crc = CRC32C (0, crc_vector.data (), crc_vector.size ()); + WriteFile (encPath, EncryptFile (json_path.string (), datatableKey), crc); // And save it + } else { + std::cout << "Missing or invalid datatable key : " << std::filesystem::relative (newPath) << " couldn't be encrypted." + << std::endl; + encPath = path.string (); + } + } else + std::cout << "Using cached file for " << std::filesystem::relative (json_path) + << std::endl; // Otherwise use the already encrypted file. + return originalCreateFileAHook (encPath.c_str (), dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, + dwFlagsAndAttributes, hTemplateFile); + } + } + + return originalCreateFileAHook (lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, + hTemplateFile); +} + +// HOOK (HANDLE, CreateFileWHook, PROC_ADDRESS ("kernel32.dll", "CreateFileW"), LPCWSTR lpFileName, DWORD dwDesiredAccess, DWORD dwShareMode, +// LPSECURITY_ATTRIBUTES lpSecurityAttributes, DWORD dwCreationDisposition, DWORD dwFlagsAndAttributes, HANDLE hTemplateFile) { +// std::wstring_convert, wchar_t> converter; +// std::string strFileName = converter.to_bytes (lpFileName); + +// std::filesystem::path path (strFileName); +// if (!path.is_absolute ()) path = std::filesystem::absolute (path); + +// auto originalDataFolder = std::filesystem::current_path ().parent_path ().parent_path () / "Data" / "x64"; +// auto originalLayeredFsFolder = std::filesystem::current_path ().parent_path ().parent_path () / "Data_mods" / "x64"; + +// if (path.string ().find (originalDataFolder.string ()) != std::string::npos) { +// auto newPath = path.string (); +// newPath.replace (0, originalDataFolder.string ().length (), originalLayeredFsFolder.string ()); + +// if (std::filesystem::exists (newPath)) { +// std::wstring wNewPath = converter.from_bytes (newPath); +// std::wcout << L"Redirecting " << lpFileName << L" to " << wNewPath << std::endl; +// return originalCreateFileWHook (wNewPath.c_str (), dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, +// dwFlagsAndAttributes, hTemplateFile); +// } +// } + +// return originalCreateFileWHook (lpFileName, dwDesiredAccess, dwShareMode, lpSecurityAttributes, dwCreationDisposition, dwFlagsAndAttributes, +// hTemplateFile); +// } + +void +Init () { + std::wcout << "Using LayeredFs!" << std::endl; + register_cipher (&aes_desc); + INSTALL_HOOK (CreateFileAHook); + // INSTALL_HOOK (CreateFileWHook); +} + +} \ No newline at end of file diff --git a/src/patches/patches.h b/src/patches/patches.h index 7ed4399..fee6ed7 100644 --- a/src/patches/patches.h +++ b/src/patches/patches.h @@ -11,6 +11,13 @@ void Init (); namespace CHN00 { void Init (); } // namespace CHN00 +namespace Dxgi { +void Init (); +} // namespace Dxgi +namespace FpsLimiter { +void Init (float fpsLimit); +void Update (); +} // namespace FpsLimiter namespace Audio { void Init (); } // namespace Audio @@ -21,4 +28,7 @@ void Update (); namespace AmAuth { void Init (); } // namespace AmAuth +namespace LayeredFS { +void Init (); +} // namespace LayeredFS } // namespace patches diff --git a/src/patches/versions/CHN00.cpp b/src/patches/versions/CHN00.cpp index e6e0e63..5479e8a 100644 --- a/src/patches/versions/CHN00.cpp +++ b/src/patches/versions/CHN00.cpp @@ -99,7 +99,6 @@ void Init () { i32 xRes = 1920; i32 yRes = 1080; - bool vsync = false; bool unlockSongs = true; bool fixLanguage = false; bool demoMovie = true; @@ -128,12 +127,6 @@ Init () { if (config_ptr) { auto patches = openConfigSection (config_ptr.get (), "patches"); if (patches) { - auto res = openConfigSection (patches, "res"); - if (res) { - xRes = readConfigInt (res, "x", xRes); - yRes = readConfigInt (res, "y", yRes); - } - vsync = readConfigBool (patches, "vsync", vsync); unlockSongs = readConfigBool (patches, "unlock_songs", unlockSongs); auto chn00 = openConfigSection (patches, "chn00"); if (chn00) { @@ -143,12 +136,20 @@ Init () { modeCollabo026 = readConfigBool (chn00, "mode_collabo026", modeCollabo026); } } + + auto graphics = openConfigSection (config_ptr.get (), "graphics"); + if (graphics) { + auto res = openConfigSection (graphics, "res"); + if (res) { + xRes = readConfigInt (res, "x", xRes); + yRes = readConfigInt (res, "y", yRes); + } + } } // Apply common config patch WRITE_MEMORY (ASLR (0x1404A4ED3), i32, xRes); WRITE_MEMORY (ASLR (0x1404A4EDA), i32, yRes); - if (!vsync) WRITE_MEMORY (ASLR (0x1405FC5B9), u8, 0xBA, 0x00, 0x00, 0x00, 0x00, 0x90); if (unlockSongs) WRITE_MEMORY (ASLR (0x140425BCD), u8, 0xB0, 0x01); // Bypass errors diff --git a/src/patches/versions/JPN00.cpp b/src/patches/versions/JPN00.cpp index dd35f1d..04af966 100644 --- a/src/patches/versions/JPN00.cpp +++ b/src/patches/versions/JPN00.cpp @@ -48,28 +48,27 @@ void Init () { i32 xRes = 1920; i32 yRes = 1080; - bool vsync = false; bool unlockSongs = true; auto configPath = std::filesystem::current_path () / "config.toml"; std::unique_ptr config_ptr (openConfig (configPath), toml_free); if (config_ptr) { auto patches = openConfigSection (config_ptr.get (), "patches"); - if (patches) { - auto res = openConfigSection (patches, "res"); + if (patches) unlockSongs = readConfigBool (patches, "unlock_songs", unlockSongs); + + auto graphics = openConfigSection (config_ptr.get (), "graphics"); + if (graphics) { + auto res = openConfigSection (graphics, "res"); if (res) { xRes = readConfigInt (res, "x", xRes); yRes = readConfigInt (res, "y", yRes); } - vsync = readConfigBool (patches, "vsync", vsync); - unlockSongs = readConfigBool (patches, "unlock_songs", unlockSongs); } } // Apply common config patch WRITE_MEMORY (ASLR (0x140224B2B), i32, xRes); WRITE_MEMORY (ASLR (0x140224B32), i32, yRes); - if (!vsync) WRITE_MEMORY (ASLR (0x1403D6189), u8, 0xBA, 0x00, 0x00, 0x00, 0x00, 0x90); if (unlockSongs) WRITE_MEMORY (ASLR (0x1401F6B78), u8, 0xB0, 0x01); // Bypass errors diff --git a/src/patches/versions/JPN08.cpp b/src/patches/versions/JPN08.cpp index f099b42..7c92aca 100644 --- a/src/patches/versions/JPN08.cpp +++ b/src/patches/versions/JPN08.cpp @@ -50,28 +50,27 @@ void Init () { i32 xRes = 1920; i32 yRes = 1080; - bool vsync = false; bool unlockSongs = true; auto configPath = std::filesystem::current_path () / "config.toml"; std::unique_ptr config_ptr (openConfig (configPath), toml_free); if (config_ptr) { auto patches = openConfigSection (config_ptr.get (), "patches"); - if (patches) { - auto res = openConfigSection (patches, "res"); + if (patches) unlockSongs = readConfigBool (patches, "unlock_songs", unlockSongs); + + auto graphics = openConfigSection (config_ptr.get (), "graphics"); + if (graphics) { + auto res = openConfigSection (graphics, "res"); if (res) { xRes = readConfigInt (res, "x", xRes); yRes = readConfigInt (res, "y", yRes); } - vsync = readConfigBool (patches, "vsync", vsync); - unlockSongs = readConfigBool (patches, "unlock_songs", unlockSongs); } } // Apply common config patch WRITE_MEMORY (ASLR (0x14035FC5B), i32, xRes); WRITE_MEMORY (ASLR (0x14035FC62), i32, yRes); - if (!vsync) WRITE_MEMORY (ASLR (0x140517339), u8, 0xBA, 0x00, 0x00, 0x00, 0x00, 0x90); if (unlockSongs) WRITE_MEMORY (ASLR (0x140314E8D), u8, 0xB0, 0x01); // Bypass errors diff --git a/src/patches/versions/JPN39.cpp b/src/patches/versions/JPN39.cpp index 6993a7f..c414f9e 100644 --- a/src/patches/versions/JPN39.cpp +++ b/src/patches/versions/JPN39.cpp @@ -44,28 +44,27 @@ void Init () { i32 xRes = 1920; i32 yRes = 1080; - bool vsync = false; bool unlockSongs = true; auto configPath = std::filesystem::current_path () / "config.toml"; std::unique_ptr config_ptr (openConfig (configPath), toml_free); if (config_ptr) { auto patches = openConfigSection (config_ptr.get (), "patches"); - if (patches) { - auto res = openConfigSection (patches, "res"); + if (patches) unlockSongs = readConfigBool (patches, "unlock_songs", unlockSongs); + + auto graphics = openConfigSection (config_ptr.get (), "graphics"); + if (graphics) { + auto res = openConfigSection (graphics, "res"); if (res) { xRes = readConfigInt (res, "x", xRes); yRes = readConfigInt (res, "y", yRes); } - vsync = readConfigBool (patches, "vsync", vsync); - unlockSongs = readConfigBool (patches, "unlock_songs", unlockSongs); } } // Apply common config patch WRITE_MEMORY (ASLR (0x140494533), i32, xRes); WRITE_MEMORY (ASLR (0x14049453A), i32, yRes); - if (!vsync) WRITE_MEMORY (ASLR (0x14064C7E9), u8, 0xBA, 0x00, 0x00, 0x00, 0x00, 0x90); if (unlockSongs) WRITE_MEMORY (ASLR (0x1403F45CF), u8, 0xB0, 0x01); // Bypass errors