[Patches] Add custom patches & fix MP4 patch

This commit is contained in:
nastys
2019-11-23 03:12:14 +01:00
parent 68a776df3f
commit aa790fc58c
13 changed files with 214 additions and 24 deletions
@@ -0,0 +1,6 @@
//# Enable FREE PLAY
// Just in case it's disabled...
//1403BABEA:75 // ...enable it.
//# Custom FREE PLAY text
//1409F61F0:!My text
+2
View File
@@ -58,6 +58,8 @@ Enhanced_Stage_Manager=0
Enhanced_Stage_Manager_Encore=1
#Unlock PSEUDO modules (incomplete, will default to Miku)
Unlock_Pseudo=0
#Enable custom patches
Custom_Patches=1
[Graphics]
# Set to -1 to unlock the frame rate.
Binary file not shown.

After

Width:  |  Height:  |  Size: 104 KiB

@@ -124,6 +124,9 @@
<DependentUpon>ui.h</DependentUpon>
</EmbeddedResource>
</ItemGroup>
<ItemGroup>
<Image Include="FeelsThinkMan.gif" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
@@ -253,8 +253,7 @@ private: ref class SkinnedMessageBoxForm : Form
// https://docs.microsoft.com/en-us/dotnet/api/system.windows.forms.messageboxicon?view=netframework-4.7.2
if (icon == MessageBoxIcon::Error) // also Hand and Stop
{
Drawing::Icon^ erricon = gcnew Drawing::Icon(SystemIcons::Error, iconsize, iconsize);
iconPB->Image = erricon->ToBitmap();
iconPB->Image = (Image^)(ResMgr->GetObject("FeelsThinkMan"));
iconPB->AccessibleDescription = "Error";
//this.Icon = SystemIcons.Error;
System::Media::SystemSounds::Hand->Play();
@@ -118,6 +118,9 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="FeelsThinkMan" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>FeelsThinkMan.gif;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
<data name="PokeSnarf4xd" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>PokeSnarf4xd.png;System.Drawing.Bitmap, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a</value>
</data>
@@ -10,6 +10,7 @@
#include "ConfigOption.h"
#include "PluginConfig.h"
#include <iostream>
int (__cdecl* divaMain)(int argc, const char** argv, const char** envp) = (int(__cdecl*)(int argc, const char** argv, const char** envp))0x140194D90;
@@ -203,7 +204,9 @@ ConfigOptionBase* optionsArray[] = {
new BooleanOption(L"opengl_patch_b", LAUNCHER_SECTION, CONFIG_FILE, L"OpenGL Patch B", L"Ignores some OpenGL-related errors. Don't use both patches at the same time unless you're know what you're doing.", L"", false),
new OptionMetaSpacer(8),
new BooleanOption(L"custom_patches", PATCHES_SECTION, CONFIG_FILE, L"Enable custom patches", L"Enable all custom patches.", true, false),
new BooleanOption(L"no_gpu_dialog", LAUNCHER_SECTION, CONFIG_FILE, L"Disable GPU Warning", L"Disables the warning dialog for unsupported GPUs.", L"", false),
//new BooleanOption(L"ignore_exe_checksum", PATCHES_SECTION, CONFIG_FILE, L"Ignore exe checksum", L"Use at your own risk.", false, false),
new StringOption(L"command_line", LAUNCHER_SECTION, CONFIG_FILE, L"Command Line:", L"Allows setting command line parameters for the game when using the launcher.\nDisabling the launcher will bypass this.", L"", false),
};
+2
View File
@@ -666,6 +666,8 @@ private: System::Void Button_Help_Click(System::Object^ sender, System::EventArg
System::Diagnostics::Process::Start("https://notabug.org/nastys/PD-Loader/wiki");
}
private: System::Void Button_Launch_Click(System::Object^ sender, System::EventArgs^ e) {
//SkinnedMessageBox::Show(this, "It looks like the executable has been tampered with, or the version of the game is not 7.10.\n\nPlease use the \"patches\" folder instead of modifying the executable directly (or disable verification).", "PD Launcher", MessageBoxButtons::OK, MessageBoxIcon::Error);
SaveSettings();
@@ -102,6 +102,9 @@
<ItemGroup>
<ClCompile Include="dllmain.cpp" />
</ItemGroup>
<ItemGroup>
<ClInclude Include="framework.h" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
@@ -19,4 +19,9 @@
<Filter>Source Files</Filter>
</ClCompile>
</ItemGroup>
<ItemGroup>
<ClInclude Include="framework.h">
<Filter>Header Files</Filter>
</ClInclude>
</ItemGroup>
</Project>
+142 -21
View File
@@ -3,16 +3,19 @@
#include <tchar.h>
#include <GL/freeglut.h>
#include <iostream>
#include <fstream>
#include <filesystem>
#include <sstream>
#include <iomanip>
#include "PluginConfigApi.h"
#include <detours.h>
#include "framework.h"
#pragma comment(lib, "detours.lib")
void InjectCode(void* address, const std::vector<uint8_t> data);
void ApplyPatches();
void ApplyCustomPatches(std::wstring CPATCH_FILE_STRING);
void(__cdecl* originalTAA)(DWORD *a1, int a2) = (void(__cdecl*)(DWORD *a1, int a2))0x1404B23A0;
void(__cdecl* originalMLAA)(__int64 a1, int a2) = (void(__cdecl*)(__int64 a1, int a2))0x1404B2210;
@@ -57,24 +60,29 @@ BOOL APIENTRY DllMain(HMODULE hModule,
void patchMovieExt(std::string moviefile, void* address)
{
bool isinmdata = 0;
for (int i = 0; i < 1000; i++)
{
std::stringstream ss;
ss << std::setw(3) << std::setfill('0') << i;
if (std::filesystem::exists("../mdata/M" + ss.str() + "/rom/movie/" + moviefile + ".mp4"))
try {
for (std::filesystem::path p : std::filesystem::directory_iterator("../mdata"))
{
isinmdata = 1;
//std::cout << "Movie " << moviefile << ".mp4 found in M" << ss.str() << std::endl;
break;
if (std::filesystem::path(p).filename().string().at(0) != 'M' || std::filesystem::path(p).filename().string().length() > 4) continue;
if (std::filesystem::exists(p.string() + "/rom/movie/" + moviefile + ".mp4"))
{
isinmdata = 1;
//std::cout << "[Patches] Movie " << moviefile << ".mp4 found in M" << ss.str() << std::endl;
break;
}
}
}
catch (const std::filesystem::filesystem_error & e) {
std::cout << "[Patches] File system error " << e.what() << " " << e.path1() << " " << e.path2() << " " << e.code() << std::endl;
}
if (isinmdata || std::filesystem::exists("../rom/movie/" + moviefile + ".mp4"))
{
InjectCode(address, { 0x6D, 0x70, 0x34 });
std::cout << "Movie " << moviefile << " patched to mp4\n";
std::cout << "[Patches] Movie " << moviefile << " patched to mp4\n";
return;
}
//std::cout << "Movie " << moviefile << " NOT patched to mp4\n";
//std::cout << "[Patches] Movie " << moviefile << " NOT patched to mp4\n";
return;
}
@@ -131,17 +139,17 @@ void ApplyPatches() {
{ (void*)0x00000001406A1FEF,{ 0xC7, 0x44, 0x24, 0x74, 0x00, 0x00, 0x00, 0x00 } }, // MOV dword ptr [RSP + 0x74],0x0
{ (void*)0x00000001406A1FF7,{ 0xEB, 0x0E } }, // JMP 0x1406a2007 (to rest of function as usual)
// add new code
{ (void*)0x00000001406A1FF9,{ 0x66, 0x48, 0x0F, 0x6E, 0xC2 } }, // MOVQ XMM0,RDX (load touch pos)
{ (void*)0x00000001406A1FFE,{ 0xEB, 0x5D } }, // JMP 0x1406a205d
{ (void*)0x00000001406A205D,{ 0x0F, 0x2A, 0x0D, 0xB8, 0x6A, 0x31, 0x00 } }, // CVTPI2PS XMM1,qword ptr [0x1409b8b1c] (load 1280x720)
{ (void*)0x00000001406A2064,{ 0x0F, 0x12, 0x51, 0x1C } }, // MOVLPS XMM2,qword ptr [RCX + 0x1c] (load actual res)
{ (void*)0x00000001406A2068,{ 0xE9, 0x14, 0xFF, 0xFF, 0xFF } }, // JMP 0x1406a1f81
{ (void*)0x00000001406A1F81,{ 0x0F, 0x59, 0xC1 } }, // MULPS XMM0,XMM1
{ (void*)0x00000001406A1F84,{ 0x0F, 0x5E, 0xC2 } }, // DIVPS XMM0,XMM2
{ (void*)0x00000001406A1F87,{ 0x66, 0x0F, 0xD6, 0x44, 0x24, 0x10 } }, // MOVQ qword ptr [RSP+0x10],XMM0
{ (void*)0x00000001406A1F8D,{ 0xEB, 0x06 } }, // JMP 0x1406a1f95 (back to original function)
// jmp to new code
{ (void*)0x00000001406A1F90,{ 0xEB, 0x67 } }, // JMP 0x1406a1ff9
{ (void*)0x00000001406A1FF9,{ 0x66, 0x48, 0x0F, 0x6E, 0xC2 } }, // MOVQ XMM0,RDX (load touch pos)
{ (void*)0x00000001406A1FFE,{ 0xEB, 0x5D } }, // JMP 0x1406a205d
{ (void*)0x00000001406A205D,{ 0x0F, 0x2A, 0x0D, 0xB8, 0x6A, 0x31, 0x00 } }, // CVTPI2PS XMM1,qword ptr [0x1409b8b1c] (load 1280x720)
{ (void*)0x00000001406A2064,{ 0x0F, 0x12, 0x51, 0x1C } }, // MOVLPS XMM2,qword ptr [RCX + 0x1c] (load actual res)
{ (void*)0x00000001406A2068,{ 0xE9, 0x14, 0xFF, 0xFF, 0xFF } }, // JMP 0x1406a1f81
{ (void*)0x00000001406A1F81,{ 0x0F, 0x59, 0xC1 } }, // MULPS XMM0,XMM1
{ (void*)0x00000001406A1F84,{ 0x0F, 0x5E, 0xC2 } }, // DIVPS XMM0,XMM2
{ (void*)0x00000001406A1F87,{ 0x66, 0x0F, 0xD6, 0x44, 0x24, 0x10 } }, // MOVQ qword ptr [RSP+0x10],XMM0
{ (void*)0x00000001406A1F8D,{ 0xEB, 0x06 } }, // JMP 0x1406a1f95 (back to original function)
// jmp to new code
{ (void*)0x00000001406A1F90,{ 0xEB, 0x67 } }, // JMP 0x1406a1ff9
};
printf("[Patches] Patches loaded\n");
@@ -171,6 +179,7 @@ void ApplyPatches() {
auto nTAA = GetPrivateProfileIntW(L"graphics", L"taa", TRUE, CONFIG_FILE);
auto nMLAA = GetPrivateProfileIntW(L"graphics", L"mlaa", TRUE, CONFIG_FILE);
auto nStereo = GetPrivateProfileIntW(L"patches", L"stereo", TRUE, CONFIG_FILE);
auto nCustomPatches = GetPrivateProfileIntW(L"patches", L"custom_patches", TRUE, CONFIG_FILE);
// The old stereo patch...
// Use 2 channels instead of 4
@@ -420,6 +429,27 @@ void ApplyPatches() {
// Don't update the touch slider state so we can write our own
InjectCode((void*)0x000000014061579B, { 0x90, 0x90, 0x90, 0x8B, 0x42, 0xE0, 0x90, 0x90, 0x90 });
}
if (nCustomPatches)
{
std::cout << "[Patches] Reading custom patches...\n";
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")
{
std::cout << "[Patches] Reading custom patch file: " << std::filesystem::path(p).filename().string() << std::endl;
ApplyCustomPatches(std::filesystem::path(p).wstring());
}
}
}
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 InjectCode(void* address, const std::vector<uint8_t> data)
@@ -432,6 +462,97 @@ void InjectCode(void* address, const std::vector<uint8_t> data)
VirtualProtect(address, byteCount, oldProtect, nullptr);
}
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.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;
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) == '!')
{
std::vector<std::string> fullColonSplit = SplitString(line, ":");
for (int i = 1; i < fullColonSplit[1].size(); i++)
{
std::cout << "[Patches] Patching: " << std::hex << address << ":" << fullColonSplit[1].at(i) << std::endl;
unsigned char byte_u = fullColonSplit[1].at(i);
std::vector<uint8_t> patch = { byte_u };
InjectCode((void*)address, patch);
address++;
}
}
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;
}
}
for (std::string bytestring : bytes)
{
int byte;
std::istringstream issb(bytestring);
issb >> std::setbase(16) >> byte;
unsigned char byte_u = byte;
std::cout << "[Patches] Patching: " << std::hex << address << ":" << std::hex << byte;
if (comment_string != "")
{
std::cout << " #" << comment_string.at(comment_counter);
comment_counter++;
}
std::cout << std::endl;
std::vector<uint8_t> patch = { byte_u };
InjectCode((void*)address, patch);
address++;
}
}
}
fileStream.close();
}
using namespace PluginConfig;
@@ -0,0 +1,36 @@
#pragma once
#include <string>
std::string TrimString(const std::string& str, const std::string& whitespace)
{
const size_t strBegin = str.find_first_not_of(whitespace);
if (strBegin == std::string::npos)
return "";
const size_t strEnd = str.find_last_not_of(whitespace);
const size_t strRange = strEnd - strBegin + 1;
return str.substr(strBegin, strRange);
}
std::vector<std::string> SplitString(const std::string& str, const std::string& delim)
{
std::vector<std::string> tokens;
size_t prev = 0, pos = 0;
do
{
pos = str.find(delim, prev);
if (pos == std::string::npos)
pos = str.length();
std::string token = str.substr(prev, pos - prev);
if (!token.empty())
tokens.push_back(token);
prev = pos + delim.length();
} while (pos < str.length() && prev < str.length());
return tokens;
}