diff --git a/.gitignore b/.gitignore index b62cbf3..983a00b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,6 +1,7 @@ *.sln *.vcxproj *.vcxproj.filters + .vs/ build/ Debug/ diff --git a/OpenParrot/src/Functions/Games/ES3X/WMMT5.cpp b/OpenParrot/src/Functions/Games/ES3X/WMMT5.cpp index aab95a6..9ccbc16 100644 --- a/OpenParrot/src/Functions/Games/ES3X/WMMT5.cpp +++ b/OpenParrot/src/Functions/Games/ES3X/WMMT5.cpp @@ -1,10 +1,17 @@ #include #include "Utility/InitFunction.h" #include "Functions/Global.h" +#include +#include +#include +#include #include "MinHook.h" #include +#include #include + #ifdef _M_AMD64 + #pragma optimize("", off) #pragma comment(lib, "Ws2_32.lib") @@ -423,8 +430,9 @@ unsigned int WINAPI Hook_bind(SOCKET s, const sockaddr *addr, int namelen) { } } - +// Save data dump memory block unsigned char saveData[0x2000]; + // BASE: 0x24E0 // Campaing honor data: 2998, save 0xB8 // Story Mode Honor data: 25F0, save 0x98 @@ -499,402 +507,578 @@ unsigned char saveData[0x2000]; // return 1; //} +// setFullTune(void): Int +// If the currently loaded car is NOT fully tuned, +// updates the power and handling values to be fully +// tuned (16 for each). If they are already fully tuned, +// does not change any values. +static int setFullTune() +{ + // Car save hex address + auto carSaveBase = (uintptr_t*)((*(uintptr_t*)(imageBase + 0x1948F10)) + 0x180 + 0xa8 + 0x18); + auto powerAddress = (uintptr_t*)(*(uintptr_t*)(carSaveBase)+0x98); + auto handleAddress = (uintptr_t*)(*(uintptr_t*)(carSaveBase)+0x9C); + + // Dereference the power value from the memory address + auto powerValue = injector::ReadMemory(powerAddress, true); + auto handleValue = injector::ReadMemory(handleAddress, true); + + // If the power and handling values do not add up to fully tuned + if (powerValue + handleValue < 0x20) + { + // Car is not fully tuned, force it to the default full tune + injector::WriteMemory(powerAddress, 0x10, true); + injector::WriteMemory(handleAddress, 0x10, true); + + // Updated + return 1; + } + + // Not updated + return 0; +} + +// forceFullTune(pArguments: void*): DWORD WINAPI +// Function which runs in a secondary thread if the forceFullTune +// option is selected in the compiler. If the player's car is not fully +// tuned, it is forcibly set to max tune. If the player's car is already +// fully tuned, it is left alone. +static DWORD WINAPI forceFullTune(void* pArguments) +{ + // Loops while the program is running + while (true) { + + // Sleep for 16ms + Sleep(16); + + // Run the set full tune process + setFullTune(); + } +} + +// ******************************************** // +// ************ Debug Data Logging ************ // +// ******************************************** // + +// ************* Global Variables ************* // + +// **** String Variables + +// Debugging event log file +std::string logfile = "wmmt5_errors.txt"; + +// writeLog(filename: String, message: String): Int +// Given a filename string and a message string, appends +// the message to the given file. +static int writeLog(std::string filename, std::string message) +{ + // Log file to write to + std::ofstream eventLog; + + // Open the filename provided (append mode) + eventLog.open(filename, std::ios_base::app); + + // File open success + if (eventLog.is_open()) + { + // Write the message to the file + eventLog << message; + + // Close the log file handle + eventLog.close(); + + // Success + return 0; + } + else // File open failed + { + // Failure + return 1; + } +} + +// writeDump(filename: Char*, data: unsigned char *, size: size_t): Int +static int writeDump(char* filename, unsigned char* data, size_t size) +{ + // Open the file with the provided filename + FILE* file = fopen(filename, "wb"); + + // File opened successfully + if (file) + { + // Write the data to the file + fwrite((void*)data, 1, size, file); + + // Close the file + fclose(file); + + // Return success status + return 0; + } + else // Failed to open + { + // Return failure status + return 1; + } +} + +// Sets if saving is allowed or not static bool saveOk = false; + +// If custom car is used +bool customCar = false; + +// Sets if loading is allowed +bool loadOk = false; + +// Car save data reserved memory unsigned char carData[0xFF]; + +// Car filename string +char carFileName[0xFF]; + +// SaveOk(void): Void +// Enables saving static int SaveOk() { saveOk = true; return 1; } -char carFileName[0xFF]; -bool loadOk = false; -bool customCar = false; - -static int SaveGameData() +// loadCarFile(filename: char*): Int +// Given a filename, loads the data from +// the car file into memory. +static int loadCarFile(char* filename) { - if (!saveOk) + // Open the file with the filename + FILE* file = fopen(filename, "rb"); + + // File open OK + if (file) + { + // Get the length of the file + fseek(file, 0, SEEK_END); + int fsize = ftell(file); + + // If the file has the right size + if (fsize == 0xE0) + { + // Reset to start of the file and read it into the car data variable + fseek(file, 0, SEEK_SET); + fread(carData, fsize, 1, file); + + // Dereference the memory location for the car save data + uintptr_t carSaveLocation = *(uintptr_t*)((*(uintptr_t*)(imageBase + 0x1948F10)) + 0x180 + 0xa8 + 0x18); + + memcpy((void*)(carSaveLocation + 0x08), carData + 0x08, 8); // ?? + memcpy((void*)(carSaveLocation + 0x10), carData + 0x10, 8); // ?? + memcpy((void*)(carSaveLocation + 0x20), carData + 0x20, 8); // ?? + memcpy((void*)(carSaveLocation + 0x28), carData + 0x28, 8); // ?? + // memcpy((void*)(carSaveLocation + 0x30), carData + 0x30, 8); // Stock Colour (0x30), Custom Colour (0x34) + memcpy((void*)(carSaveLocation + 0x34), carData + 0x34, 4); // Custom Colour (0x34) + memcpy((void*)(carSaveLocation + 0x38), carData + 0x38, 8); // Rims Type (0x38), Rims Colour (0x3C) + memcpy((void*)(carSaveLocation + 0x40), carData + 0x40, 8); // Aero Type (0x40), Hood Type (0x44) + memcpy((void*)(carSaveLocation + 0x50), carData + 0x50, 8); // Wing Type (0x50), Mirror Type (0x54) + memcpy((void*)(carSaveLocation + 0x58), carData + 0x58, 8); // Body Sticker Type (0x58), Variant (0x5C) + memcpy((void*)(carSaveLocation + 0x68), carData + 0x68, 8); // ?? + memcpy((void*)(carSaveLocation + 0x7C), carData + 0x7C, 1); // Neon Type + memcpy((void*)(carSaveLocation + 0x80), carData + 0x80, 8); // Trunk Colour (0x80), Plate Frame (0x84) + memcpy((void*)(carSaveLocation + 0x88), carData + 0x88, 8); // Plate Frame Colour (0x8A) + memcpy((void*)(carSaveLocation + 0x90), carData + 0x90, 8); // ?? + memcpy((void*)(carSaveLocation + 0x98), carData + 0x98, 8); // Power (0x98), Handling (0x9C) + memcpy((void*)(carSaveLocation + 0xA0), carData + 0xA0, 8); // Rank (0xA4) + memcpy((void*)(carSaveLocation + 0xA8), carData + 0xA8, 8); // ?? + memcpy((void*)(carSaveLocation + 0xB8), carData + 0xB8, 8); // ?? + memcpy((void*)(carSaveLocation + 0xC8), carData + 0xC8, 8); // ?? + memcpy((void*)(carSaveLocation + 0xD8), carData + 0xD8, 8); // ?? + } + + // Disable loading + loadOk = false; + + // Close the file + fclose(file); + + // Success return 1; + } - memset(saveData, 0, 0x2000); - uintptr_t value = *(uintptr_t*)(imageBase + 0x1948F10); - value = *(uintptr_t*)(value + 0x108); - memcpy(saveData, (void *)value, 0x340); - FILE* file = fopen("openprogress.sav", "wb"); - fwrite(saveData, 1, 0x2000, file); - fclose(file); + // Failed + return 0; +} +// loadCarData(filepath: char*): Void +// Given a filepath, attempts to load a +// car file (either custom.car or specific +// car file) from that folder. +static int loadCarData(char* filepath) +{ + // Sleep for 1 second + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + + // Custom car disabled by default + customCar = false; + + // Miles path string + char carPath[0xFF]; + + // Set the milepath memory to zero + memset(carPath, 0, 0xFF); + + // Copy the file path to the miles path + strcpy(carPath, filepath); + + // Append the mileage filename to the string + strcat(carPath, "\\OpenParrot_Cars"); + + // Create the OpenParrot_cars directory at the given filepath + std::filesystem::create_directories(carPath); + + // Get the path to the custom car file + sprintf(carFileName, "%s\\custom.car", carPath); + + // If the custom car file exists + if (FileExists(carFileName)) + { + // Load the custom car file + loadCarFile(carFileName); + + // Enable custom car switch + customCar = true; + } + + // Empty the car filename string + memset(carFileName, 0, 0xFF); + + // Get the path to the specific car file + sprintf(carFileName, "%s\\%08X.car", carPath, *(DWORD*)(*(uintptr_t*)(*(uintptr_t*)(imageBase + 0x1948F10) + 0x180 + 0xa8 + 0x18) + 0x2C)); + + // If the specific car file exists + if (FileExists(carFileName)) + { + // Load the car file + loadCarFile(carFileName); + } + + // If the force full tune switch is set + if (ToBool(config["Tune"]["Force Full Tune"])) + { + // Create the force full tune thread + // CreateThread(0, 0, forceFullTune, 0, 0, 0); + + // Set the car to be fully tuned + setFullTune(); + } + + // Success + return 1; +} + +static int saveCarData(char* filepath) +{ // Car Profile saving memset(carData, 0, 0xFF); memset(carFileName, 0, 0xFF); - memcpy(carData, (void *)*(uintptr_t*)(*(uintptr_t*)(imageBase + 0x1948F10) + 0x180 + 0xa8 + 0x18), 0xE0); - CreateDirectoryA("OpenParrot_Cars", nullptr); - if(customCar) + + // Get the hex address for the start of the save data block + uintptr_t saveDataBase = *(uintptr_t*)(imageBase + 0x1948F10); + + // Address where car save data starts + uintptr_t carSaveBase = *(uintptr_t*)(saveDataBase + 0x108); + + // Miles path string + char carPath[0xFF]; + + // Set the milepath memory to zero + memset(carPath, 0, 0xFF); + + // Copy the file path to the miles path + strcpy(carPath, filepath); + + // Append the mileage filename to the string + strcat(carPath, "\\OpenParrot_Cars"); + + // CreateDirectoryA(carPath, nullptr); + + // Create the cars path folder + std::filesystem::create_directories(carPath); + + // Copy the 0xE0 bytes from memory to the car data array + memcpy(carData, (void*)*(uintptr_t*)(saveDataBase + 0x180 + 0xa8 + 0x18), 0xE0); + + // If custom car is set + if (customCar) { - sprintf(carFileName, ".\\OpenParrot_Cars\\custom.car"); + // Save the file to custom.car + sprintf(carPath, "%s\\custom.car", carPath); } - else + else // Custom car is not set { - sprintf(carFileName, ".\\OpenParrot_Cars\\%08X.car", *(DWORD*)(*(uintptr_t*)(*(uintptr_t*)(imageBase + 0x1948F10) + 0x180 + 0xa8 + 0x18) + 0x2C)); + // Save the file to the specific car filename + sprintf(carPath, "%s\\%08X.car", carPath, *(DWORD*)(*(uintptr_t*)(*(uintptr_t*)(imageBase + 0x1948F10) + 0x180 + 0xa8 + 0x18) + 0x2C)); } - FILE *carSave = fopen(carFileName, "wb"); - fwrite(carData, 1, 0xE0, file); - fclose(carSave); + + // Open the file at the given car path + FILE* carFile = fopen(carPath, "wb"); + + // Write the data from the array to the file + fwrite(carData, 1, 0xE0, carFile); + fclose(carFile); + + // Success + return 1; +} + +static int saveStoryData(char* filepath) +{ + // Miles path string + char storyPath[0xFF]; + + // Set the milepath memory to zero + memset(storyPath, 0, 0xFF); + + // Copy the file path to the miles path + strcpy(storyPath, filepath); + + // Append the mileage filename to the string + strcat(storyPath, "\\openprogress.sav"); + + // Save story data + + // Address where player save data starts + uintptr_t saveDataBase = *(uintptr_t*)(imageBase + 0x1948F10); + + // Zero out save data binary + memset(saveData, 0, 0x2000); + + // Address where the story save data starts + uintptr_t storySaveBase = *(uintptr_t*)(saveDataBase + 0x108); + + // Copy to saveData from the story save data index + memcpy(saveData, (void*)storySaveBase, 0x340); + + // Dump the save data to openprogress.sav + writeDump(storyPath, saveData, 0x2000); + //SaveStoryData(); //SaveCampaingHonorData(); //SaveStoryModeNoLoseHonorData(); //SaveOtherHonorData(); //SaveCampaingHonorData2(); - saveOk = false; + + // Success return 1; } -uintptr_t saveGameOffset; - -//static int LoadCampaingHonorData2() -//{ -// memset(saveData, 0x0, 0x1000); -// FILE* file = fopen(V("CampaignHonorData.sav"), V("rb")); -// if (file) -// { -// fseek(file, 0, SEEK_END); -// int fsize = ftell(file); -// if (fsize == 0x100) -// { -// fseek(file, 0, SEEK_SET); -// fread(saveData, fsize, 1, file); -// uintptr_t imageBase = (uintptr_t)GetModuleHandleA(0); -// uintptr_t value = *(uintptr_t*)(imageBase + 0x1948F10); -// value += 0x2698; -// memcpy((void *)value, saveData, 0x48); -// } -// fclose(file); -// } -// return 1; -//} -// -//static int LoadOtherHonorData() -//{ -// memset(saveData, 0x0, 0x1000); -// FILE* file = fopen(V("OtherHonorData.sav"), V("rb")); -// if (file) -// { -// fseek(file, 0, SEEK_END); -// int fsize = ftell(file); -// if (fsize == 0x100) -// { -// fseek(file, 0, SEEK_SET); -// fread(saveData, fsize, 1, file); -// uintptr_t imageBase = (uintptr_t)GetModuleHandleA(0); -// uintptr_t value = *(uintptr_t*)(imageBase + 0x1948F10); -// value += 0x2A90; -// memcpy((void *)value, saveData, 0x60); -// } -// fclose(file); -// } -// return 1; -//} -// -//static int LoadStoryModeNoLoseHonorData() -//{ -// memset(saveData, 0x0, 0x1000); -// FILE* file = fopen(V("StoryModeNoLoseHonorData.sav"), V("rb")); -// if (file) -// { -// fseek(file, 0, SEEK_END); -// int fsize = ftell(file); -// if (fsize == 0x100) -// { -// fseek(file, 0, SEEK_SET); -// fread(saveData, fsize, 1, file); -// uintptr_t imageBase = (uintptr_t)GetModuleHandleA(0); -// uintptr_t value = *(uintptr_t*)(imageBase + 0x1948F10); -// value += 0x2C80; -// //memcpy((void *)value, saveData, 0x10); -// value += 0x18; -// memcpy((void *)value, saveData, 0x28); -// } -// fclose(file); -// } -// return 1; -//} -// -//static int LoadCampaingHonorData() -//{ -// memset(saveData, 0x0, 0x1000); -// FILE* file = fopen(V("campaing.sav"), V("rb")); -// if (file) -// { -// fseek(file, 0, SEEK_END); -// int fsize = ftell(file); -// if (fsize == 0x100) -// { -// fseek(file, 0, SEEK_SET); -// fread(saveData, fsize, 1, file); -// uintptr_t imageBase = (uintptr_t)GetModuleHandleA(0); -// uintptr_t value = *(uintptr_t*)(imageBase + 0x1948F10); -// value += 0x24E0; -// memcpy((void *)value, saveData, 0xB8); -// } -// fclose(file); -// } -// return 1; -//} -// -//static int LoadStoryData() -//{ -// memset(saveData, 0x0, 0x1000); -// FILE* file = fopen(V("story.sav"), V("rb")); -// if (file) -// { -// fseek(file, 0, SEEK_END); -// int fsize = ftell(file); -// if (fsize == 0x100) -// { -// fseek(file, 0, SEEK_SET); -// fread(saveData, fsize, 1, file); -// uintptr_t imageBase = (uintptr_t)GetModuleHandleA(0); -// uintptr_t value = *(uintptr_t*)(imageBase + 0x1948F10); -// value += 0x25F0; -// memcpy((void *)value, saveData, 0x98); -// } -// fclose(file); -// } -// return 1; -//} - -static int LoadGameData() +static int loadStoryData(char* filepath) { - saveOk = false; + // Zero out the save data array memset(saveData, 0x0, 0x2000); - FILE* file = fopen("openprogress.sav", "rb"); + + // Miles path string + char storyPath[0xFF]; + + // Set the milepath memory to zero + memset(storyPath, 0, 0xFF); + + // Copy the file path to the miles path + strcpy(storyPath, filepath); + + // Append the mileage filename to the string + strcat(storyPath, "\\openprogress.sav"); + + // Address where player save data starts + uintptr_t saveDataBase = *(uintptr_t*)(imageBase + 0x1948F10); + + // Open the openprogress file with read privileges + FILE* file = fopen(storyPath, "rb"); + + // If the file exists if (file) { + // Get all of the contents from the file fseek(file, 0, SEEK_END); + + // Get the size of the file int fsize = ftell(file); + + // Check file is correct size if (fsize == 0x2000) { + // Reset seek index to start fseek(file, 0, SEEK_SET); + + // Read all of the contents of the file into saveData fread(saveData, fsize, 1, file); - uintptr_t value = *(uintptr_t*)(imageBase + 0x1948F10); - value = *(uintptr_t*)(value + 0x108); - // First page - //memcpy((void *)(value), saveData, 0x48); - memcpy((void *)(value + 0x10), saveData + 0x10, 0x20); - memcpy((void *)(value + 0x40), saveData + 0x40, 0x08); - //memcpy((void *)(value + 0x48 + 8), saveData + 0x48 + 8, 0x20); - memcpy((void *)(value + 0x48 + 8), saveData + 0x48 + 8, 0x08); - memcpy((void *)(value + 0x48 + 24), saveData + 0x48 + 24, 0x08); - memcpy((void *)(value + 0x48 + 32), saveData + 0x48 + 32, 0x08); + // Story save data offset + uintptr_t saveStoryBase = *(uintptr_t*)(saveDataBase + 0x108); - // Second page - value += 0x110; - memcpy((void *)(value), saveData + 0x110, 0x90); - value -= 0x110; + // 0x00 - 70 23 - Should be able to use this to figure out what game a save is from - // Third Page - value += 0x1B8; - memcpy((void *)(value), saveData + 0x1B8, 0x48); - memcpy((void *)(value + 0x48 + 8), saveData + 0x1B8 + 0x48 + 8, 0x28); - value -= 0x1B8; + // (Mostly) discovered story data - // Fourth page - value += 0x240; - memcpy((void *)(value), saveData + 0x240, 0x68); - value -= 0x240; - - // Fifth page - value += 0x2B8; - memcpy((void *)(value), saveData + 0x2B8, 0x88); - value -= 0x2B8; + memcpy((void*)(saveStoryBase + 0x118), saveData + 0x118, 0x8); // Total Wins (0x118) + memcpy((void*)(saveStoryBase + 0x120), saveData + 0x120, 0x8); // Chapter Progress (0x120) (Bitmask), Current Chapter (0x124) + memcpy((void*)(saveStoryBase + 0x128), saveData + 0x128, 0x8); // ?? + memcpy((void*)(saveStoryBase + 0x130), saveData + 0x130, 0x8); // ?? + memcpy((void*)(saveStoryBase + 0x138), saveData + 0x138, 0x8); // Win Streak (0x138) + memcpy((void*)(saveStoryBase + 0x140), saveData + 0x140, 0x8); // ?? + memcpy((void*)(saveStoryBase + 0x148), saveData + 0x148, 0x8); // ?? + memcpy((void*)(saveStoryBase + 0x150), saveData + 0x150, 0x8); // Locked Chapters (0x150) (Bitmask) + memcpy((void*)(saveStoryBase + 0x158), saveData + 0x158, 0x8); // ?? + // Save data loaded successfully loadOk = true; - - //+ 0x80 - - //+ [0x340] - - // [[[[0000000005CE5850] + 108] + 340] + 50] + 50 - // [[[[0000000005CE5850] + 108] + 340] + 50] + 54 - // wmn5r.exe + 1948BF8 - //TA stuff - - //[[[[magic_rva]+108]+340]+50] - - //value += 0x24E0; - // First chunk - //memcpy((void *)(value + 0x16), saveData + 0x16, 0x28); - //// - //memcpy((void *)(value + 0x40), saveData + 0x40, 0x18); - //// - //memcpy((void *)(value + 0x60), saveData + 0x60, 0x20); - //// - //memcpy((void *)(value + 0x90), saveData + 0x90, 0x28); - //// - //memcpy((void *)(value + 0xC0), saveData + 0xC0, 0x10); - //// - //memcpy((void *)(value + 0xD8), saveData + 0xD8, 0x28); // OK - //// - //memcpy((void *)(value + 0x110), saveData + 0x110, 0x98); - //// - //memcpy((void *)(value + 0x1B8), saveData + 0x1B8, 0x48); - //// - //memcpy((void *)(value + 0x208), saveData + 0x208, 0x28); - //// - //memcpy((void *)(value + 0x240), saveData + 0x240, 0x68); - //// - //memcpy((void *)(value + 0x2B8), saveData + 0x2B8, 0x88); - // - //memcpy((void *)(value + 0x370), saveData + 0x370, 0x10); - //// - //memcpy((void *)(value + 0x388), saveData + 0x388, 0x90); - //// - //memcpy((void *)(value + 0x420), saveData + 0x420, 0x18); - //// - //memcpy((void *)(value + 0x440), saveData + 0x440, 0x18); - //// - //memcpy((void *)(value + 0x460), saveData + 0x460, 0x48); - //// - //memcpy((void *)(value + 0x4B8), saveData + 0x4B8, 0xB8); - //// - //memcpy((void *)(value + 0x578), saveData + 0x578, 0x08); - //// - //memcpy((void *)(value + 0x5A8), saveData + 0x5A8, 0x68); - //// - //memcpy((void *)(value + 0x628), saveData + 0x628, 0x48); - //// - //memcpy((void *)(value + 0x688), saveData + 0x688, 0x48); - //// - //memcpy((void *)(value + 0x6E8), saveData + 0x6E8, 0xA8); - //// - //memcpy((void *)(value + 0x7A0), saveData + 0x7A0, 0x10); - //// - //memcpy((void *)(value + 0x7B8), saveData + 0x7B8, 0x28); - //// - //memcpy((void *)(value + 0x7E8), saveData + 0x7E8, 0x10); - //// - ////memcpy((void *)(value + 0x800), saveData + 0x800, 0x48); // Problem - ////// - //memcpy((void *)(value + 0x850), saveData + 0x850, 0x08); - // - //memcpy((void *)(value + 0x860), saveData + 0x860, 0x08); - ////// - //memcpy((void *)(value + 0x870), saveData + 0x870, 0x18); - //// - //memcpy((void *)(value + 0x890), saveData + 0x890, 0x40); - //// - //memcpy((void *)(value + 0x8E0), saveData + 0x8E0, 0x10); - //// - //memcpy((void *)(value + 0x8F8), saveData + 0x8F8, 0x28); - //// - //memcpy((void *)(value + 0x928), saveData + 0x928, 0x10); - //// - //memcpy((void *)(value + 0x940), saveData + 0x940, 0x48); // Problem } fclose(file); } + //LoadStoryData(); //LoadCampaingHonorData(); //LoadStoryModeNoLoseHonorData(); //LoadOtherHonorData(); //LoadCampaingHonorData2(); + + // Success status return 1; } -static void LoadWmmt5CarData() +static int SaveGameData() { - if (!loadOk) - return; - customCar = false; - memset(carData, 0, 0xFF); - memset(carFileName, 0, 0xFF); - CreateDirectoryA("OpenParrot_Cars", nullptr); + // Saving is disabled + if (!saveOk) + return 1; - // check for custom car - sprintf(carFileName, ".\\OpenParrot_Cars\\custom.car"); - if (FileExists(carFileName)) + // Miles path string + char savePath[0xFF]; + + // Set the milepath memory to zero + memset(savePath, 0, 0xFF); + + // Write the '.' into the load path + // sprintf(savePath, ".\\SaveData"); + sprintf(savePath, "."); + + // Seperate save file / cars per user profile + if (ToBool(config["Save"]["Save Per Custom Name"])) { - FILE* file = fopen(carFileName, "rb"); - if (file) + // Get the profile name from the + std::string name = config["General"]["CustomName"]; + + // Add the c string version of the profile name to the path + sprintf(savePath, "%s\\%s", savePath, name.c_str()); + } + + // Seperate miles / story per car + if (ToBool(config["Save"]["Save Per Car"])) + { + // Need to get the hex code for the selected car + + // Address where player save data starts + uintptr_t saveDataBase = *(uintptr_t*)(imageBase + 0x1948F10); + + // Address where the car save data starts + uintptr_t carSaveBase = *(uintptr_t*)(saveDataBase + 0x108); + + // If custom car is set + if (customCar) { - fseek(file, 0, SEEK_END); - int fsize = ftell(file); - if (fsize == 0xE0) - { - fseek(file, 0, SEEK_SET); - fread(carData, fsize, 1, file); - uintptr_t carSaveLocation = *(uintptr_t*)((*(uintptr_t*)(imageBase + 0x1948F10)) + 0x180 + 0xa8 + 0x18); - memcpy((void *)(carSaveLocation + 0x08), carData + 0x08, 8); - memcpy((void *)(carSaveLocation + 0x10), carData + 0x10, 8); - memcpy((void *)(carSaveLocation + 0x20), carData + 0x20, 8); - memcpy((void *)(carSaveLocation + 0x28), carData + 0x28, 8); - memcpy((void *)(carSaveLocation + 0x30), carData + 0x30, 8); - memcpy((void *)(carSaveLocation + 0x38), carData + 0x38, 8); - memcpy((void *)(carSaveLocation + 0x40), carData + 0x40, 8); - memcpy((void *)(carSaveLocation + 0x50), carData + 0x50, 8); - memcpy((void *)(carSaveLocation + 0x58), carData + 0x58, 8); - memcpy((void *)(carSaveLocation + 0x68), carData + 0x68, 8); - memcpy((void *)(carSaveLocation + 0x7C), carData + 0x7C, 1); //should add neons - memcpy((void *)(carSaveLocation + 0x80), carData + 0x80, 8); - memcpy((void *)(carSaveLocation + 0x88), carData + 0x88, 8); - memcpy((void *)(carSaveLocation + 0x90), carData + 0x90, 8); - memcpy((void *)(carSaveLocation + 0x98), carData + 0x98, 8); - memcpy((void *)(carSaveLocation + 0xA0), carData + 0xA0, 8); - memcpy((void *)(carSaveLocation + 0xA8), carData + 0xA8, 8); - memcpy((void *)(carSaveLocation + 0xB8), carData + 0xB8, 8); - memcpy((void *)(carSaveLocation + 0xC8), carData + 0xC8, 8); - memcpy((void *)(carSaveLocation + 0xD8), carData + 0xD8, 8); - //memcpy((void *)(carSaveLocation + 0xE0), carData + 0xE0, 8); - customCar = true; - } - loadOk = false; - fclose(file); - return; + // Add the car id to the save path + sprintf(savePath, "%s\\custom", savePath); + } + else // Custom car is not set + { + // Add the custom folder to the save path + sprintf(savePath, "%s\\%08X", savePath, *(DWORD*)(*(uintptr_t*)(*(uintptr_t*)(imageBase + 0x1948F10) + 0x180 + 0xa8 + 0x18) + 0x2C)); } } - memset(carFileName, 0, 0xFF); - // Load actual car if available - sprintf(carFileName, ".\\OpenParrot_Cars\\%08X.car", *(DWORD*)(*(uintptr_t*)(*(uintptr_t*)(imageBase + 0x1948F10) + 0x180 + 0xa8 + 0x18) + 0x2C)); - if(FileExists(carFileName)) + // Ensure the directory exists + std::filesystem::create_directories(savePath); + + // Save the car save file + saveCarData(savePath); + + // Save the openprogress.sav file + saveStoryData(savePath); + + // Disable saving + saveOk = false; + + // Success + return 1; +} + +static int loadGameData() +{ + // Disable saving + saveOk = false; + + // Miles path string + char loadPath[0xFF]; + + // Set the milepath memory to zero + memset(loadPath, 0, 0xFF); + + // Write the '.' into the load path + // sprintf(loadPath, ".\\SaveData"); + sprintf(loadPath, "."); + + // Seperate save file / cars per user profile + if (ToBool(config["Save"]["Save Per Custom Name"])) { - FILE* file = fopen(carFileName, "rb"); - if (file) + // Get the profile name from the + std::string name = config["General"]["CustomName"]; + + // Add the c string version of the profile name to the path + sprintf(loadPath, "%s\\%s", loadPath, name.c_str()); + } + + // Seperate miles / story per car + if (ToBool(config["Save"]["Save Per Car"])) + { + // Need to get the hex code for the selected car + + // Address where player save data starts + uintptr_t saveDataBase = *(uintptr_t*)(imageBase + 0x1948F10); + + // Address where the car save data starts + uintptr_t carSaveBase = *(uintptr_t*)(saveDataBase + 0x108); + + // If custom car is set + if (customCar) { - fseek(file, 0, SEEK_END); - int fsize = ftell(file); - if (fsize == 0xE0) - { - fseek(file, 0, SEEK_SET); - fread(carData, fsize, 1, file); - uintptr_t carSaveLocation = *(uintptr_t*)((*(uintptr_t*)(imageBase + 0x1948F10)) + 0x180 + 0xa8 + 0x18); - memcpy((void *)(carSaveLocation + 0x08), carData + 0x08, 8); - memcpy((void *)(carSaveLocation + 0x10), carData + 0x10, 8); - memcpy((void *)(carSaveLocation + 0x20), carData + 0x20, 8); - memcpy((void *)(carSaveLocation + 0x28), carData + 0x28, 8); - memcpy((void *)(carSaveLocation + 0x30), carData + 0x30, 8); - memcpy((void *)(carSaveLocation + 0x38), carData + 0x38, 8); - memcpy((void *)(carSaveLocation + 0x40), carData + 0x40, 8); - memcpy((void *)(carSaveLocation + 0x50), carData + 0x50, 8); - memcpy((void *)(carSaveLocation + 0x58), carData + 0x58, 8); - memcpy((void *)(carSaveLocation + 0x68), carData + 0x68, 8); - memcpy((void *)(carSaveLocation + 0x7C), carData + 0x7C, 1); //should add neons - memcpy((void *)(carSaveLocation + 0x80), carData + 0x80, 8); - memcpy((void *)(carSaveLocation + 0x88), carData + 0x88, 8); - memcpy((void *)(carSaveLocation + 0x90), carData + 0x90, 8); - memcpy((void *)(carSaveLocation + 0x98), carData + 0x98, 8); - memcpy((void *)(carSaveLocation + 0xA0), carData + 0xA0, 8); - memcpy((void *)(carSaveLocation + 0xA8), carData + 0xA8, 8); - memcpy((void *)(carSaveLocation + 0xB8), carData + 0xB8, 8); - memcpy((void *)(carSaveLocation + 0xC8), carData + 0xC8, 8); - memcpy((void *)(carSaveLocation + 0xD8), carData + 0xD8, 8); - //memcpy((void *)(carSaveLocation + 0xE0), carData + 0xE0, 8); - } - fclose(file); + // Add the car id to the save path + sprintf(loadPath, "%s\\custom", loadPath); + } + else // Custom car is not set + { + // Add the custom folder to the save path + sprintf(loadPath, "%s\\%08X", loadPath, *(DWORD*)(*(uintptr_t*)(*(uintptr_t*)(imageBase + 0x1948F10) + 0x180 + 0xa8 + 0x18) + 0x2C)); } } - loadOk = false; + + // Ensure the directory exists + std::filesystem::create_directories(loadPath); + + // Load the car save file + loadCarData(loadPath); + + // Load the openprogress.sav file + loadStoryData(loadPath); + + // Success + return 1; +} + +static void loadGame() +{ + // Runs after car data is loaded + + // Load story data thread + std::thread t1(loadGameData); + t1.detach(); } static int ReturnTrue() @@ -1150,6 +1334,7 @@ static InitFunction Wmmt5Func([]() hookPort = "COM3"; imageBase = (uintptr_t)GetModuleHandleA(0); + MH_Initialize(); // Hook dongle funcs @@ -1162,8 +1347,6 @@ static InitFunction Wmmt5Func([]() MH_CreateHookApi(L"hasp_windows_x64_109906.dll", "hasp_login", Hook_hasp_login, NULL); MH_CreateHookApi(L"WS2_32", "bind", Hook_bind, reinterpret_cast(&pbind)); - - GenerateDongleData(isTerminal); // Patch some check @@ -1311,7 +1494,9 @@ static InitFunction Wmmt5Func([]() // skip erasing of temp card data injector::WriteMemory(imageBase + 0x8DEBC3, 0xEB, true); // Skip erasing of temp card - safeJMP(imageBase + 0x54DCE1, LoadGameData); + + // Old story load func + // safeJMP(imageBase + 0x54DCE1, LoadGameData); safeJMP(imageBase + 0x5612F0, ReturnTrue); safeJMP(imageBase + 0x5753C0, ReturnTrue); safeJMP(imageBase + 0x57DF10, ReturnTrue); @@ -1329,8 +1514,12 @@ static InitFunction Wmmt5Func([]() safeJMP(imageBase + 0x5507A0, ReturnTrue); safeJMP(imageBase + 0x561290, ReturnTrue); - safeJMP(imageBase + 0x5A0AE8, LoadWmmt5CarData); + + // safeJMP(imageBase + 0x5A0AE8, LoadWmmt5CarData); + // Load story and car data + safeJMP(imageBase + 0x5A0AE8, loadGame); + // crash fix //safeJMP(imageBase + 0xAD6F28, WmmtOperatorDelete); //safeJMP(imageBase + 0xAD6F4C, WmmtMemset); diff --git a/OpenParrot/src/Functions/Games/ES3X/WMMT5DXPlus.cpp b/OpenParrot/src/Functions/Games/ES3X/WMMT5DXPlus.cpp index 9a82c40..519ba00 100644 --- a/OpenParrot/src/Functions/Games/ES3X/WMMT5DXPlus.cpp +++ b/OpenParrot/src/Functions/Games/ES3X/WMMT5DXPlus.cpp @@ -1,6 +1,7 @@ #include #include "Utility/InitFunction.h" #include "Functions/Global.h" +#include #include #include #include @@ -19,45 +20,9 @@ static bool isFreePlay; static bool isEventMode2P; static bool isEventMode4P; const char *ipaddrdxplus; -/* -// Data for IC card, Force Feedback etc OFF. -unsigned char settingData[408] = { - 0x1F, 0x8B, 0x08, 0x08, 0x53, 0x6A, 0x8B, 0x5A, 0x00, 0x03, 0x46, 0x73, - 0x65, 0x74, 0x74, 0x69, 0x6E, 0x67, 0x2E, 0x6C, 0x75, 0x61, 0x00, 0x85, - 0x93, 0x5B, 0x6F, 0x82, 0x30, 0x14, 0xC7, 0xDF, 0xF9, 0x14, 0x7E, 0x01, - 0x17, 0x11, 0xE7, 0xDC, 0xC3, 0x1E, 0x14, 0x65, 0x9A, 0x48, 0x66, 0x94, - 0x68, 0xB2, 0xB7, 0x5A, 0x8E, 0xD2, 0xD8, 0x8B, 0x29, 0xED, 0x16, 0xBF, - 0xFD, 0x5A, 0xA8, 0x50, 0xB2, 0x65, 0xF2, 0x40, 0xF8, 0xFF, 0xCE, 0x85, - 0x73, 0x69, 0xFB, 0xFD, 0xFF, 0x9F, 0xC0, 0xBE, 0x7A, 0x25, 0x28, 0x45, - 0xF8, 0xF9, 0x89, 0x6A, 0x14, 0x3C, 0x08, 0xE8, 0x07, 0x01, 0x8B, 0x11, - 0x25, 0xC7, 0x25, 0xE2, 0x39, 0x85, 0x18, 0xB8, 0x02, 0xD9, 0x7B, 0xEB, - 0x45, 0xC3, 0x97, 0xF1, 0xC4, 0x99, 0xA6, 0x18, 0x03, 0x6D, 0x2C, 0x03, - 0x47, 0x67, 0x12, 0x5D, 0xE0, 0x17, 0x4D, 0x85, 0x12, 0xB2, 0xA1, 0xCF, - 0x61, 0xE8, 0x78, 0x26, 0x34, 0x2E, 0xD6, 0x70, 0x52, 0x86, 0x0E, 0x07, - 0xA3, 0x89, 0x8F, 0xB7, 0xE4, 0x5C, 0x58, 0x1E, 0x8E, 0xA2, 0x68, 0xEC, - 0x1B, 0x32, 0x71, 0xFD, 0x0B, 0xCF, 0x84, 0x52, 0x82, 0xB5, 0x89, 0x04, - 0xE1, 0x71, 0xA1, 0x15, 0x58, 0xDF, 0x80, 0xCD, 0xF4, 0x2D, 0x46, 0x32, - 0x8F, 0x45, 0x69, 0x73, 0x46, 0x01, 0x7B, 0x47, 0x0C, 0x9C, 0x1A, 0x5A, - 0x6F, 0x6E, 0x66, 0xA3, 0x3D, 0x92, 0x68, 0x4A, 0x63, 0xA1, 0x65, 0x79, - 0x67, 0x23, 0xC3, 0x24, 0xC0, 0x86, 0xA2, 0x5B, 0x9D, 0x72, 0x83, 0x8F, - 0xAB, 0xBC, 0x6E, 0x72, 0x85, 0x6D, 0xF2, 0xED, 0xB7, 0xAF, 0xF6, 0xC0, - 0xF3, 0xFB, 0x10, 0xD2, 0xB3, 0x6F, 0x4F, 0x84, 0xC4, 0x90, 0x00, 0xE4, - 0x47, 0x84, 0x2F, 0x35, 0x3A, 0x10, 0x5E, 0x4E, 0x79, 0xBE, 0x05, 0x86, - 0xCC, 0x57, 0x9D, 0x7F, 0xF1, 0x65, 0x06, 0x96, 0x8A, 0x1C, 0x6A, 0x97, - 0x46, 0xCE, 0x49, 0x55, 0x8F, 0x8F, 0x4C, 0xA1, 0xDC, 0xD5, 0x18, 0x53, - 0x51, 0x42, 0x76, 0xBB, 0x82, 0x6B, 0xCC, 0xCA, 0x9D, 0xE6, 0x46, 0xBD, - 0x8E, 0x9D, 0x4C, 0x45, 0x47, 0x66, 0x1A, 0x7C, 0x79, 0x80, 0xBC, 0x63, - 0x2D, 0xB4, 0x2F, 0x13, 0x49, 0x7C, 0xB9, 0x43, 0xCA, 0x97, 0xF3, 0x6A, - 0x36, 0x56, 0x56, 0x2B, 0xD9, 0x20, 0x0E, 0xB4, 0x2E, 0xD5, 0x8E, 0x7B, - 0x2F, 0xAC, 0x08, 0x8D, 0x9A, 0x2A, 0x25, 0x11, 0x56, 0x2D, 0xF8, 0x38, - 0x9D, 0x28, 0xE1, 0xD0, 0x76, 0x6B, 0xD2, 0xE1, 0x8B, 0xA1, 0xE6, 0xD0, - 0xD6, 0x20, 0x23, 0x0C, 0x3E, 0x05, 0xBF, 0xB7, 0x66, 0x77, 0x6F, 0x91, - 0xF9, 0xE3, 0xDA, 0x1D, 0x14, 0xCF, 0x69, 0x69, 0x16, 0xD7, 0x04, 0x4F, - 0x5A, 0x9E, 0x12, 0xEE, 0xE7, 0xDC, 0x69, 0xC6, 0x40, 0x5A, 0x63, 0x27, - 0xA0, 0x63, 0xE9, 0x86, 0x3C, 0xBC, 0x37, 0xD5, 0x4D, 0x5B, 0x7C, 0x24, - 0x8F, 0x3D, 0x7F, 0x00, 0x10, 0x1E, 0x34, 0xD9, 0xB5, 0x03, 0x00, 0x00 -}; -*/ + +// MUST DISABLE IC CARD, FFB MANUALLY N MT5DX+ + // FOR FREEPLAY unsigned char dxpterminalPackage1_Free[79] = { 0x01, 0x04, 0x4B, 0x00, 0x12, 0x14, 0x0A, 0x00, 0x10, 0x04, 0x18, 0x00, @@ -210,7 +175,6 @@ unsigned char dxpterminalPackage6_Coin[139] = { 0x00, 0x28, 0x00, 0xBD, 0x07, 0xCF, 0xDC }; - //Event mode 2P unsigned char dxpterminalPackage1_Event4P[79] = { 0x01, 0x04, 0x44, 0x00, 0x12, 0x0e, 0x0a, 0x00, 0x10, 0x04, 0x18, 0x00, @@ -406,11 +370,24 @@ unsigned int dxpHook_hasp_write(int hasp_handle, int hasp_fileid, unsigned int o return HASP_STATUS_OK; } - - +// Save data dump memory block unsigned char saveDatadxp[0x2000]; + +// Mile data dump memory block unsigned char mileDatadxp[0x08]; +// Star data dump memory block +unsigned char starDataDxp[0x40]; + +//set system date patch by pockywitch +typedef bool (WINAPI* SETSYSTEMTIME)(SYSTEMTIME* in); +SETSYSTEMTIME pSetSystemTime = NULL; + +bool WINAPI Hook_SetSystemTime(SYSTEMTIME* in) +{ + return TRUE; +} + // BASE: 0x24E0 // Campaing honor data: 2998, save 0xB8 // Story Mode Honor data: 25F0, save 0x98 @@ -485,120 +462,336 @@ unsigned char mileDatadxp[0x08]; // return 1; //} -//set system date patch by pockywitch -typedef bool (WINAPI* SETSYSTEMTIME)(SYSTEMTIME* in); -SETSYSTEMTIME pSetSystemTime = NULL; - -bool WINAPI Hook_SetSystemTime(SYSTEMTIME* in) +// setFullTune(void): Int +// If the currently loaded car is NOT fully tuned, +// updates the power and handling values to be fully +// tuned (16 for each). If they are already fully tuned, +// does not change any values. +static int setFullTune() { - return TRUE; -} + // Get the memory addresses for the car base save, power and handling values + auto carSaveBase = (uintptr_t*)(*(uintptr_t*)(imageBasedxplus + 0x01F7D578) + 0x268); + auto powerAddress = (uintptr_t*)(*(uintptr_t*)(carSaveBase)+0xAC); + auto handleAddress = (uintptr_t*)(*(uintptr_t*)(carSaveBase)+0xB8); -static DWORD WINAPI forceFT(void* pArguments) -{ - while (true) { - Sleep(16); - auto carSaveBase = (uintptr_t*)(*(uintptr_t*)(imageBasedxplus + 0x01F7D578) + 0x268); - auto powerAddress = (uintptr_t*)(*(uintptr_t*)(carSaveBase)+0xAC); - auto handleAddress = (uintptr_t*)(*(uintptr_t*)(carSaveBase)+0xB8); + // Dereference the power value from the memory address + auto powerValue = injector::ReadMemory(powerAddress, true); + auto handleValue = injector::ReadMemory(handleAddress, true); + + // If the power and handling values do not add up to fully tuned + if (powerValue + handleValue < 0x20) + { + // Car is not fully tuned, force it to the default full tune injector::WriteMemory(powerAddress, 0x10, true); injector::WriteMemory(handleAddress, 0x10, true); + + // Updated + return 1; } - //debug - /* - std::ofstream myfile("debug.txt"); - myfile << "Base: "; - myfile << carSaveBase; - myfile << " Power: "; - myfile << powerAddress; - myfile << " Handling: "; - myfile << handleAddress; - myfile.close(); - */ + + // Not updated + return 0; } +// forceFullTune(pArguments: void*): DWORD WINAPI +// Function which runs in a secondary thread if the forceFullTune +// option is selected in the menu. If the player's car is not fully +// tuned, it is forcibly set to max tune. If the player's car is already +// fully tuned, it is left alone. +static DWORD WINAPI forceFullTune(void* pArguments) +{ + // Loops while the program is running + while (true) { + + // Only runs every 16th frame + Sleep(16); + + // Run the set full tune process + setFullTune(); + } +} + +// ******************************************** // +// ************ Debug Data Logging ************ // +// ******************************************** // + +// ************* Global Variables ************* // + +// **** String Variables + +// Debugging event log file +std::string logfileDxp = "wmmt5dxp_errors.txt"; + +// writeLog(filename: String, message: String): Int +// Given a filename string and a message string, appends +// the message to the given file. +static int writeLog(std::string filename, std::string message) +{ + // Log file to write to + std::ofstream eventLog; + + // Open the filename provided (append mode) + eventLog.open(filename, std::ios_base::app); + + // File open success + if (eventLog.is_open()) + { + // Write the message to the file + eventLog << message; + + // Close the log file handle + eventLog.close(); + + // Success + return 0; + } + else // File open failed + { + // Failure + return 1; + } +} + +// writeDump(filename: Char*, data: unsigned char *, size: size_t): Int +static int writeDump(char * filename, unsigned char * data, size_t size) +{ + // Open the file with the provided filename + FILE* file = fopen(filename, "wb"); + + // File opened successfully + if (file) + { + // Write the data to the file + fwrite((void*)data, 1, size, file); + + // Close the file + fclose(file); + + // Return success status + return 0; + } + else // Failed to open + { + // Return failure status + return 1; + } +} + +// Sets if saving is allowed or not static bool saveOk = false; -unsigned char carDatadxp[0xFF]; + +// If custom car is used +bool customCarDxp = false; + +// Sets if loading is allowed +bool loadOkDxp = false; + +// Car save data reserved memory +unsigned char carDataDxp[0xFF]; + +// Car filename string +char carFileNameDxp[0xFF]; + +// SaveOk(void): Void +// Enables saving static int SaveOk() { saveOk = true; return 1; } -char carFileNamedxp[0xFF]; -bool loadOkdxp = false; -bool customCardxp = false; - -static void saveMileagedxp() +// loadCarFile(filename: char*): Int +// Given a filename, loads the data from +// the car file into memory. +static int loadCarFile(char* filename) { - - //Mileage Write to "GAME/mileage.dat" - auto mileageLocation = (uintptr_t*)(*(uintptr_t*)(imageBasedxplus + 0x1F7D578) + 0x280); - //try this maybe, casting to int probably not right/not gonna work - FILE* tempFile = fopen("mileage.dat", "wb"); - fwrite(mileageLocation, 1, sizeof(mileageLocation), tempFile); - fclose(tempFile); -} + // Open the file with the filename + FILE* file = fopen(filename, "rb"); -static void LoadMileagedxp() -{ - - memset(mileDatadxp, 0, 0x08); - FILE* miles = fopen("mileage.dat", "rb"); - if (miles) + // File open OK + if (file) { - fseek(miles, 0, SEEK_END); - int mileSize = ftell(miles); - if (mileSize == 0x08) + // Get the length of the file + fseek(file, 0, SEEK_END); + int fsize = ftell(file); + + // If the file has the right size + if (fsize == 0xFF) { - fseek(miles, 0, SEEK_SET); - fread(mileDatadxp, mileSize, 1, miles); - uintptr_t mileMemory = *(uintptr_t*)(imageBasedxplus + 0x1F7D578); - memcpy((void*)(mileMemory + 0x280), mileDatadxp + 0x00, 0x04); - fclose(miles); + // Reset to start of the file and read it into the car data variable + fseek(file, 0, SEEK_SET); + fread(carDataDxp, fsize, 1, file); + + // Dereference the memory location for the car save data + uintptr_t carSaveLocation = *(uintptr_t*)((*(uintptr_t*)(imageBasedxplus + 0x1F7D578)) + 0x268); + + // memcpy((void*)(carSaveLocation + 0x00), carDataDxp + 0x00, 8); // ?? + // memcpy((void*)(carSaveLocation + 0x08), carDataDxp + 0x08, 8); // ?? + // memcpy((void*)(carSaveLocation + 0x10), carDataDxp + 0x10, 8); // ?? + // memcpy((void*)(carSaveLocation + 0x18), carDataDxp + 0x18, 8); // ?? + // memcpy((void*)(carSaveLocation + 0x20), carDataDxp + 0x20, 8); // Crash + memcpy((void*)(carSaveLocation + 0x28), carDataDxp + 0x28, 8); // Region (0x28) + memcpy((void*)(carSaveLocation + 0x30), carDataDxp + 0x30, 8); // CarID (0x34) + // memcpy((void*)(carSaveLocation + 0x38), carDataDxp + 0x38, 4); // defaultColor + memcpy((void*)(carSaveLocation + 0x3C), carDataDxp + 0x3C, 4); // CustomColor (0x3C) + memcpy((void*)(carSaveLocation + 0x40), carDataDxp + 0x40, 8); // Rims (0x40), Rims Colour (0x44) + memcpy((void*)(carSaveLocation + 0x48), carDataDxp + 0x48, 8); // Aero (0x48), Hood (0x4C) + // memcpy((void*)(carSaveLocation + 0x50), carDataDxp + 0x50, 8); // Crash + memcpy((void*)(carSaveLocation + 0x58), carDataDxp + 0x58, 8); // Wing (0x58), Mirror (0x5C) + memcpy((void*)(carSaveLocation + 0x60), carDataDxp + 0x60, 8); // Sticker (0x60), Sticker Type (0x64) + // memcpy((void*)(carSaveLocation + 0x68), carDataDxp + 0x60, 8); // Crash + memcpy((void*)(carSaveLocation + 0x88), carDataDxp + 0x88, 8); // Roof Sticker (0x88), Roof Sticker Type (0x8C) + memcpy((void*)(carSaveLocation + 0x90), carDataDxp + 0x90, 8); // Neon (0x90), Trunk (0x94) + memcpy((void*)(carSaveLocation + 0x98), carDataDxp + 0x98, 8); // Plate Frame (0x98) + memcpy((void*)(carSaveLocation + 0xA0), carDataDxp + 0xA0, 8); // Plate Number (0xA0), vinyl_body_challenge_prefecture_1~15 (0xA4) + memcpy((void*)(carSaveLocation + 0xA8), carDataDxp + 0xA8, 8); // vinyl_body_challenge_prefecture (0xA8), Power (0xAC) + memcpy((void*)(carSaveLocation + 0xB8), carDataDxp + 0xB8, 8); // Handling (0xB8), Rank (0xBC) + // memcpy((void*)(carSaveLocation + 0xC0), carDataDxp + 0xC0, 8); // ?? + // memcpy((void*)(carSaveLocation + 0xC8), carDataDxp + 0xC8, 8); // ?? + // memcpy((void*)(carSaveLocation + 0xD0), carDataDxp + 0xD0, 8); // Crash + // memcpy((void*)(carSaveLocation + 0xD8), carDataDxp + 0xD8, 8); // ?? + // memcpy((void*)(carSaveLocation + 0xE0), carDataDxp + 0xE0, 8); // ?? + // memcpy((void*)(carSaveLocation + 0xE8), carDataDxp + 0xE8, 8); // ?? + // memcpy((void*)(carSaveLocation + 0xF0), carDataDxp + 0xF0, 8); // ?? + // memcpy((void*)(carSaveLocation + 0xF8), carDataDxp + 0xF8, 8); // ?? } + + // Disable loading + loadOkDxp = false; + + // Close the file + fclose(file); + + // Success + return 1; } + + // Failed + return 0; +} + +// loadCarData(filepath: char*): Void +// Given a filepath, attempts to load a +// car file (either custom.car or specific +// car file) from that folder. +static int loadCarData(char * filepath) +{ + // Custom car disabled by default + customCarDxp = false; + + // Miles path string + char carpath[0xFF]; + + // Set the milepath memory to zero + memset(carpath, 0, 0xFF); + + // Copy the file path to the miles path + strcpy(carpath, filepath); + + // Append the mileage filename to the string + strcat(carpath, "\\OpenParrot_Cars"); + + // Create the OpenParrot_cars directory at the given filepath + std::filesystem::create_directories(carpath); + + // Get the path to the custom car file + sprintf(carFileNameDxp, "%s\\custom.car", carpath); + + // If the custom car file exists + if (FileExists(carFileNameDxp)) + { + // Load the custom car file + loadCarFile(carFileNameDxp); + + // Enable custom car switch + customCarDxp = true; + } + + // Empty the car filename string + memset(carFileNameDxp, 0, 0xFF); + + // Get the path to the specific car file + sprintf(carFileNameDxp, "%s\\%08X.car", carpath, *(DWORD*)(*(uintptr_t*)(*(uintptr_t*)(imageBasedxplus + 0x1F7D578) + 0x268) + 0x34)); + + // If the specific car file exists + if (FileExists(carFileNameDxp)) + { + // Load the car file + loadCarFile(carFileNameDxp); + } + + // If the force full tune switch is set + if (ToBool(config["Tune"]["Force Full Tune"])) + { + // Create the force full tune thread + // CreateThread(0, 0, forceFullTune, 0, 0, 0); + + // Set the car to be fully tuned + setFullTune(); + } + + // Success + return 1; } - -static int SaveGameData() +static int saveCarData(char* filepath) { - if (!saveOk) - return 1; - // Car Profile saving - memset(carDatadxp, 0, 0xFF); - memset(carFileNamedxp, 0, 0xFF); + memset(carDataDxp, 0, 0xFF); + memset(carFileNameDxp, 0, 0xFF); - //new multilevel - uintptr_t carSaveBase = *(uintptr_t*)((*(uintptr_t*)(imageBasedxplus + 0x1F7D578)) + 0x268); + // Address where player save data starts + uintptr_t saveDataBase = *(uintptr_t*)(imageBasedxplus + 0x1F7D578); - //memcpy(carData + 0x00, (void*)(carSaveBase + 0xAC), 0x1); - //memcpy(carData + 0x01, (void*)(carSaveBase + 0xB8), 0x1); //successfully dumped power and handling! - memcpy(carDatadxp + 0x00, (void*)(carSaveBase + 0x0), 0xFF); //dumps whole region + // Address where car save data starts + uintptr_t carSaveBase = *(uintptr_t*)(saveDataBase + 0x268); + // Miles path string + char carpath[0xFF]; - CreateDirectoryA("OpenParrot_Cars", nullptr); + // Set the milepath memory to zero + memset(carpath, 0, 0xFF); - if (customCardxp) + // Copy the file path to the miles path + strcpy(carpath, filepath); + + // Append the mileage filename to the string + strcat(carpath, "\\OpenParrot_Cars"); + + // CreateDirectoryA(carpath, nullptr); + + // Create the cars path folder + std::filesystem::create_directories(carpath); + + // Copy the 0xFF bytes from memory to the car data array + memcpy(carDataDxp + 0x00, (void*)(carSaveBase + 0x0), 0xFF); + + // If custom car is set + if (customCarDxp) { - sprintf(carFileNamedxp, ".\\OpenParrot_Cars\\custom.car"); + // Save the file to custom.car + sprintf(carpath, "%s\\custom.car", carpath); } - else + else // Custom car is not set { - sprintf(carFileNamedxp, ".\\OpenParrot_Cars\\%08X.car", *(DWORD*)(*(uintptr_t*)(*(uintptr_t*)(imageBasedxplus + 0x1F7D578) + 0x268) + 0x34)); + // Save the file to the specific car filename + sprintf(carpath, "%s\\%08X.car", carpath, *(DWORD*)(*(uintptr_t*)(*(uintptr_t*)(imageBasedxplus + 0x1F7D578) + 0x268) + 0x34)); } - FILE* file = fopen(carFileNamedxp, "wb"); - fwrite(carDatadxp, 1, 0xFF, file); - fclose(file); + // Open the file at the given car path + FILE* carFile = fopen(carpath, "wb"); - saveMileagedxp(); + // Write the data from the array to the file + fwrite(carDataDxp, 1, 0xFF, carFile); + fclose(carFile); - saveOk = false; + // Success return 1; /* + + // Legacy MT5 car saving code reference + memset(saveData, 0, 0x2000); uintptr_t value = *(uintptr_t*)(imageBase + 0x1948F10); value = *(uintptr_t*)(value + 0x108); @@ -606,12 +799,13 @@ static int SaveGameData() FILE* file = fopen("openprogress.sav", "wb"); fwrite(saveData, 1, 0x2000, file); fclose(file); - + // Car Profile saving memset(carData, 0, 0xFF); memset(carFileNamedxp, 0, 0xFF); memcpy(carData, (void *)*(uintptr_t*)(*(uintptr_t*)(imageBase + 0x1948F10) + 0x180 + 0xa8 + 0x18), 0xE0); CreateDirectoryA("OpenParrot_Cars", nullptr); + if(customCardxp) { sprintf(carFileNamedxp, ".\\OpenParrot_Cars\\custom.car"); @@ -620,20 +814,192 @@ static int SaveGameData() { sprintf(carFileNamedxp, ".\\OpenParrot_Cars\\%08X.car", *(DWORD*)(*(uintptr_t*)(*(uintptr_t*)(imageBase + 0x1948F10) + 0x180 + 0xa8 + 0x18) + 0x2C)); } + FILE *carSave = fopen(carFileNamedxp, "wb"); fwrite(carData, 1, 0xE0, file); fclose(carSave); + //SaveStoryData(); //SaveCampaingHonorData(); //SaveStoryModeNoLoseHonorData(); //SaveOtherHonorData(); //SaveCampaingHonorData2(); + saveOk = false; return 1; */ } -uintptr_t saveGameOffsetdxp; +// loadStoryData(filepath: char *): Void +// Given a filepath, loads the story data +// from the file into memory. +static int loadStoryData(char* filepath) +{ + // Zero out the save data array + memset(saveDatadxp, 0x0, 0x2000); + + // Miles path string + char storyPath[0xFF]; + + // Set the milepath memory to zero + memset(storyPath, 0, 0xFF); + + // Copy the file path to the miles path + strcpy(storyPath, filepath); + + // Append the mileage filename to the string + strcat(storyPath, "\\openprogress.sav"); + + // Address where player save data starts + uintptr_t saveDataBase = *(uintptr_t*)(imageBasedxplus + 0x1F7D578); + + // Open the openprogress file with read privileges + FILE* file = fopen(storyPath, "rb"); + + // If the file exists + if (file) + { + // Get all of the contents from the file + fseek(file, 0, SEEK_END); + + // Get the size of the file + int fsize = ftell(file); + + // Check file is correct size + if (fsize == 0x2000) + { + // Reset seek index to start + fseek(file, 0, SEEK_SET); + + // Read all of the contents of the file into saveDatadxp + fread(saveDatadxp, fsize, 1, file); + + // Story save data offset + uintptr_t saveStoryBase = *(uintptr_t*)(saveDataBase + 0x108); + + // 0x00 - 08 4C - Should be able to use this to figure out what game a save is from + + // (Mostly) discovered story data + + memcpy((void*)(saveStoryBase + 0x48), saveDatadxp + 0x48, 0x8); // Story Bit + memcpy((void*)(saveStoryBase + 0xE0), saveDatadxp + 0xE0, 0x8); // ?? + memcpy((void*)(saveStoryBase + 0xE8), saveDatadxp + 0xE8, 0x8); // Chapter Progress (0xE8) (Bitmask) + memcpy((void*)(saveStoryBase + 0xF0), saveDatadxp + 0xF0, 0x8); // Current Chapter (0xF0), Total Wins (0xF4) + memcpy((void*)(saveStoryBase + 0xF8), saveDatadxp + 0xF8, 0x8); // ?? + memcpy((void*)(saveStoryBase + 0x100), saveDatadxp + 0x100, 0x8); // Win Streak (0x104) + memcpy((void*)(saveStoryBase + 0x108), saveDatadxp + 0x108, 0x8); // ?? + memcpy((void*)(saveStoryBase + 0x110), saveDatadxp + 0x110, 0x8); // Locked Chapters (0x110) (Bitmask) + + // Can't tell if the data past this point does anything + + // memcpy((void*)(saveStoryBase + 0x118), saveDatadxp + 0x118, 0x8); // ?? + // memcpy((void*)(saveStoryBase + 0x120), saveDatadxp + 0x120, 0x8); // ?? + // memcpy((void*)(saveStoryBase + 0x128), saveDatadxp + 0x128, 0x8); // ?? + // memcpy((void*)(saveStoryBase + 0x130), saveDatadxp + 0x130, 0x8); // ?? + // memcpy((void*)(saveStoryBase + 0x138), saveDatadxp + 0x138, 0x8); // ?? + // memcpy((void*)(saveStoryBase + 0x140), saveDatadxp + 0x140, 0x8); // ?? + // memcpy((void*)(saveStoryBase + 0x148), saveDatadxp + 0x148, 0x8); // ?? + // memcpy((void*)(saveStoryBase + 0x150), saveDatadxp + 0x150, 0x8); // ?? + // memcpy((void*)(saveStoryBase + 0x158), saveDatadxp + 0x158, 0x8); // ?? + + // Save data loaded successfully + loadOkDxp = true; + + //+ 0x80 + + //+ [0x340] + + // [[[[0000000005CE5850] + 108] + 340] + 50] + 50 + // [[[[0000000005CE5850] + 108] + 340] + 50] + 54 + // wmn5r.exe + 1948BF8 + //TA stuff + + //[[[[magic_rva]+108]+340]+50] + + // memcpy((void*)(saveStoryBase + 0x24E0 + 0x16), saveDatadxp + 0x16, 0x1000); + + //value += 0x24E0; + // First chunk + //memcpy((void *)(value + 0x16), saveData + 0x16, 0x28); + //// + //memcpy((void *)(value + 0x40), saveData + 0x40, 0x18); + //// + //memcpy((void *)(value + 0x60), saveData + 0x60, 0x20); + //// + //memcpy((void *)(value + 0x90), saveData + 0x90, 0x28); + //// + //memcpy((void *)(value + 0xC0), saveData + 0xC0, 0x10); + //// + //memcpy((void *)(value + 0xD8), saveData + 0xD8, 0x28); // OK + //// + //memcpy((void *)(value + 0x110), saveData + 0x110, 0x98); + //// + //memcpy((void *)(value + 0x1B8), saveData + 0x1B8, 0x48); + //// + //memcpy((void *)(value + 0x208), saveData + 0x208, 0x28); + //// + //memcpy((void *)(value + 0x240), saveData + 0x240, 0x68); + //// + //memcpy((void *)(value + 0x2B8), saveData + 0x2B8, 0x88); + // + //memcpy((void *)(value + 0x370), saveData + 0x370, 0x10); + //// + //memcpy((void *)(value + 0x388), saveData + 0x388, 0x90); + //// + //memcpy((void *)(value + 0x420), saveData + 0x420, 0x18); + //// + //memcpy((void *)(value + 0x440), saveData + 0x440, 0x18); + //// + //memcpy((void *)(value + 0x460), saveData + 0x460, 0x48); + //// + //memcpy((void *)(value + 0x4B8), saveData + 0x4B8, 0xB8); + //// + //memcpy((void *)(value + 0x578), saveData + 0x578, 0x08); + //// + //memcpy((void *)(value + 0x5A8), saveData + 0x5A8, 0x68); + //// + //memcpy((void *)(value + 0x628), saveData + 0x628, 0x48); + //// + //memcpy((void *)(value + 0x688), saveData + 0x688, 0x48); + //// + //memcpy((void *)(value + 0x6E8), saveData + 0x6E8, 0xA8); + //// + //memcpy((void *)(value + 0x7A0), saveData + 0x7A0, 0x10); + //// + //memcpy((void *)(value + 0x7B8), saveData + 0x7B8, 0x28); + //// + //memcpy((void *)(value + 0x7E8), saveData + 0x7E8, 0x10); + //// + ////memcpy((void *)(value + 0x800), saveData + 0x800, 0x48); // Problem + ////// + //memcpy((void *)(value + 0x850), saveData + 0x850, 0x08); + // + //memcpy((void *)(value + 0x860), saveData + 0x860, 0x08); + ////// + //memcpy((void *)(value + 0x870), saveData + 0x870, 0x18); + //// + //memcpy((void *)(value + 0x890), saveData + 0x890, 0x40); + //// + //memcpy((void *)(value + 0x8E0), saveData + 0x8E0, 0x10); + //// + //memcpy((void *)(value + 0x8F8), saveData + 0x8F8, 0x28); + //// + //memcpy((void *)(value + 0x928), saveData + 0x928, 0x10); + //// + //memcpy((void *)(value + 0x940), saveData + 0x940, 0x48); // Problem + } + fclose(file); + } + + //LoadStoryData(); + //LoadCampaingHonorData(); + //LoadStoryModeNoLoseHonorData(); + //LoadOtherHonorData(); + //LoadCampaingHonorData2(); + + // Success status + return 1; +} //static int LoadCampaingHonorData2() //{ @@ -747,260 +1113,376 @@ uintptr_t saveGameOffsetdxp; // return 1; //} -static int LoadGameData() +static int saveStoryData(char* filepath) { - saveOk = false; - memset(saveDatadxp, 0x0, 0x2000); - FILE* file = fopen("openprogress.sav", "rb"); - if (file) + // Miles path string + char storyPath[0xFF]; + + // Set the milepath memory to zero + memset(storyPath, 0, 0xFF); + + // Copy the file path to the miles path + strcpy(storyPath, filepath); + + // Append the mileage filename to the string + strcat(storyPath, "\\openprogress.sav"); + + // Save story data + + // Address where player save data starts + uintptr_t saveDataBase = *(uintptr_t*)(imageBasedxplus + 0x1F7D578); + + // Zero out save data binary + memset(saveDatadxp, 0, 0x2000); + + // Address where the player story data starts + uintptr_t storySaveBase = *(uintptr_t*)(saveDataBase + 0x108); + + // Copy to saveDatadxp from the story save data index + memcpy(saveDatadxp, (void*)storySaveBase, 0x340); + + // Dump the save data to openprogress.sav + writeDump(storyPath, saveDatadxp, 0x2000); + + // Success + return 1; +} + +static int loadMileData(char* filepath) +{ + // Zero out the mile data memory + memset(mileDatadxp, 0, 0x08); + + // Miles path string + char milepath[0xFF]; + + // Set the milepath memory to zero + memset(milepath, 0, 0xFF); + + // Copy the file path to the miles path + strcpy(milepath, filepath); + + // Append the mileage filename to the string + strcat(milepath, "\\mileage.dat"); + + // Path to the miles file + FILE* miles = fopen(milepath, "rb"); + + // File loaded OK + if (miles) { - fseek(file, 0, SEEK_END); - int fsize = ftell(file); - if (fsize == 0x2000) + // Get the size of the file + fseek(miles, 0, SEEK_END); + int mileSize = ftell(miles); + + // If the file size is correct + if (mileSize == 0x08) { - fseek(file, 0, SEEK_SET); - fread(saveDatadxp, fsize, 1, file); - uintptr_t value = *(uintptr_t*)(imageBasedxplus + 0x1948F10); - value = *(uintptr_t*)(value + 0x108); + // Load the content from the file into mileDatadxp + fseek(miles, 0, SEEK_SET); + fread(mileDatadxp, mileSize, 1, miles); - // First page - //memcpy((void *)(value), saveData, 0x48); - memcpy((void *)(value + 0x10), saveDatadxp + 0x10, 0x20); - memcpy((void *)(value + 0x40), saveDatadxp + 0x40, 0x08); - //memcpy((void *)(value + 0x48 + 8), saveData + 0x48 + 8, 0x20); - memcpy((void *)(value + 0x48 + 8), saveDatadxp + 0x48 + 8, 0x08); - memcpy((void *)(value + 0x48 + 24), saveDatadxp + 0x48 + 24, 0x08); - memcpy((void *)(value + 0x48 + 32), saveDatadxp + 0x48 + 32, 0x08); + // Get the pointer to the memory location storing the miles + uintptr_t mileMemory = *(uintptr_t*)(imageBasedxplus + 0x1F7D578); - // Second page - value += 0x110; - memcpy((void *)(value), saveDatadxp + 0x110, 0x90); - value -= 0x110; + // Copy the mile data from the file into the memory location + memcpy((void*)(mileMemory + 0x280), mileDatadxp + 0x00, 0x04); - // Third Page - value += 0x1B8; - memcpy((void *)(value), saveDatadxp + 0x1B8, 0x48); - memcpy((void *)(value + 0x48 + 8), saveDatadxp + 0x1B8 + 0x48 + 8, 0x28); - value -= 0x1B8; - - // Fourth page - value += 0x240; - memcpy((void *)(value), saveDatadxp + 0x240, 0x68); - value -= 0x240; - - // Fifth page - value += 0x2B8; - memcpy((void *)(value), saveDatadxp + 0x2B8, 0x88); - value -= 0x2B8; - - loadOkdxp = true; - - //+ 0x80 - - //+ [0x340] - - // [[[[0000000005CE5850] + 108] + 340] + 50] + 50 - // [[[[0000000005CE5850] + 108] + 340] + 50] + 54 - // wmn5r.exe + 1948BF8 - //TA stuff - - //[[[[magic_rva]+108]+340]+50] - - //value += 0x24E0; - // First chunk - //memcpy((void *)(value + 0x16), saveData + 0x16, 0x28); - //// - //memcpy((void *)(value + 0x40), saveData + 0x40, 0x18); - //// - //memcpy((void *)(value + 0x60), saveData + 0x60, 0x20); - //// - //memcpy((void *)(value + 0x90), saveData + 0x90, 0x28); - //// - //memcpy((void *)(value + 0xC0), saveData + 0xC0, 0x10); - //// - //memcpy((void *)(value + 0xD8), saveData + 0xD8, 0x28); // OK - //// - //memcpy((void *)(value + 0x110), saveData + 0x110, 0x98); - //// - //memcpy((void *)(value + 0x1B8), saveData + 0x1B8, 0x48); - //// - //memcpy((void *)(value + 0x208), saveData + 0x208, 0x28); - //// - //memcpy((void *)(value + 0x240), saveData + 0x240, 0x68); - //// - //memcpy((void *)(value + 0x2B8), saveData + 0x2B8, 0x88); - // - //memcpy((void *)(value + 0x370), saveData + 0x370, 0x10); - //// - //memcpy((void *)(value + 0x388), saveData + 0x388, 0x90); - //// - //memcpy((void *)(value + 0x420), saveData + 0x420, 0x18); - //// - //memcpy((void *)(value + 0x440), saveData + 0x440, 0x18); - //// - //memcpy((void *)(value + 0x460), saveData + 0x460, 0x48); - //// - //memcpy((void *)(value + 0x4B8), saveData + 0x4B8, 0xB8); - //// - //memcpy((void *)(value + 0x578), saveData + 0x578, 0x08); - //// - //memcpy((void *)(value + 0x5A8), saveData + 0x5A8, 0x68); - //// - //memcpy((void *)(value + 0x628), saveData + 0x628, 0x48); - //// - //memcpy((void *)(value + 0x688), saveData + 0x688, 0x48); - //// - //memcpy((void *)(value + 0x6E8), saveData + 0x6E8, 0xA8); - //// - //memcpy((void *)(value + 0x7A0), saveData + 0x7A0, 0x10); - //// - //memcpy((void *)(value + 0x7B8), saveData + 0x7B8, 0x28); - //// - //memcpy((void *)(value + 0x7E8), saveData + 0x7E8, 0x10); - //// - ////memcpy((void *)(value + 0x800), saveData + 0x800, 0x48); // Problem - ////// - //memcpy((void *)(value + 0x850), saveData + 0x850, 0x08); - // - //memcpy((void *)(value + 0x860), saveData + 0x860, 0x08); - ////// - //memcpy((void *)(value + 0x870), saveData + 0x870, 0x18); - //// - //memcpy((void *)(value + 0x890), saveData + 0x890, 0x40); - //// - //memcpy((void *)(value + 0x8E0), saveData + 0x8E0, 0x10); - //// - //memcpy((void *)(value + 0x8F8), saveData + 0x8F8, 0x28); - //// - //memcpy((void *)(value + 0x928), saveData + 0x928, 0x10); - //// - //memcpy((void *)(value + 0x940), saveData + 0x940, 0x48); // Problem + fclose(miles); } - fclose(file); } - //LoadStoryData(); - //LoadCampaingHonorData(); - //LoadStoryModeNoLoseHonorData(); - //LoadOtherHonorData(); - //LoadCampaingHonorData2(); + + // Success + return 1; +} + +static int saveMileData(char* filepath) +{ + // Get the pointer to the memory location storing the miles + auto mileageLocation = (uintptr_t*)(*(uintptr_t*)(imageBasedxplus + 0x1F7D578) + 0x280); + + // Miles path string + char milepath[0xFF]; + + // Set the milepath memory to zero + memset(milepath, 0, 0xFF); + + // Copy the file path to the miles path + strcpy(milepath, filepath); + + // Append the mileage filename to the string + strcat(milepath, "\\mileage.dat"); + + // Load the miles file + FILE* tempFile = fopen(milepath, "wb"); + + // Write the miles data from memory to the miles file + fwrite(mileageLocation, 1, sizeof(mileageLocation), tempFile); + + fclose(tempFile); + + // Success + return 1; +} + +// Credits to chery vtec tuning club for figuring out star loading / saving +static int saveStarData(char* filepath) +{ + // Star path saving + char starPath[0xFF]; + + // Set the storyPath memory to zero + memset(starPath, 0, 0xFF); + + // Copy the file path to the stars path + strcpy(starPath, filepath); + + // Append the mileage filename to the string + strcat(starPath, "\\stars.bin"); + + // Clear star data memory + memset(starDataDxp, 0, 0x40); + + // Save Star Data + + // Dereference the star pointer + uintptr_t starBase = *(uintptr_t*)((*(uintptr_t*)(imageBasedxplus + 0x1F7D578)) + 0x110); + + // Dumps first 2 bytes from star pointer + memcpy(starDataDxp + 0x00, (void*)(starBase + 0x248), 0x2); + + // Dumps medal offsets from star pointer, 16 bytes + memcpy(starDataDxp + 0x04, (void*)(starBase + 0x254), 0x10); + + // Dump the contents of the star data array to the file + writeDump(starPath, starDataDxp, sizeof(starDataDxp)); + + // Success + return 1; +} + +static int loadStarData(char* filepath) +{ + // Star path loading + char starPath[0xFF]; + + // Set the storyPath memory to zero + memset(starPath, 0, 0xFF); + + // Copy the file path to the stars path + strcpy(starPath, filepath); + + // Append the mileage filename to the string + strcat(starPath, "\\stars.bin"); + + // Clear star data memory + memset(starDataDxp, 0, 0x40); + + // Open the star binary file + FILE* starFile = fopen(starPath, "rb"); + + // saveStarData(".\\preloadstars"); + writeLog(logfileDxp, "Loading stars ...\n"); + + // If the file opened successfully + if (starFile) + { + // saveStarData(".\\preloadstars"); + writeLog(logfileDxp, "success.\n"); + + // If the file size is correct + fseek(starFile, 0, SEEK_END); + int starSize = ftell(starFile); + if (starSize == 0x40) + { + // Reset the file pointer to the start + fseek(starFile, 0, SEEK_SET); + + // Read all of the contents into the array + fread(starDataDxp, starSize, 1, starFile); + + // Dereference the star pointer in the game memory + uintptr_t starBase = *(uintptr_t*)((*(uintptr_t*)(imageBasedxplus + 0x1F7D578)) + 0x110); + + // Dumps first 2 bytes from star pointer + memcpy((void*)(starBase + 0x248), starDataDxp + 0x00, 0x2); + + // Dumps medal offsets from star pointer, 16 bytes + memcpy((void*)(starBase + 0x254), starDataDxp + 0x04, 0x10); + + // Close the stars file + fclose(starFile); + } + } + + // saveStarData(".\\postloadstars"); + + // Delay another ten seconds + // std::this_thread::sleep_for(std::chrono::seconds(10)); + + // saveStarData(".\\delayloadstars"); + + // Success + return 1; +} + +static int loadGameData() +{ + // Disable saving + saveOk = false; + + // Miles path string + char loadPath[0xFF]; + + // Set the milepath memory to zero + memset(loadPath, 0, 0xFF); + + // Wirte the '.' into the load path + // sprintf(loadPath, ".\\SaveData"); + sprintf(loadPath, "."); + + // Seperate save file / cars per user profile + if (ToBool(config["Save"]["Save Per Custom Name"])) + { + // Get the profile name from the + std::string name = config["General"]["CustomName"]; + + // Add the c string version of the profile name to the path + sprintf(loadPath, "%s\\%s", loadPath, name.c_str()); + } + + // Seperate miles / story per car + if (ToBool(config["Save"]["Save Per Car"])) + { + // Need to get the hex code for the selected car + + // Address where player save data starts + uintptr_t saveDataBase = *(uintptr_t*)(imageBasedxplus + 0x1F7D578); + + // Address where the car save data starts + uintptr_t carSaveBase = *(uintptr_t*)(saveDataBase + 0x268); + + // If custom car is set + if (customCarDxp) + { + // Add the car id to the save path + sprintf(loadPath, "%s\\custom", loadPath); + } + else // Custom car is not set + { + // Add the custom folder to the save path + sprintf(loadPath, "%s\\%08X", loadPath, *(DWORD*)(*(uintptr_t*)(*(uintptr_t*)(imageBasedxplus + 0x1F7D578) + 0x268) + 0x34)); + } + } + + // Ensure the directory exists + std::filesystem::create_directories(loadPath); + + // Sleep for 1 second + std::this_thread::sleep_for(std::chrono::seconds(1)); + + // Load the car save file + loadCarData(loadPath); + + // Load the openprogress.sav file + loadStoryData(loadPath); + + // Load the miles save file + loadMileData(loadPath); + + // Sleep for 14 seconds + std::this_thread::sleep_for(std::chrono::seconds(14)); + + // Load the stars save file + loadStarData(loadPath); + + // Success return 1; } -static void LoadWmmt5CarData() +// SaveGameData(void): Int +// If saving is enabled, loads the +// player story data +static int SaveGameData() { - std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + // Saving is disabled + if (!saveOk) + return 1; -// if (!loadOkdxp) -// return; - customCardxp = false; - memset(carDatadxp, 0, 0xFF); - memset(carFileNamedxp, 0, 0xFF); - CreateDirectoryA("OpenParrot_Cars", nullptr); + // Miles path string + char savePath[0xFF]; - LoadMileagedxp(); + // Set the milepath memory to zero + memset(savePath, 0, 0xFF); - // check for custom car - sprintf(carFileNamedxp, ".\\OpenParrot_Cars\\custom.car"); - if (FileExists(carFileNamedxp)) + // Wirte the '.' into the load path + // sprintf(savePath, ".\\SaveData"); + sprintf(savePath, "."); + + // Seperate save file / cars per user profile + if (ToBool(config["Save"]["Save Per Custom Name"])) { - FILE* file = fopen(carFileNamedxp, "rb"); - if (file) - { - fseek(file, 0, SEEK_END); - int fsize = ftell(file); - if (fsize == 0xFF) - { - fseek(file, 0, SEEK_SET); - fread(carDatadxp, fsize, 1, file); - uintptr_t carSaveLocation = *(uintptr_t*)((*(uintptr_t*)(imageBasedxplus + 0x1F7D578)) + 0x268); - memcpy((void*)(carSaveLocation + 0xAC), carDatadxp + 0xAC, 0x1); //power - memcpy((void*)(carSaveLocation + 0xB8), carDatadxp + 0xB8, 0x1); //handling - memcpy((void*)(carSaveLocation + 0x28), carDatadxp + 0x28, 0x1); //region - memcpy((void*)(carSaveLocation + 0x34), carDatadxp + 0x34, 0x1); //carID - memcpy((void*)(carSaveLocation + 0x38), carDatadxp + 0x38, 0x1); //defaultColor - memcpy((void*)(carSaveLocation + 0x3C), carDatadxp + 0x3C, 0x1); //customColor - memcpy((void*)(carSaveLocation + 0x40), carDatadxp + 0x40, 0x1); //rims - memcpy((void*)(carSaveLocation + 0x44), carDatadxp + 0x44, 0x1); //rimColor - memcpy((void*)(carSaveLocation + 0x48), carDatadxp + 0x48, 0x1); //aero - memcpy((void*)(carSaveLocation + 0x4C), carDatadxp + 0x4C, 0x1); //hood - memcpy((void*)(carSaveLocation + 0x58), carDatadxp + 0x58, 0x1); //wang - memcpy((void*)(carSaveLocation + 0x5C), carDatadxp + 0x5C, 0x1); //mirror - memcpy((void*)(carSaveLocation + 0x60), carDatadxp + 0x60, 0x1); //sticker - memcpy((void*)(carSaveLocation + 0x64), carDatadxp + 0x64, 0x1); //stickerVariant - memcpy((void*)(carSaveLocation + 0x88), carDatadxp + 0x88, 0x1); //roofSticker - memcpy((void*)(carSaveLocation + 0x8C), carDatadxp + 0x8C, 0x1); //roofStickerVariant - memcpy((void*)(carSaveLocation + 0x90), carDatadxp + 0x90, 0x1); //neon - memcpy((void*)(carSaveLocation + 0x94), carDatadxp + 0x94, 0x1); //trunk - memcpy((void*)(carSaveLocation + 0x98), carDatadxp + 0x98, 0x1); //plateFrame - memcpy((void*)(carSaveLocation + 0xA0), carDatadxp + 0xA0, 0x4); //plateNumber - memcpy((void*)(carSaveLocation + 0xA4), carDatadxp + 0xA4, 0x1); //vinyl_body_challenge_prefecture_1~15 - memcpy((void*)(carSaveLocation + 0xA8), carDatadxp + 0xA8, 0x1); //vinyl_body_challenge_prefecture - memcpy((void*)(carSaveLocation + 0xBC), carDatadxp + 0xBC, 0x1); //rank - memcpy((void*)(carSaveLocation + 0xF0), carDatadxp + 0xF0, 0x1); //title?? + // Get the profile name from the + std::string name = config["General"]["CustomName"]; - customCardxp = true; - } - loadOkdxp = false; - fclose(file); - return; + // Add the c string version of the profile name to the path + sprintf(savePath, "%s\\%s", savePath, name.c_str()); + } + + // Seperate miles / story per car + if (ToBool(config["Save"]["Save Per Car"])) + { + // Need to get the hex code for the selected car + + // Address where player save data starts + uintptr_t saveDataBase = *(uintptr_t*)(imageBasedxplus + 0x1F7D578); + + // Address where the car save data starts + uintptr_t carSaveBase = *(uintptr_t*)(saveDataBase + 0x268); + + // If custom car is set + if (customCarDxp) + { + // Add the car id to the save path + sprintf(savePath, "%s\\custom", savePath); + } + else // Custom car is not set + { + // Add the custom folder to the save path + sprintf(savePath, "%s\\%08X", savePath, *(DWORD*)(*(uintptr_t*)(*(uintptr_t*)(imageBasedxplus + 0x1F7D578) + 0x268) + 0x34)); } } - if (ToBool(config["Tune"]["Force Full Tune"])) - { - CreateThread(0, 0, forceFT, 0, 0, 0); - } - memset(carFileNamedxp, 0, 0xFF); - // Load actual car if available - sprintf(carFileNamedxp, ".\\OpenParrot_Cars\\%08X.car", *(DWORD*)(*(uintptr_t*)(*(uintptr_t*)(imageBasedxplus + 0x1F7D578) + 0x268) + 0x34)); - if(FileExists(carFileNamedxp)) - { - FILE* file = fopen(carFileNamedxp, "rb"); - if (file) - { - fseek(file, 0, SEEK_END); - int fsize = ftell(file); - if (fsize == 0xFF) - { - fseek(file, 0, SEEK_SET); - fread(carDatadxp, fsize, 1, file); - uintptr_t carSaveLocation = *(uintptr_t*)((*(uintptr_t*)(imageBasedxplus + 0x1F7D578)) + 0x268); - memcpy((void*)(carSaveLocation + 0xAC), carDatadxp + 0xAC, 0x1); //power - memcpy((void*)(carSaveLocation + 0xB8), carDatadxp + 0xB8, 0x1); //handling - memcpy((void*)(carSaveLocation + 0x28), carDatadxp + 0x28, 0x1); //region - memcpy((void*)(carSaveLocation + 0x34), carDatadxp + 0x34, 0x1); //carID - memcpy((void*)(carSaveLocation + 0x38), carDatadxp + 0x38, 0x1); //defaultColor - memcpy((void*)(carSaveLocation + 0x3C), carDatadxp + 0x3C, 0x1); //customColor - memcpy((void*)(carSaveLocation + 0x40), carDatadxp + 0x40, 0x1); //rims - memcpy((void*)(carSaveLocation + 0x44), carDatadxp + 0x44, 0x1); //rimColor - memcpy((void*)(carSaveLocation + 0x48), carDatadxp + 0x48, 0x1); //aero - memcpy((void*)(carSaveLocation + 0x4C), carDatadxp + 0x4C, 0x1); //hood - memcpy((void*)(carSaveLocation + 0x58), carDatadxp + 0x58, 0x1); //wang - memcpy((void*)(carSaveLocation + 0x5C), carDatadxp + 0x5C, 0x1); //mirror - memcpy((void*)(carSaveLocation + 0x60), carDatadxp + 0x60, 0x1); //sticker - memcpy((void*)(carSaveLocation + 0x64), carDatadxp + 0x64, 0x1); //stickerVariant - memcpy((void*)(carSaveLocation + 0x88), carDatadxp + 0x88, 0x1); //roofSticker - memcpy((void*)(carSaveLocation + 0x8C), carDatadxp + 0x8C, 0x1); //roofStickerVariant - memcpy((void*)(carSaveLocation + 0x90), carDatadxp + 0x90, 0x1); //neon - memcpy((void*)(carSaveLocation + 0x94), carDatadxp + 0x94, 0x1); //trunk - memcpy((void*)(carSaveLocation + 0x98), carDatadxp + 0x98, 0x1); //plateFrame - memcpy((void*)(carSaveLocation + 0xA0), carDatadxp + 0xA0, 0x4); //plateNumber - memcpy((void*)(carSaveLocation + 0xA4), carDatadxp + 0xA4, 0x1); //vinyl_body_challenge_prefecture_1~15 - memcpy((void*)(carSaveLocation + 0xA8), carDatadxp + 0xA8, 0x1); //vinyl_body_challenge_prefecture - memcpy((void*)(carSaveLocation + 0xBC), carDatadxp + 0xBC, 0x1); //rank - memcpy((void*)(carSaveLocation + 0xF0), carDatadxp + 0xF0, 0x1); //title?? - } - fclose(file); - } - } - loadOkdxp = false; + // Ensure the directory exists + std::filesystem::create_directories(savePath); + + // Load the car save file + saveCarData(savePath); + + // Load the openprogress.sav file + saveStoryData(savePath); + + // Load the miles save file + saveMileData(savePath); + + // Load the miles save file + saveStarData(savePath); + + // Disable saving + saveOk = false; + + // Success + return 1; } -static void loadCar() +static void loadGame() { - std::thread t1(LoadWmmt5CarData); + // Runs after car data is loaded + + // Load story data thread + std::thread t1(loadGameData); t1.detach(); } @@ -1207,7 +1689,6 @@ extern int* ffbOffset; extern int* ffbOffset2; extern int* ffbOffset3; extern int* ffbOffset4; - DWORD WINAPI Wmmt5FfbCollector(void* ctx) { uintptr_t imageBase = (uintptr_t)GetModuleHandleA(0); @@ -1221,8 +1702,14 @@ DWORD WINAPI Wmmt5FfbCollector(void* ctx) } }*/ + +// Wmmt5Func([]()): InitFunction +// Performs the initial startup tasks for +// maximum tune 5, including the starting +// of required subprocesses. static InitFunction Wmmt5Func([]() -{/* +{ + /* FILE* fileF = _wfopen(L"Fsetting.lua.gz", L"r"); if (fileF == NULL) { @@ -1234,7 +1721,6 @@ static InitFunction Wmmt5Func([]() { fclose(fileF); } - FILE* fileG = _wfopen(L"Gsetting.lua.gz", L"r"); if (fileG == NULL) { @@ -1245,24 +1731,32 @@ static InitFunction Wmmt5Func([]() else { fclose(fileG); - }*/ - + } + */ + // Records if terminal mode is enabled bool isTerminal = false; + + // If terminal mode is set in the general settings if (ToBool(config["General"]["TerminalMode"])) { + // Terminal mode is set isTerminal = true; } + // Get the network adapter ip address from the general settings std::string networkip = config["General"]["NetworkAdapterIP"]; + + // If the ip address is not blank if (!networkip.empty()) { - //strcpy(ipaddr, networkip.c_str()); + // Overwrite the default ip address ipaddrdxplus = networkip.c_str(); } hookPort = "COM3"; imageBasedxplus = (uintptr_t)GetModuleHandleA(0); + MH_Initialize(); // Hook dongle funcs @@ -1274,12 +1768,9 @@ static InitFunction Wmmt5Func([]() MH_CreateHookApi(L"hasp_windows_x64_106482.dll", "hasp_logout", dxpHook_hasp_logout, NULL); MH_CreateHookApi(L"hasp_windows_x64_106482.dll", "hasp_login", dxpHook_hasp_login, NULL); - - GenerateDongleDataDxp(isTerminal); - - //prevents game from setting time, thanks pockywitch! + // Prevents game from setting time, thanks pockywitch! MH_CreateHookApi(L"KERNEL32", "SetSystemTime", Hook_SetSystemTime, reinterpret_cast(&pSetSystemTime)); // Patch some check TEMP DISABLE AS WELL OVER HERE @@ -1317,40 +1808,52 @@ static InitFunction Wmmt5Func([]() // Patch some call // 45 33 C0 BA 65 09 00 00 48 8D 4D B0 E8 ?? ?? ?? ?? 48 8B 08 // FOUND ON 21, 10, 1 - //injector::MakeNOP(imageBase + 0x7DADED, 5); - //THIS injector::MakeNOP(hook::get_pattern("45 33 C0 BA 65 09 00 00 48 8D 4D B0 E8 ? ? ? ? 48 8B 08", 12), 5); { // 199AE18 TIME OFFSET RVA temp disable ALL JNZ PATCH auto location = hook::get_pattern("41 3B C7 74 0E 48 8D 8F B8 00 00 00 BA F6 01 00 00 EB 6E 48 8D 8F A0 00 00 00"); + // Patch some jnz // 41 3B C7 74 0E 48 8D 8F B8 00 00 00 BA F6 01 00 00 EB 6E 48 8D 8F A0 00 00 00 // FOUND ON 21, 10, 1 - //injector::WriteMemory(imageBase + 0x943F52, 0xEB, true); injector::WriteMemory(location + 3, 0xEB, true); //patches content router (doomer) // Skip some jnz - //injector::MakeNOP(imageBase + 0x943F71, 2); injector::MakeNOP(location + 0x22, 2); //patches ip addr error again (doomer) // Skip some jnz - //injector::MakeNOP(imageBase + 0x943F82, 2); injector::MakeNOP(location + 0x33, 2); //patches ip aaddr error(doomer) } - // Skip DebugBreak on MFStartup fail - // 48 83 EC 28 33 D2 B9 70 00 02 00 E8 ?? ?? ?? ?? 85 C0 79 06 - // FOUND on 21, 1 + // Terminal mode is off + if (!isTerminal) { - /* - auto location = hook::get_pattern("48 83 EC 28 33 D2 B9 70 00 02 00 E8 ? ? ? ? 85 C0 79 06"); - injector::WriteMemory(location + 0x12, 0xEB, true); - */ - } - //safeJMP(hook::get_pattern(V("48 83 EC 28 33 D2 B9 70 00 02 00 E8 ? ? ? ? 85 C0 79 06")), ReturnTrue); + // Disregard terminal scanner stuff. + // 48 8B 18 48 3B D8 0F 84 88 00 00 00 39 7B 1C 74 60 80 7B 31 00 75 4F 48 8B 43 10 80 78 31 00 + // FOUND ON 21, 10, 1 + //injector::MakeNOP(imageBase + 0x91E1AE, 6); + //injector::MakeNOP(imageBase + 0x91E1B7, 2); + //injector::MakeNOP(imageBase + 0x91E1BD, 2); - if (isTerminal) + /* + auto location = hook::get_pattern("48 8B 18 48 3B D8 0F 84 8B 00 00 00 0F 1F 80 00 00 00 00 39 73 1C 74 5C 80 7B 31 00"); + // injector::MakeNOP(location + 6, 6); // 6 + injector::MakeNOP(location + 0xF, 2); // 0xF + // injector::MakeNOP(location + 0x15, 2); // 0x15 + */ + + injector::MakeNOP(imageBasedxplus + 0x9F2BB3, 2); + + // If terminal emulator is enabled + if (ToBool(config["General"]["TerminalEmulator"])) + { + // Start the multicast spam thread + CreateThread(0, 0, SpamMulticast, 0, 0, 0); + } + } + /* + else { // Patch some func to 1 // @@ -1367,33 +1870,7 @@ static InitFunction Wmmt5Func([]() //safeJMP(hook::get_pattern("40 53 48 83 EC 20 48 83 39 00 48 8B D9 75 11 48 8B 0D C2"), ReturnTrue); //safeJMP(imageBase + 0x8B5190, ReturnTrue); } - else - { - // Disregard terminal scanner stuff. - // 48 8B 18 48 3B D8 0F 84 88 00 00 00 39 7B 1C 74 60 80 7B 31 00 75 4F 48 8B 43 10 80 78 31 00 - // FOUND ON 21, 10, 1 - //injector::MakeNOP(imageBase + 0x91E1AE, 6); - //injector::MakeNOP(imageBase + 0x91E1B7, 2); - //injector::MakeNOP(imageBase + 0x91E1BD, 2); - - { - - /* - auto location = hook::get_pattern("48 8B 18 48 3B D8 0F 84 8B 00 00 00 0F 1F 80 00 00 00 00 39 73 1C 74 5C 80 7B 31 00"); - //injector::MakeNOP(location + 6, 6); // 6 - injector::MakeNOP(location + 0xF, 2); // 0xF - //injector::MakeNOP(location + 0x15, 2); // 0x15 - */ - injector::MakeNOP(imageBasedxplus + 0x9F2BB3, 2); - } - - - // spam thread - if (ToBool(config["General"]["TerminalEmulator"])) - { - CreateThread(0, 0, SpamMulticast, 0, 0, 0); - } - } + */ auto chars = { 'F', 'G' }; @@ -1418,38 +1895,37 @@ static InitFunction Wmmt5Func([]() } } - if (ToBool(config["General"]["SkipMovies"])) - { - // Skip movies fuck you wmmt5 - //safeJMP(imageBase + 0x806020, ReturnTrue); - } - + // Get the custom name specified in the config file std::string value = config["General"]["CustomName"]; + + // If a custom name is set if (!value.empty()) { - + // Zero out the custom name variable memset(customNamedxp, 0, 256); + + // Copy the custom name to the custom name block strcpy(customNamedxp, value.c_str()); + + // Create the spam custom name thread CreateThread(0, 0, SpamcustomNamedxp, 0, 0, 0); - } // Save story stuff (only 05) { - - // skip erasing of temp card data - //injector::WriteMemory(imageBase + 0xA35CA3, 0xEB, true); + // Skip erasing of temp card data + // injector::WriteMemory(imageBase + 0xA35CA3, 0xEB, true); + /* // Skip erasing of temp card safeJMP(imageBase + 0x54DCE1, LoadGameData); safeJMP(imageBase + 0x5612F0, ReturnTrue); safeJMP(imageBase + 0x5753C0, ReturnTrue); safeJMP(imageBase + 0x57DF10, ReturnTrue); - safeJMP(imageBase + 0x92DB20, ReturnTrue); safeJMP(imageBase + 0x5628C0, ReturnTrue); safeJMP(imageBase + 0x579090, ReturnTrue); - + // Skip more safeJMP(imageBase + 0x54B0F0, ReturnTrue); safeJMP(imageBase + 0x909DB0, ReturnTrue); @@ -1458,53 +1934,49 @@ static InitFunction Wmmt5Func([]() safeJMP(imageBase + 0x915370, ReturnTrue); safeJMP(imageBase + 0x5507A0, ReturnTrue); safeJMP(imageBase + 0x561290, ReturnTrue); - safeJMP(imageBase + 0x5A0AE8, LoadWmmt5CarData); - + // crash fix //safeJMP(imageBase + 0xAD6F28, WmmtOperatorDelete); //safeJMP(imageBase + 0xAD6F4C, WmmtMemset); - + // Save progress trigger injector::WriteMemory(imageBase + 0x556CE3, 0xB848, true); injector::WriteMemory(imageBase + 0x556CE3 + 2, (uintptr_t)SaveOk, true); injector::WriteMemory(imageBase + 0x556CED, 0x9090D0FF, true); - + // Try save later! injector::MakeNOP(imageBase + 0x308546, 0x12); injector::WriteMemory(imageBase + 0x308546, 0xB848, true); injector::WriteMemory(imageBase + 0x308546 + 2, (uintptr_t)SaveGameData, true); injector::WriteMemory(imageBase + 0x308550, 0x3348D0FF, true); injector::WriteMemory(imageBase + 0x308550 + 4, 0x90C0, true); - CreateThread(0, 0, Wmmt5FfbCollector, 0, 0, 0); */ // Enable all print injector::MakeNOP(imageBasedxplus + 0x898BD3, 6); - //load car trigger - safeJMP(imageBasedxplus + 0x72AB90, loadCar); + // Load car and story data at once + safeJMP(imageBasedxplus + 0x72AB90, loadGame); - //save car trigger - //injector::WriteMemory(imageBase + 0x376F80 + 2, (uintptr_t)SaveGameData, true); - //safeJMP(imageBase + 0x376F76, SaveGameData); + // Save car trigger + // injector::WriteMemory(imageBase + 0x376F80 + 2, (uintptr_t)SaveGameData, true); + // safeJMP(imageBase + 0x376F76, SaveGameData); - + // Save car trigger injector::MakeNOP(imageBasedxplus + 0x376F76, 0x12); injector::WriteMemory(imageBasedxplus + 0x376F76, 0xB848, true); injector::WriteMemory(imageBasedxplus + 0x376F76 + 2, (uintptr_t)SaveGameData, true); injector::WriteMemory(imageBasedxplus + 0x376F80, 0x3348D0FF, true); injector::WriteMemory(imageBasedxplus + 0x376F80 + 4, 0x90C0, true); - //prevents startup saving - //injector::MakeNOP(imageBase + 0x6B908C, 0x0D); - //safeJMP(imageBase + 0x6B908C, SaveOk); + // Prevents startup saving + // injector::MakeNOP(imageBase + 0x6B908C, 0x0D); + // safeJMP(imageBase + 0x6B908C, SaveOk); injector::WriteMemory(imageBasedxplus + 0x6B909A, 0xB848, true); injector::WriteMemory(imageBasedxplus + 0x6B909A + 2, (uintptr_t)SaveOk, true); injector::WriteMemory(imageBasedxplus + 0x6B90A4, 0x9090D0FF, true); - - } MH_EnableHook(MH_ALL_HOOKS);