#include "windows.h" #include "vector" #include #include #include #include #include #include #include #include "patches.h" //#include "PluginConfigApi.h" #include "PatchApplier.h" #include "PatchApplier600.h" #include "PatchApplier710.h" #include #include "patches-framework.h" #pragma comment(lib, "detours.lib") extern unsigned short game_version; /*HMODULE* hModulePtr; BOOL APIENTRY DllMain(HMODULE hModule, DWORD ul_reason_for_call, LPVOID lpReserved ) { switch (ul_reason_for_call) { case DLL_PROCESS_ATTACH: hModulePtr = &hModule; ApplyPatches(); case DLL_THREAD_ATTACH: case DLL_THREAD_DETACH: case DLL_PROCESS_DETACH: break; } return TRUE; }*/ void ApplyPatches() { if (nBuiltinPatches) { if (*(char*)0x140A570F0 == '6') game_version = 600; std::string version_string = std::to_string(game_version); version_string.insert(version_string.begin()+1, '.'); std::cout << "[Patches] Game version " + version_string << std::endl; PatchApplier* pa; switch (game_version) { case 600: pa = new PatchApplier600; break; default: pa = new PatchApplier710; } pa->ApplyPatches(); printf("[Patches] Patches applied\n"); } } void ApplyAllCustomPatches() { if (nCustomPatches) { std::cout << "[Patches] Reading custom patches in " << std::filesystem::current_path().string() << "\\patches" << std::endl; try { for (std::filesystem::path p : std::filesystem::directory_iterator("patches")) { std::string extension = std::filesystem::path(p).extension().string(); if ((extension == ".p" || extension == ".P" || extension == ".p2" || extension == ".P2")) { if (GetPrivateProfileIntW(L"plugins", std::filesystem::path(p).filename().c_str(), FALSE, CONFIG_FILE)) { std::cout << "[Patches] Reading custom patch file: " << std::filesystem::path(p).filename().string() << std::endl; ApplyCustomPatches(std::filesystem::path(p).wstring()); } else std::cout << "[Patches] Skipping disabled patch file: " << std::filesystem::path(p).filename().string() << std::endl; } } } catch (const std::filesystem::filesystem_error& e) { std::cout << "[Patches] File system error " << e.what() << " " << e.path1() << " " << e.path2() << " " << e.code() << std::endl; } std::cout << "[Patches] All custom patches applied\n"; } } void ApplyCustomPatches(std::wstring CPATCH_FILE_STRING) { LPCWSTR CPATCH_FILE = CPATCH_FILE_STRING.c_str(); std::ifstream fileStream(CPATCH_FILE_STRING); if (!fileStream.is_open()) return; std::string line; // check for BOM std::getline(fileStream, line); if (line.size() >= 3 && line.rfind("\xEF\xBB\xBF", 0) == 0) fileStream.seekg(3); else fileStream.seekg(0); while (std::getline(fileStream, line)) { if (line[0] == '#') { std::cout << "[Patches]" << line.substr(1, line.size()-1) << std::endl; continue; } if (line == "IGNORE") break; if (line.find(':') == std::string::npos || (line[0] == '/' && line[1] == '/')) continue; std::vector commentHSplit = SplitString(line, "#"); std::vector commentDSSplit = SplitString(commentHSplit[0], "//"); std::vector colonSplit = SplitString(commentDSSplit[0], ":"); if (colonSplit.size() != 2) continue; bool echo = true; if (colonSplit[0].at(0) == '@') { echo = false; colonSplit[0].at(0) = ' '; } long long int address; std::istringstream iss(colonSplit[0]); iss >> std::setbase(16) >> address; if (address == 0) std::cout << "[Patches] Custom patch address wrong: " << std::hex << address << std::endl; if (colonSplit[1].at(0) == '!') { if (echo) std::cout << "[Patches] Patching: " << std::hex << address << ":!"; std::vector fullColonSplit = SplitString(line, ":"); for (int i = 1; i < fullColonSplit[1].size(); i++) { unsigned char byte_u = fullColonSplit[1].at(i); if(byte_u=='\\' && i patch = { byte_u }; InjectCode((void*)address, patch); address++; } if (echo) std::cout << std::endl; } else { std::vector bytes = SplitString(colonSplit[1], " "); if (bytes.size() < 1) continue; std::string comment_string = ""; int comment_counter = 0; if (commentHSplit.size() > 1) { bool ignore = 1; for (std::string comment : commentHSplit) { if (ignore) { ignore = 0; continue; } comment_string = comment_string + comment; } } if (echo) std::cout << "[Patches] Patching: " << std::hex << address << ":"; for (std::string bytestring : bytes) { int byte; std::istringstream issb(bytestring); issb >> std::setbase(16) >> byte; unsigned char byte_u = byte; if (echo) { std::cout << std::hex << byte << " "; if (comment_counter < comment_string.length()) { std::cout << "(" << comment_string.at(comment_counter) << ") "; comment_counter++; } } std::vector patch = { byte_u }; InjectCode((void*)address, patch); address++; } if (echo) std::cout << std::endl; else if (comment_string.length() > 0) { std::cout << "[Patches]";; if (comment_string.at(0) != ' ') std::cout << ' '; std::cout << comment_string << std::endl; } } } fileStream.close(); } /*using namespace PluginConfig; extern "C" __declspec(dllexport) LPCWSTR GetPluginName(void) { return L"Patches"; } extern "C" __declspec(dllexport) LPCWSTR GetPluginDescription(void) { return L"Applies patches/tweaks to the game before it starts.\nThis plugin is required."; }*/