Skip to content

Commit

Permalink
Merge branch 'shadps4-emu:main' into bb-shaders-skip
Browse files Browse the repository at this point in the history
  • Loading branch information
Foul-Tarnished authored Sep 14, 2024
2 parents 29afbb3 + c924457 commit 43ed6f3
Show file tree
Hide file tree
Showing 12 changed files with 176 additions and 50 deletions.
4 changes: 2 additions & 2 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,8 @@ set(COMMON src/common/logging/backend.cpp
src/common/version.h
src/common/ntapi.h
src/common/ntapi.cpp
src/common/memory_patcher.h
src/common/memory_patcher.cpp
src/common/scm_rev.cpp
src/common/scm_rev.h
)
Expand Down Expand Up @@ -628,8 +630,6 @@ set(QT_GUI src/qt_gui/about_dialog.cpp
src/qt_gui/about_dialog.ui
src/qt_gui/cheats_patches.cpp
src/qt_gui/cheats_patches.h
src/qt_gui/memory_patcher.cpp
src/qt_gui/memory_patcher.h
src/qt_gui/main_window_ui.h
src/qt_gui/main_window.cpp
src/qt_gui/main_window.h
Expand Down
171 changes: 135 additions & 36 deletions src/qt_gui/memory_patcher.cpp → src/common/memory_patcher.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,93 +2,190 @@
// SPDX-License-Identifier: GPL-2.0-or-later

#include <algorithm>
#include <codecvt>
#include <sstream>
#include <string>
#include <pugixml.hpp>
#ifdef ENABLE_QT_GUI
#include <QFile>
#include <QJsonArray>
#include <QJsonDocument>
#include <QJsonObject>
#include <QListView>
#include <QMessageBox>
#include <QString>
#include <QXmlStreamReader>
#endif
#include "common/logging/log.h"
#include "common/path_util.h"
#include "memory_patcher.h"

namespace MemoryPatcher {

uintptr_t g_eboot_address;
u64 g_eboot_image_size;
uint64_t g_eboot_image_size;
std::string g_game_serial;
std::string patchFile;
std::vector<patchInfo> pending_patches;

QString toHex(unsigned long long value, size_t byteSize) {
std::string toHex(unsigned long long value, size_t byteSize) {
std::stringstream ss;
ss << std::hex << std::setfill('0') << std::setw(byteSize * 2) << value;
return QString::fromStdString(ss.str());
return ss.str();
}

QString convertValueToHex(const QString& type, const QString& valueStr) {
QString result;
std::string typeStr = type.toStdString();
std::string valueStrStd = valueStr.toStdString();
std::string convertValueToHex(const std::string type, const std::string valueStr) {
std::string result;

if (typeStr == "byte") {
unsigned int value = std::stoul(valueStrStd, nullptr, 16);
if (type == "byte") {
unsigned int value = std::stoul(valueStr, nullptr, 16);
result = toHex(value, 1);
} else if (typeStr == "bytes16") {
unsigned int value = std::stoul(valueStrStd, nullptr, 16);
} else if (type == "bytes16") {
unsigned int value = std::stoul(valueStr, nullptr, 16);
result = toHex(value, 2);
} else if (typeStr == "bytes32") {
unsigned long value = std::stoul(valueStrStd, nullptr, 16);
} else if (type == "bytes32") {
unsigned long value = std::stoul(valueStr, nullptr, 16);
result = toHex(value, 4);
} else if (typeStr == "bytes64") {
unsigned long long value = std::stoull(valueStrStd, nullptr, 16);
} else if (type == "bytes64") {
unsigned long long value = std::stoull(valueStr, nullptr, 16);
result = toHex(value, 8);
} else if (typeStr == "float32") {
} else if (type == "float32") {
union {
float f;
uint32_t i;
} floatUnion;
floatUnion.f = std::stof(valueStrStd);
floatUnion.f = std::stof(valueStr);
result = toHex(floatUnion.i, sizeof(floatUnion.i));
} else if (typeStr == "float64") {
} else if (type == "float64") {
union {
double d;
uint64_t i;
} doubleUnion;
doubleUnion.d = std::stod(valueStrStd);
doubleUnion.d = std::stod(valueStr);
result = toHex(doubleUnion.i, sizeof(doubleUnion.i));
} else if (typeStr == "utf8") {
QByteArray byteArray = QString::fromStdString(valueStrStd).toUtf8();
byteArray.append('\0');
} else if (type == "utf8") {
std::vector<unsigned char> byteArray =
std::vector<unsigned char>(valueStr.begin(), valueStr.end());
byteArray.push_back('\0');
std::stringstream ss;
for (unsigned char c : byteArray) {
ss << std::hex << std::setfill('0') << std::setw(2) << static_cast<int>(c);
}
result = QString::fromStdString(ss.str());
} else if (typeStr == "utf16") {
QByteArray byteArray(
reinterpret_cast<const char*>(QString::fromStdString(valueStrStd).utf16()),
QString::fromStdString(valueStrStd).size() * 2);
byteArray.append('\0');
byteArray.append('\0');
result = ss.str();
} else if (type == "utf16") {
std::wstring wide_str(valueStr.size(), L'\0');
std::mbstowcs(&wide_str[0], valueStr.c_str(), valueStr.size());
wide_str.resize(std::wcslen(wide_str.c_str()));

std::u16string valueStringU16;

for (wchar_t wc : wide_str) {
if (wc <= 0xFFFF) {
valueStringU16.push_back(static_cast<char16_t>(wc));
} else {
wc -= 0x10000;
valueStringU16.push_back(static_cast<char16_t>(0xD800 | (wc >> 10)));
valueStringU16.push_back(static_cast<char16_t>(0xDC00 | (wc & 0x3FF)));
}
}

std::vector<unsigned char> byteArray;
// convert to little endian
for (char16_t ch : valueStringU16) {
unsigned char low_byte = static_cast<unsigned char>(ch & 0x00FF);
unsigned char high_byte = static_cast<unsigned char>((ch >> 8) & 0x00FF);

byteArray.push_back(low_byte);
byteArray.push_back(high_byte);
}
byteArray.push_back('\0');
byteArray.push_back('\0');
std::stringstream ss;
for (unsigned char c : byteArray) {
ss << std::hex << std::setfill('0') << std::setw(2) << static_cast<int>(c);

for (unsigned char ch : byteArray) {
ss << std::hex << std::setw(2) << std::setfill('0') << static_cast<int>(ch);
}
result = QString::fromStdString(ss.str());
} else if (typeStr == "bytes") {
result = ss.str();
} else if (type == "bytes") {
result = valueStr;
} else if (typeStr == "mask" || typeStr == "mask_jump32") {
} else if (type == "mask" || type == "mask_jump32") {
result = valueStr;
} else {
LOG_INFO(Loader, "Error applying Patch, unknown type: {}", typeStr);
LOG_INFO(Loader, "Error applying Patch, unknown type: {}", type);
}
return result;
}

void OnGameLoaded() {

if (!patchFile.empty()) {
std::string patchDir = Common::FS::GetUserPath(Common::FS::PathType::PatchesDir).string();

std::string filePath = patchDir + "/" + patchFile;

pugi::xml_document doc;
pugi::xml_parse_result result = doc.load_file(filePath.c_str());

if (result) {
auto patchXML = doc.child("Patch");
for (pugi::xml_node_iterator it = patchXML.children().begin();
it != patchXML.children().end(); ++it) {

if (std::string(it->name()) == "Metadata") {
if (std::string(it->attribute("isEnabled").value()) == "true") {
auto patchList = it->first_child();

std::string currentPatchName = it->attribute("Name").value();

for (pugi::xml_node_iterator patchLineIt = patchList.children().begin();
patchLineIt != patchList.children().end(); ++patchLineIt) {

std::string type = patchLineIt->attribute("Type").value();
std::string address = patchLineIt->attribute("Address").value();
std::string patchValue = patchLineIt->attribute("Value").value();
std::string maskOffsetStr = patchLineIt->attribute("type").value();

patchValue = convertValueToHex(type, patchValue);

bool littleEndian = false;

if (type == "bytes16") {
littleEndian = true;
} else if (type == "bytes32") {
littleEndian = true;
} else if (type == "bytes64") {
littleEndian = true;
}

MemoryPatcher::PatchMask patchMask = MemoryPatcher::PatchMask::None;
int maskOffsetValue = 0;

if (type == "mask") {
patchMask = MemoryPatcher::PatchMask::Mask;

// im not sure if this works, there is no games to test the mask
// offset on yet
if (!maskOffsetStr.empty())
maskOffsetValue = std::stoi(maskOffsetStr, 0, 10);
}

if (type == "mask_jump32")
patchMask = MemoryPatcher::PatchMask::Mask_Jump32;

MemoryPatcher::PatchMemory(currentPatchName, address, patchValue, false,
littleEndian, patchMask);
}
}
}
}
} else
LOG_ERROR(Loader, "couldnt patch parse xml : {}", result.description());

ApplyPendingPatches();
return;
}

#ifdef ENABLE_QT_GUI
// We use the QT headers for the xml and json parsing, this define is only true on QT builds
QString patchDir =
QString::fromStdString(Common::FS::GetUserPath(Common::FS::PathType::PatchesDir).string());
Expand Down Expand Up @@ -190,7 +287,8 @@ void OnGameLoaded() {
QString patchValue = lineObject["Value"].toString();
QString maskOffsetStr = lineObject["Offset"].toString();

patchValue = convertValueToHex(type, patchValue);
patchValue = QString::fromStdString(
convertValueToHex(type.toStdString(), patchValue.toStdString()));

bool littleEndian = false;

Expand Down Expand Up @@ -233,6 +331,7 @@ void OnGameLoaded() {
}
ApplyPendingPatches();
}
#endif
}

void AddPatchToQueue(patchInfo patchToAdd) {
Expand Down
6 changes: 3 additions & 3 deletions src/qt_gui/memory_patcher.h → src/common/memory_patcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,13 @@
#include <cstring>
#include <string>
#include <vector>
#include <QString>

namespace MemoryPatcher {

extern uintptr_t g_eboot_address;
extern u64 g_eboot_image_size;
extern uint64_t g_eboot_image_size;
extern std::string g_game_serial;
extern std::string patchFile;

enum PatchMask : uint8_t {
None,
Expand All @@ -32,7 +32,7 @@ struct patchInfo {

extern std::vector<patchInfo> pending_patches;

QString convertValueToHex(const QString& type, const QString& valueStr);
std::string convertValueToHex(const std::string type, const std::string valueStr);

void OnGameLoaded();
void AddPatchToQueue(patchInfo patchToAdd);
Expand Down
2 changes: 1 addition & 1 deletion src/core/libraries/kernel/thread_management.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1063,7 +1063,7 @@ ScePthread PThreadPool::Create(const char* name) {
std::scoped_lock lock{m_mutex};

for (auto* p : m_threads) {
if (p->is_free && p->name == name) {
if (p->is_free && name != nullptr && p->name == name) {
p->is_free = false;
return p;
}
Expand Down
6 changes: 1 addition & 5 deletions src/core/module.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,7 @@
#include "common/arch.h"
#include "common/assert.h"
#include "common/logging/log.h"
#ifdef ENABLE_QT_GUI
#include "qt_gui/memory_patcher.h"
#endif
#include "common/memory_patcher.h"
#include "common/string_util.h"
#include "core/aerolib/aerolib.h"
#include "core/cpu_patches.h"
Expand Down Expand Up @@ -199,15 +197,13 @@ void Module::LoadModuleToMemory(u32& max_tls_index) {
const VAddr entry_addr = base_virtual_addr + elf.GetElfEntry();
LOG_INFO(Core_Linker, "program entry addr ..........: {:#018x}", entry_addr);

#ifdef ENABLE_QT_GUI
if (MemoryPatcher::g_eboot_address == 0) {
if (name == "eboot") {
MemoryPatcher::g_eboot_address = base_virtual_addr;
MemoryPatcher::g_eboot_image_size = base_size;
MemoryPatcher::OnGameLoaded();
}
}
#endif
}

void Module::LoadDynamicInfo() {
Expand Down
2 changes: 1 addition & 1 deletion src/emulator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
#include "common/logging/backend.h"
#include "common/logging/log.h"
#ifdef ENABLE_QT_GUI
#include "qt_gui/memory_patcher.h"
#include "common/memory_patcher.h"
#endif
#include "common/ntapi.h"
#include "common/path_util.h"
Expand Down
10 changes: 10 additions & 0 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later

#include <fmt/core.h>
#include "common/memory_patcher.h"
#include "emulator.h"

int main(int argc, char* argv[]) {
Expand All @@ -10,7 +11,16 @@ int main(int argc, char* argv[]) {
return -1;
}

for (int i = 0; i < argc; i++) {
std::string curArg = argv[i];
if (curArg == "-p") {
std::string patchFile = argv[i + 1];
MemoryPatcher::patchFile = patchFile;
}
}

Core::Emulator emulator;
emulator.Run(argv[1]);

return 0;
}
5 changes: 3 additions & 2 deletions src/qt_gui/cheats_patches.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,9 +28,9 @@
#include <QXmlStreamReader>
#include <common/logging/log.h>
#include "cheats_patches.h"
#include "common/memory_patcher.h"
#include "common/path_util.h"
#include "core/module.h"
#include "qt_gui/memory_patcher.h"

using namespace Common::FS;

Expand Down Expand Up @@ -1178,7 +1178,8 @@ void CheatsPatches::applyPatch(const QString& patchName, bool enabled) {
QString patchValue = lineObject["Value"].toString();
QString maskOffsetStr = lineObject["Offset"].toString();

patchValue = MemoryPatcher::convertValueToHex(type, patchValue);
patchValue = QString::fromStdString(
MemoryPatcher::convertValueToHex(type.toStdString(), patchValue.toStdString()));

bool littleEndian = false;

Expand Down
8 changes: 8 additions & 0 deletions src/qt_gui/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later

#include "common/config.h"
#include "common/memory_patcher.h"
#include "core/file_sys/fs.h"
#include "emulator.h"
#include "game_install_dialog.h"
Expand Down Expand Up @@ -36,6 +37,13 @@ int main(int argc, char* argv[]) {
// Check for command line arguments
if (has_command_line_argument) {
Core::Emulator emulator;
for (int i = 0; i < argc; i++) {
std::string curArg = argv[i];
if (curArg == "-p") {
std::string patchFile = argv[i + 1];
MemoryPatcher::patchFile = patchFile;
}
}
emulator.Run(argv[1]);
}

Expand Down
Loading

0 comments on commit 43ed6f3

Please sign in to comment.