Files
PDModdingCommunity_PD-Loader/source-code/source/PD-Loader/Patches/patches.cpp
T
2021-08-11 20:07:24 +02:00

252 lines
6.2 KiB
C++

#include "windows.h"
#include "vector"
#include <tchar.h>
#include <GL/freeglut.h>
#include <iostream>
#include <fstream>
#include <filesystem>
#include <sstream>
#include <iomanip>
#include "patches.h"
//#include "PluginConfigApi.h"
#include "PatchApplier.h"
#include "PatchApplier710.h"
#include <detours.h>
#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)
{
const char* exe_ver_string = (const char*)0x140A92CB8;
if (strcmp(exe_ver_string, "7.10.00") != 0)
{
MessageBoxW(nullptr, L"Game version not 7.10. Please verify your files.", L"Patches", MB_ICONERROR);
exit(1);
}
PatchApplier* pa;
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"))
{
if (std::filesystem::path(p).filename().string()._Starts_with("._")) continue; // exclude macOS metadata
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<std::string> commentHSplit = SplitString(line, "#");
std::vector<std::string> commentDSSplit = SplitString(commentHSplit[0], "//");
std::vector<std::string> 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<std::string> fullColonSplit = SplitString(line, ":");
for (int i = 1; i < fullColonSplit[1].size(); i++)
{
unsigned char byte_u = fullColonSplit[1].at(i);
if(byte_u=='\\' && i<fullColonSplit[1].size())
{
switch (fullColonSplit[1].at(i + 1))
{
case '0':
byte_u = '\0';
i++;
break;
case 'n':
byte_u = '\n';
i++;
break;
case 't':
byte_u = '\t';
i++;
break;
case 'r':
byte_u = '\r';
i++;
break;
case 'b':
byte_u = '\b';
i++;
break;
case 'a':
byte_u = '\a';
i++;
break;
case 'f':
byte_u = '\f';
i++;
break;
case 'v':
byte_u = '\v';
i++;
break;
case '\\':
byte_u = '\\';
i++;
break;
}
}
if (echo) std::cout << byte_u;
std::vector<uint8_t> patch = { byte_u };
InjectCode((void*)address, patch);
address++;
}
if (echo) std::cout << std::endl;
}
else
{
std::vector<std::string> 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<uint8_t> 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.";
}*/