switch to exe loader method to make sure the dll is properly injected
This commit is contained in:
Kuriko Moe
2025-02-28 16:52:23 +08:00
parent 437c8675e7
commit 81d7faa0da
22 changed files with 247 additions and 336 deletions
+10
View File
@@ -85,3 +85,13 @@ _deps
*.app *.app
# End of https://www.toptal.com/developers/gitignore/api/c++ # End of https://www.toptal.com/developers/gitignore/api/c++
# Created by https://www.toptal.com/developers/gitignore/api/xmake
# Edit at https://www.toptal.com/developers/gitignore?templates=xmake
### xmake ###
# Xmake cache
.xmake/
build/
# End of https://www.toptal.com/developers/gitignore/api/xmake
-35
View File
@@ -1,35 +0,0 @@
cmake_minimum_required(VERSION 3.25.0)
set(CMAKE_TOOLCHAIN_FILE ${CMAKE_SOURCE_DIR}/vcpkg/scripts/buildsystems/vcpkg.cmake CACHE STRING "")
set(CMAKE_EXPORT_COMPILE_COMMANDS true)
set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake/")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
include(AutoCCache)
project(KProject)
set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_MSVC_RUNTIME_LIBRARY "MultiThreaded$<$<CONFIG:Debug>:Debug>")
find_package(minhook CONFIG REQUIRED)
find_package(spdlog CONFIG REQUIRED)
set(TARGET "kpatch")
set(TARGET_SRC src/dllmain.cpp)
set(TARGET_OUTPUT_NAME "kpatch")
add_library(${TARGET} SHARED ${TARGET_SRC})
set_target_properties(${TARGET} PROPERTIES OUTPUT_NAME ${TARGET_OUTPUT_NAME})
target_include_directories(${TARGET} PRIVATE ${CMAKE_SOURCE_DIR}/include)
target_link_libraries(${TARGET} PRIVATE spdlog::spdlog_header_only)
# target_link_libraries(${TARGET} PUBLIC minhook::minhook)
# ------------ post build ------------
# copy compile_commands.json for clangd
if(EXISTS "${CMAKE_BINARY_DIR}/compile_commands.json")
file(COPY "${CMAKE_BINARY_DIR}/compile_commands.json" DESTINATION "${CMAKE_SOURCE_DIR}")
endif()
-15
View File
@@ -1,15 +0,0 @@
{
"version": 6,
"cmakeMinimumRequired": {
"major": 3,
"minor": 25,
"patch": 0
},
"include": [
"cmake/presets/linux.json",
"cmake/presets/windows.json"
],
"configurePresets": [ ],
"buildPresets": [ ],
"testPresets": [ ]
}
BIN
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 303 KiB

+1
View File
@@ -0,0 +1 @@
IDI_APP_ICON ICON "app.ico"
-10
View File
@@ -1,10 +0,0 @@
# From https://gist.github.com/cgmb/c48bfa77da6c825a27bf05d25001d321
option(AUTO_CCACHE "Use ccache to speed up rebuilds" ON)
find_program(CCACHE_PROGRAM ccache)
if(CCACHE_PROGRAM AND ${AUTO_CCACHE})
message(STATUS "Using ${CCACHE_PROGRAM} as compiler launcher")
set(CMAKE_CXX_COMPILER_LAUNCHER "${CCACHE_PROGRAM}")
# requires at least CMake 3.9 to be any use
set(CMAKE_CUDA_COMPILER_LAUNCHER "${CCACHE_PROGRAM}")
endif()
-15
View File
@@ -1,15 +0,0 @@
{
"version": 6,
"configurePresets": [
{
"name": "config-base",
"displayName": "base Configuration",
"hidden": true,
"binaryDir": "${sourceDir}/build/${presetName}",
"installDir": "${sourceDir}/install/${presetName}",
"cacheVariables": {
"CMAKE_EXPORT_COMPILE_COMMANDS": true
}
}
]
}
-77
View File
@@ -1,77 +0,0 @@
{
"version": 6,
"include": [ "base.json" ],
"configurePresets": [
{
"name": "config-base-linux",
"displayName": "base Configuration for linux",
"inherits": "config-base",
"hidden": true,
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Linux"
}
},
{
"name": "x64-debug",
"inherits": "config-base-linux",
"generator": "Ninja",
"architecture":{
"value": "x64",
"strategy": "external"
},
"cacheVariables": {
"CMAKE_BUILD_TYPE" : "Debug"
}
},
{
"name": "x64-release",
"inherits": "x64-debug",
"cacheVariables": {
"CMAKE_BUILD_TYPE" : "Release"
}
},
{
"name": "x86-debug",
"inherits": "config-base-linux",
"generator": "Ninja",
"architecture":{
"value": "x86",
"strategy": "external"
},
"cacheVariables": {
"CMAKE_BUILD_TYPE" : "Debug",
"CMAKE_C_FLAGS": "-m32",
"CMAKE_CXX_FLAGS": "-m32",
"CMAKE_SYSTEM_PROCESSOR": "x86"
}
},
{
"name": "x86-release",
"inherits": "x86-debug",
"cacheVariables": {
"CMAKE_BUILD_TYPE" : "Release"
}
}
],
"buildPresets": [
{
"name": "x64-debug",
"configurePreset": "x64-debug"
},
{
"name": "x64-release",
"configurePreset": "x64-release"
},
{
"name": "x86-debug",
"configurePreset": "x86-debug"
},
{
"name": "x86-release",
"configurePreset": "x86-release"
}
],
"testPresets": [ ]
}
-76
View File
@@ -1,76 +0,0 @@
{
"version": 6,
"include": ["base.json"],
"configurePresets": [
{
"name": "config-base-windows",
"displayName": "base Configuration for windows",
"inherits": "config-base",
"hidden": true,
"condition": {
"type": "equals",
"lhs": "${hostSystemName}",
"rhs": "Windows"
}
},
{
"name": "x64-debug-msvc",
"inherits": "config-base-windows",
"generator": "",
"architecture":{
"value": "x64",
"strategy": "external"
},
"cacheVariables": {
"CMAKE_BUILD_TYPE" : "Debug",
"CMAKE_GENERATOR_PLATFORM": "x64"
}
},
{
"name": "x64-release-msvc",
"inherits": "x64-debug-msvc",
"cacheVariables": {
"CMAKE_BUILD_TYPE" : "Release"
}
},
{
"name": "x86-debug-msvc",
"inherits": "config-base-windows",
"generator": "",
"architecture":{
"value": "x86",
"strategy": "external"
},
"cacheVariables": {
"CMAKE_BUILD_TYPE" : "Debug",
"CMAKE_GENERATOR_PLATFORM": "Win32"
}
},
{
"name": "x86-release-msvc",
"inherits": "x86-debug-msvc",
"cacheVariables": {
"CMAKE_BUILD_TYPE" : "Release"
}
}
],
"buildPresets": [
{
"name": "x64-debug-msvc",
"configurePreset": "x64-debug-msvc"
},
{
"name": "x64-release-msvc",
"configurePreset": "x64-release-msvc"
},
{
"name": "x86-debug-msvc",
"configurePreset": "x86-debug-msvc"
},
{
"name": "x86-release-msvc",
"configurePreset": "x86-release-msvc"
}
],
"testPresets": [ ]
}
View File
+15 -8
View File
@@ -1,5 +1,5 @@
TEMPLATE_VER := "v1.0.0" TEMPLATE_VER := "v1.0.0"
TARGET := "F:/Games/SteamLibrary/steamapps/common/Left 4 Dead 2" TARGET := "D:\\Games\\GamePlatforms\\SteamLibrary\\steamapps\\common\\Left 4 Dead 2"
# use `just preset=x64-release config build` to override this # use `just preset=x64-release config build` to override this
preset := "x86-release-msvc" preset := "x86-release-msvc"
@@ -12,17 +12,24 @@ init:
clean: clean:
rm -rf build rm -rf build
config: # config:
cmake --preset {{preset}} # # cmake --preset {{preset}} -DBUILD_SHARED_LIBS=OFF
# xmake
build: build:
cmake --build --preset {{preset}} --config Release # cmake --build --preset {{preset}} --config Release
xmake
copy: build copy: build
cd ./build/x86-release-msvc/bin/Release && \ # cd ./build/x86-release-msvc/bin/Release && \
cp -f kpatch.dll "{{TARGET}}/kpatch.asi" && \ # cp -f kpatch.dll "{{TARGET}}/kpatch.asi" && \
cp -f fmt.dll "{{TARGET}}/" # cp -f fmt.dll "{{TARGET}}/"
cp -f third/version.dll "{{TARGET}}/" # cp -f third/version.dll "{{TARGET}}/"
# cp build/windows/x86/release/version.dll "{{TARGET}}"
cp build/windows/x86/release/kpatch.dll "{{TARGET}}"
cp build/windows/x86/release/left4dead2_fix.exe "{{TARGET}}"
@run: @run:
./build/{{preset}}/bin/{{target}} ./build/{{preset}}/bin/{{target}}
+71
View File
@@ -0,0 +1,71 @@
//#pragma comment(linker, "/subsystem:\"Windows\" /entry:\"mainCRTStartup\"")
#include <windows.h>
#include <string>
#include <filesystem>
#include <shellapi.h>
#include <detours/detours.h>
namespace fs = std::filesystem;
const wchar_t* game_name = L"left4dead2.exe";
int WINAPI wWinMain(
_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpwCmdLine,
_In_ int nShowCmd
) {
WCHAR working_path[MAX_PATH];
GetModuleFileNameW(nullptr, working_path, MAX_PATH);
// Change the working directory to the directory containing the DLL.
fs::path path(working_path);
SetCurrentDirectoryW(path.parent_path().wstring().c_str());
LPCSTR dll_path = "kpatch.dll";
LPCWSTR target_exe_path = game_name;
// if (std::filesystem::exists(L"left4dead2.exe.orig")) {
// target_exe_path = L"left4dead2.exe.orig";
// } else {
// target_exe_path = game_name;
// }
STARTUPINFOW si;
PROCESS_INFORMATION pi;
ZeroMemory(&si, sizeof(si));
ZeroMemory(&pi, sizeof(pi));
si.cb = sizeof(si);
DWORD dwFlags = CREATE_DEFAULT_ERROR_MODE | CREATE_SUSPENDED;
SetLastError(0);
if (TRUE != DetourCreateProcessWithDllExW(
target_exe_path,
lpwCmdLine,
nullptr,
nullptr,
TRUE,
dwFlags,
nullptr,
nullptr,
&si,
&pi,
dll_path,
nullptr)) {
auto dwError = GetLastError();
printf("DetourCreateProcessWithDllEx failed with error %ld\n", dwError);
ExitProcess(9009);
}
ResumeThread(pi.hThread);
WaitForSingleObject(pi.hProcess, INFINITE);
return 0;
}
-8
View File
@@ -1,8 +0,0 @@
#!/bin/bash
set -xe
git clone https://github.com/microsoft/vcpkg.git --depth 1
./vcpkg/bootstrap-vcpkg.sh
./vcpkg/vcpkg new --application
-10
View File
@@ -1,10 +0,0 @@
#!nu
echo "init vcpkg"
git clone https://github.com/microsoft/vcpkg.git --depth 1
./vcpkg/bootstrap-vcpkg.bat
./vcpkg/vcpkg new --application
echo "Retarget from linux preset `x64-debug` to windows preset `x64-debug-msvc`"
open justfile | str replace r#'"x64-debug"'# r#'"x64-debug-msvc"'# | save justfile -f
+103 -29
View File
@@ -2,11 +2,22 @@
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
#include <spdlog/sinks/basic_file_sink.h> #include <spdlog/sinks/basic_file_sink.h>
#include <cctype> #include <windows.h>
#include <libloaderapi.h>
#include <cstdint>
#include <cstddef>
#include <iostream>
#include <filesystem>
#include <algorithm> #include <algorithm>
#include <detours/detours.h>
#include "helper.hpp" #include "helper.hpp"
constexpr bool isDebug = true;
constexpr bool isTesting = true;
HMODULE baseModule = GetModuleHandle(NULL); HMODULE baseModule = GetModuleHandle(NULL);
HMODULE thisModule; // Fix DLL HMODULE thisModule; // Fix DLL
@@ -21,7 +32,16 @@ std::filesystem::path sExePath;
std::string sExeName; std::string sExeName;
std::filesystem::path sThisModulePath; std::filesystem::path sThisModulePath;
void InitConsole() {
AllocConsole();
FILE *dummy;
freopen_s(&dummy, "CONOUT$", "w", stdout);
}
void Logging() { void Logging() {
if constexpr (isDebug) {
InitConsole();
}
// Get this module path // Get this module path
WCHAR thisModulePath[_MAX_PATH] = { 0 }; WCHAR thisModulePath[_MAX_PATH] = { 0 };
GetModuleFileNameW(thisModule, thisModulePath, MAX_PATH); GetModuleFileNameW(thisModule, thisModulePath, MAX_PATH);
@@ -57,18 +77,18 @@ void Logging() {
spdlog::info("Module Timestamp: {0:d}", Memory::ModuleTimestamp(baseModule)); spdlog::info("Module Timestamp: {0:d}", Memory::ModuleTimestamp(baseModule));
spdlog::info("----------"); spdlog::info("----------");
} catch (const spdlog::spdlog_ex &ex) { } catch (const spdlog::spdlog_ex &ex) {
AllocConsole(); InitConsole();
FILE *dummy;
freopen_s(&dummy, "CONOUT$", "w", stdout);
std::cout << "Log initialisation failed: " << ex.what() << std::endl;
FreeLibraryAndExitThread(baseModule, 1);
} }
} }
DWORD __stdcall Main(void*) { DWORD __stdcall Main(void*) {
Logging(); Logging();
if constexpr (isTesting) {
MessageBoxW(NULL, L"警告:这是测试版补丁,设定为必定会炸,用于检测补丁是否正确应用。", L"L4D2 Fix", MB_OK|MB_SYSTEMMODAL|MB_ICONWARNING);
}
std::filesystem::path startup_check = L"success.txt"; std::filesystem::path startup_check = L"success.txt";
// MessageBoxW(NULL, L"警告:这是测试版补丁,设定为必定会炸,用于检测补丁是否正确应用。", L"L4D2 Fix", MB_OK|MB_SYSTEMMODAL|MB_ICONWARNING);
if (!std::filesystem::exists(startup_check)) { if (!std::filesystem::exists(startup_check)) {
MessageBoxW( MessageBoxW(
@@ -80,31 +100,51 @@ DWORD __stdcall Main(void*) {
std::wstring cmdline = GetCommandLineW(); std::wstring cmdline = GetCommandLineW();
spdlog::info(L"Startup commandline: {}", cmdline.c_str()); spdlog::info(L"Startup commandline: {}", cmdline.c_str());
std::wstring dllName; std::wstring dllName = L"shaderapidx9.dll";
std::transform(cmdline.cbegin(), cmdline.cend(), cmdline.begin(), ::tolower); bool isVulkan = false;
std::transform(cmdline.cbegin(), cmdline.cend(), cmdline.begin(), ::tolower);
if (cmdline.find(L"-vulkan") != std::wstring::npos) { if (cmdline.find(L"-vulkan") != std::wstring::npos) {
dllName = L"shaderapivk.dll"; dllName = L"shaderapivk.dll";
spdlog::info(L"Detected Vulkan: using {}", dllName); spdlog::info(L"Detected Vulkan: using {}", dllName);
isVulkan = true;
} else { } else {
dllName = L"shaderapidx9.dll"; spdlog::info(L"Detected DirectX9: using {}", dllName);
} }
auto hDll = LoadLibraryW(dllName.c_str());
auto relPath = std::filesystem::path(L"bin") / dllName;
auto absPath = std::filesystem::absolute(relPath);
std::wcout << absPath << std::endl;
spdlog::info(L"Loading Dll fromg {}", absPath.wstring());
HMODULE hDll = LoadLibraryExW(absPath.c_str(), nullptr, LOAD_WITH_ALTERED_SEARCH_PATH);
if (hDll == nullptr) { if (hDll == nullptr) {
MessageBoxW(NULL, std::format(L"Failed to load {}!", dllName).c_str(), L"L4D2 Fix", MB_OK|MB_SYSTEMMODAL|MB_ICONSTOP); auto errCode = GetLastError();
wchar_t buf[255];
FormatMessageW(
FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
NULL, errCode, MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
buf, (sizeof(buf) / sizeof(wchar_t)), NULL);
std::wcout << errCode << std::endl;
std::wcout << buf << std::endl;
MessageBoxW(NULL, std::format(L"Failed to load {}!", dllName).c_str(), L"L4D2 Fix", MB_OK | MB_SYSTEMMODAL | MB_ICONSTOP);
exit(-1); exit(-1);
} }
// Tag, pattern, start_search_path, write_offset
auto f = [&](const wchar_t* tag, const char* pattern, size_t offset, size_t w_offset) { auto f = [&](const wchar_t* tag, const char* pattern, size_t offset, size_t w_offset) {
std::uint8_t* ptr = Memory::PatternScan(hDll, pattern); std::uint8_t* ptr = Memory::PatternScan(hDll, pattern, offset);
constexpr uint32_t new_buffer_size = 0x020000; uint32_t new_buffer_size = 0x020000;
// constexpr uint32_t new_buffer_size = 32; if constexpr (isTesting) {
new_buffer_size = 32;
}
if (ptr != nullptr) { if (ptr != nullptr) {
Memory::Write((uintptr_t)(ptr + w_offset), new_buffer_size); Memory::Write((uintptr_t)(ptr + w_offset), new_buffer_size);
spdlog::info(L"Modified the vertex max buffer {}: {}", dllName, tag); spdlog::info(L"Modified the vertex max buffer {}: {} @ 0x{:0x}", dllName, tag, (intptr_t)(ptr) - (intptr_t)hDll);
return ptr; return ptr;
} }
@@ -112,24 +152,58 @@ DWORD __stdcall Main(void*) {
return (uint8_t*)nullptr; return (uint8_t*)nullptr;
}; };
// CreateEmptyColorMesh
auto ptr1 = f(L"CreateEmptyColorMesh", "68 ?? ?? ?? ?? 68 00 80 00 00 6A 04", 0, 6);
auto ptr1_1 = f(L"CreateEmptyColorMesh Later", "68 00 80 00 00 50 8B", (size_t)ptr1, 1); std::vector<void*> ptr_cache;
std::string pattern;
// CreateEmptyColorMesh
pattern = "68 ?? ?? ?? ?? 68 00 80 00 00 6A 04";
auto* ptr1 = f(
L"CreateEmptyColorMesh",
pattern.c_str(),
0,
6
);
ptr_cache.push_back(ptr1);
pattern = "68 00 80 00 00 50 8B";
auto* ptr1_1 = f(
L"CreateEmptyColorMesh Later",
pattern.c_str(),
(size_t)ptr1,
1
);
ptr_cache.push_back(ptr1_1);
// CreateVertexIDBuffer // CreateVertexIDBuffer
auto ptr2 = f(L"CreateVertexIDBuffer", "68 ?? ?? ?? ?? 68 00 80 00 00 6A 04", (size_t)ptr1_1, 6); pattern = "68 ?? ?? ?? ?? 68 00 80 00 00 6A 04";
auto ptr2_1 = f(L"CreateVertexIDBuffer Later", "68 00 80 00 00 50 8B", (size_t)ptr2, 1); auto* ptr2 = f(
L"CreateVertexIDBuffer",
pattern.c_str(),
(size_t)ptr1_1,
6
);
ptr_cache.push_back(ptr2);
pattern = "68 00 80 00 00 50 8B";
auto* ptr2_1 = f(
L"CreateVertexIDBuffer Later",
pattern.c_str(),
(size_t)ptr2,
1
);
ptr_cache.push_back(ptr2_1);
auto* ptr3 = f(
L"Unknown",
"0F B6 C0 50 68 00 80 00 00 53 8B CF E8 ?? ?? ?? ??",
(size_t)ptr2,
5
);
ptr_cache.push_back(ptr3);
// Not known // Not known
auto ptr3 = f(L"Unknown", "0F B6 C0 50 68 00 80 00 00 53 8B CF E8 ?? ?? ?? ??", (size_t)ptr1, 5);
if (ptr1 == nullptr if (std::ranges::any_of(ptr_cache, [](void* ptr) { return ptr == nullptr; })) {
|| ptr1_1 == nullptr
|| ptr2 == nullptr
|| ptr2_1 == nullptr
|| ptr3 == nullptr
) {
MessageBoxW(NULL, L"未能正常应用补丁,patch 未生效,请联系开发者\n这只是一个警告,可能不影响游戏运行", L"L4D2 Fix", MB_OK); MessageBoxW(NULL, L"未能正常应用补丁,patch 未生效,请联系开发者\n这只是一个警告,可能不影响游戏运行", L"L4D2 Fix", MB_OK);
} else { } else {
std::fstream file(startup_check, std::ios::out); std::fstream file(startup_check, std::ios::out);
@@ -150,5 +224,5 @@ BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserv
return TRUE; return TRUE;
} }
// Detour needs at least on exported function
void __declspec(dllexport) kuriko_export() {} void __declspec(dllexport) kuriko_export() {}
+11 -20
View File
@@ -1,4 +1,8 @@
#include "stdafx.h" #include <cassert>
#include <windows.h>
#include <cstdint>
#include <cstddef>
#include <vector>
namespace Memory namespace Memory
{ {
@@ -52,7 +56,12 @@ namespace Memory
auto s = patternBytes.size(); auto s = patternBytes.size();
auto d = patternBytes.data(); auto d = patternBytes.data();
for (auto i = offset; i < sizeOfImage - s; ++i) { auto new_offset = 0;
if (offset != 0) {
assert((intptr_t)offset > (intptr_t)&scanBytes[0]);
new_offset = offset - (intptr_t)&scanBytes[0];
}
for (auto i = new_offset; i < sizeOfImage - s; ++i) {
bool found = true; bool found = true;
for (auto j = 0ul; j < s; ++j) { for (auto j = 0ul; j < s; ++j) {
if (scanBytes[i + j] != d[j] && d[j] != -1) { if (scanBytes[i + j] != d[j] && d[j] != -1) {
@@ -87,21 +96,3 @@ namespace Memory
return (address + 4 + *reinterpret_cast<std::int32_t*>(address)); return (address + 4 + *reinterpret_cast<std::int32_t*>(address));
} }
} }
// namespace Util
// {
// std::pair<int, int> GetPhysicalDesktopDimensions() {
// if (DEVMODE devMode{ .dmSize = sizeof(DEVMODE) }; EnumDisplaySettings(nullptr, ENUM_CURRENT_SETTINGS, &devMode))
// return { devMode.dmPelsWidth, devMode.dmPelsHeight };
// return {};
// }
// int HexStringToInt(const std::string& hexString) {
// int num;
// std::stringstream ss;
// ss << std::hex << hexString;
// ss >> num;
// return num;
// }
// }
BIN
View File
Binary file not shown.
-13
View File
@@ -1,13 +0,0 @@
#pragma once
#define WIN32_LEAN_AND_MEAN
#include <cstdlib>
#include <cassert>
#include <windows.h>
#include <fstream>
#include <iostream>
#include <filesystem>
#include <string>
#include <cstdint>
#include <cstddef>
View File
-14
View File
@@ -1,14 +0,0 @@
{
"default-registry": {
"kind": "git",
"baseline": "f523208df4ae467436dc2d2eeab594fed240d552",
"repository": "https://github.com/microsoft/vcpkg"
},
"registries": [
{
"kind": "artifact",
"location": "https://github.com/microsoft/vcpkg-ce-catalog/archive/refs/heads/main.zip",
"name": "microsoft"
}
]
}
-6
View File
@@ -1,6 +0,0 @@
{
"dependencies": [
"spdlog",
"minhook"
]
}
+36
View File
@@ -0,0 +1,36 @@
-- add_requires("microsoft-proxy 2.4.0")
add_rules("mode.debug", "mode.release")
add_rules("plugin.compile_commands.autoupdate")
set_languages("cxx20", "c++20")
set_plat("windows")
set_arch("x86") -- Use "x64" for 64-bit builds
add_requires("spdlog")
add_requires("vcpkg::detours")
-- local name = "version"
-- target(name)
-- set_kind("shared")
-- add_files("src/dllmain.cpp")
-- add_packages("spdlog")
-- add_links("user32", "gdi32")
-- add_linkdirs("$(projectdir)/lib")
-- -- add_files(string.format("lib/%s.def", name), string.format("lib/%s.asm", name))
-- add_files(string.format("lib/%s.def", name))
local name = "kpatch"
target(name)
set_kind("shared")
add_files("src/dllmain.cpp")
add_packages("spdlog", "vcpkg::detours")
add_links("user32", "gdi32")
local name = "left4dead2_fix"
target(name)
set_kind("binary")
add_files("launcher/main.cpp")
add_files("assets/app.rc")
add_links("user32", "gdi32")
add_packages("vcpkg::detours")