mirror of
https://github.com/shadps4-emu/shadPS4.git
synced 2026-10-12 02:22:27 +00:00
Trophy fix (#4774)
* trophies cleanup and fixes * even more trophy fixes for stephen
This commit is contained in:
@@ -1,6 +1,8 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2024-2026 shadPS4 Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <system_error>
|
||||
|
||||
#include "common/aes.h"
|
||||
#include "common/key_manager.h"
|
||||
#include "common/logging/log.h"
|
||||
@@ -35,13 +37,6 @@ static void removePadding(std::vector<u8>& vec) {
|
||||
}
|
||||
}
|
||||
|
||||
static void hexToBytes(const char* hex, unsigned char* dst) {
|
||||
for (size_t i = 0; hex[i] != 0; i++) {
|
||||
const unsigned char value = (hex[i] < 0x3A) ? (hex[i] - 0x30) : (hex[i] - 0x37);
|
||||
dst[i / 2] |= ((i % 2) == 0) ? (value << 4) : (value);
|
||||
}
|
||||
}
|
||||
|
||||
bool TRP::Extract(const std::filesystem::path& trophyPath, std::string npCommId,
|
||||
const std::filesystem::path& outputPath) {
|
||||
// Retrieve trophy key
|
||||
@@ -58,6 +53,10 @@ bool TRP::Extract(const std::filesystem::path& trophyPath, std::string npCommId,
|
||||
|
||||
s32 trpFileIndex = 0;
|
||||
bool success = true;
|
||||
const auto cleanupOnFailure = [&outputPath] {
|
||||
std::error_code ec;
|
||||
std::filesystem::remove_all(outputPath, ec);
|
||||
};
|
||||
try {
|
||||
if (trophyPath.extension() != ".trp") {
|
||||
return false;
|
||||
@@ -75,15 +74,22 @@ bool TRP::Extract(const std::filesystem::path& trophyPath, std::string npCommId,
|
||||
}
|
||||
|
||||
if (header.magic != TRP_MAGIC) {
|
||||
LOG_ERROR(Common_Filesystem, "Wrong trophy magic number in {}", trophyPath.string());
|
||||
LOG_ERROR(Common_Filesystem,
|
||||
"Wrong trophy magic number in {}: got {:#010x}, expected {:#010x}",
|
||||
trophyPath.string(), static_cast<u32>(header.magic), TRP_MAGIC);
|
||||
return false;
|
||||
}
|
||||
|
||||
s64 seekPos = sizeof(TrpHeader);
|
||||
// Create output directories
|
||||
if (!std::filesystem::create_directories(outputPath / "Icons") ||
|
||||
!std::filesystem::create_directories(outputPath / "Xml")) {
|
||||
LOG_ERROR(Common_Filesystem, "Failed to create output directories for {}", npCommId);
|
||||
std::error_code dir_ec;
|
||||
std::filesystem::create_directories(outputPath / "Icons", dir_ec);
|
||||
if (!dir_ec) {
|
||||
std::filesystem::create_directories(outputPath / "Xml", dir_ec);
|
||||
}
|
||||
if (dir_ec) {
|
||||
LOG_ERROR(Common_Filesystem, "Failed to create output directories for {}: {}", npCommId,
|
||||
dir_ec.message());
|
||||
cleanupOnFailure();
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -132,18 +138,22 @@ bool TRP::Extract(const std::filesystem::path& trophyPath, std::string npCommId,
|
||||
|
||||
} catch (const std::filesystem::filesystem_error& e) {
|
||||
LOG_CRITICAL(Common_Filesystem, "Filesystem error during trophy extraction: {}", e.what());
|
||||
cleanupOnFailure();
|
||||
return false;
|
||||
} catch (const std::exception& e) {
|
||||
LOG_CRITICAL(Common_Filesystem, "Error during trophy extraction: {}", e.what());
|
||||
cleanupOnFailure();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (success) {
|
||||
LOG_INFO(Common_Filesystem, "Successfully extracted {} trophy files for {}", trpFileIndex,
|
||||
npCommId);
|
||||
if (!success) {
|
||||
cleanupOnFailure();
|
||||
return false;
|
||||
}
|
||||
|
||||
return success;
|
||||
LOG_INFO(Common_Filesystem, "Successfully extracted {} trophy files for {}", trpFileIndex,
|
||||
npCommId);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TRP::ProcessPngEntry(Common::FS::IOFile& file, const TrpEntry& entry,
|
||||
|
||||
@@ -45,7 +45,4 @@ private:
|
||||
bool ProcessEncryptedXmlEntry(Common::FS::IOFile& file, const TrpEntry& entry,
|
||||
const std::filesystem::path& outputPath, std::string_view name,
|
||||
const std::array<u8, 16>& user_key, const std::string& npCommId);
|
||||
|
||||
std::array<u8, 16> esfmIv{};
|
||||
static constexpr int iv_len = 16;
|
||||
};
|
||||
|
||||
@@ -14,6 +14,28 @@
|
||||
|
||||
namespace Core::FileSys {
|
||||
|
||||
// Iterates a pre-collected entry list produced by merging the backend stack.
|
||||
class MergedDirectory final : public IDirectory {
|
||||
public:
|
||||
explicit MergedDirectory(std::vector<DirEntry> entries) : entries{std::move(entries)} {}
|
||||
|
||||
bool Next(DirEntry& out) override {
|
||||
if (index >= entries.size()) {
|
||||
return false;
|
||||
}
|
||||
out = entries[index++];
|
||||
return true;
|
||||
}
|
||||
|
||||
void Rewind() override {
|
||||
index = 0;
|
||||
}
|
||||
|
||||
private:
|
||||
std::vector<DirEntry> entries;
|
||||
size_t index{0};
|
||||
};
|
||||
|
||||
bool MntPoints::ignore_game_patches = false;
|
||||
|
||||
std::string RemoveTrailingSlashes(const std::string& path) {
|
||||
@@ -467,13 +489,31 @@ std::unique_ptr<IDirectory> MntPoints::OpenDir(std::string_view guest_path) {
|
||||
}
|
||||
const auto rel = RelativeToMount(*corrected, *mount);
|
||||
const std::string rel_copy{rel};
|
||||
|
||||
std::vector<DirEntry> entries;
|
||||
std::unordered_set<std::string> seen;
|
||||
bool found = false;
|
||||
for (const auto& backend : mount->backends) {
|
||||
if (backend->Exists(rel) && backend->IsDirectory(rel)) {
|
||||
return backend->OpenDir(rel_copy);
|
||||
if (!backend->Exists(rel) || !backend->IsDirectory(rel)) {
|
||||
continue;
|
||||
}
|
||||
found = true;
|
||||
auto dir = backend->OpenDir(rel_copy);
|
||||
if (!dir) {
|
||||
continue;
|
||||
}
|
||||
DirEntry entry;
|
||||
while (dir->Next(entry)) {
|
||||
const auto key = NeedsCaseInsensitiveSearch ? Common::ToLower(entry.name) : entry.name;
|
||||
if (!seen.insert(key).second) {
|
||||
continue;
|
||||
}
|
||||
entries.push_back(entry);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
if (!found) {
|
||||
return nullptr;
|
||||
}
|
||||
return std::make_unique<MergedDirectory>(std::move(entries));
|
||||
}
|
||||
|
||||
std::optional<std::vector<u8>> MntPoints::ReadFile(std::string_view guest_path) {
|
||||
|
||||
+29
-8
@@ -12,6 +12,7 @@
|
||||
|
||||
#include "common/debug.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/string_util.h"
|
||||
#include "common/thread.h"
|
||||
#include "core/emulator_settings.h"
|
||||
#include "core/ipc/ipc.h"
|
||||
@@ -157,12 +158,13 @@ std::map<s32, std::string> ExtractTrophies(std::string_view npbind_guest,
|
||||
if (entry.is_directory) {
|
||||
continue;
|
||||
}
|
||||
// Extension check: entry names carry the raw leaf, no path.
|
||||
if (entry.name.size() < 4 || entry.name.compare(entry.name.size() - 4, 4, ".trp") != 0) {
|
||||
// Extension check: match TROPHY00.TRP as well as trophy00.trp.
|
||||
const std::string name_lower = Common::ToLower(entry.name);
|
||||
if (!name_lower.ends_with(".trp")) {
|
||||
continue;
|
||||
}
|
||||
const std::string stem = entry.name.substr(0, entry.name.size() - 4);
|
||||
if (stem.find(pattern) != 0) {
|
||||
const std::string stem = name_lower.substr(0, name_lower.size() - 4);
|
||||
if (!stem.starts_with(pattern)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -212,7 +214,18 @@ std::map<s32, std::string> ExtractTrophies(std::string_view npbind_guest,
|
||||
continue;
|
||||
}
|
||||
TRP trp;
|
||||
const bool ok = trp.Extract(trp_source, np_comm_id, trophy_output_dir);
|
||||
bool ok = trp.Extract(trp_source, np_comm_id, trophy_output_dir);
|
||||
if (!ok) {
|
||||
// if it's an update and doesn't contain trophies fallback to base
|
||||
const auto base_source = mnt->GetHostPath(
|
||||
entry_guest, nullptr, Core::FileSys::MntPoints::HostPathType::Base);
|
||||
if (!base_source.empty() && base_source != trp_source &&
|
||||
std::filesystem::is_regular_file(base_source)) {
|
||||
LOG_WARNING(Loader, "Retrying trophy extraction with base game file {}",
|
||||
base_source.string());
|
||||
ok = trp.Extract(base_source, np_comm_id, trophy_output_dir);
|
||||
}
|
||||
}
|
||||
if (!temp_extract.empty()) {
|
||||
std::error_code ec;
|
||||
std::filesystem::remove(temp_extract, ec);
|
||||
@@ -231,13 +244,21 @@ std::map<s32, std::string> ExtractTrophies(std::string_view npbind_guest,
|
||||
if (!std::filesystem::exists(user_trophy_file)) {
|
||||
auto temp = user_trophy_file.parent_path();
|
||||
std::filesystem::create_directories(temp);
|
||||
std::error_code discard;
|
||||
std::filesystem::copy_file(trophy_output_dir / "Xml" / "TROPCONF.XML",
|
||||
user_trophy_file, discard);
|
||||
std::error_code ec;
|
||||
const auto tropconf = trophy_output_dir / "Xml" / "TROPCONF.XML";
|
||||
std::filesystem::copy_file(tropconf, user_trophy_file, ec);
|
||||
if (ec) {
|
||||
LOG_ERROR(Loader, "Failed to copy {} to {}: {}", tropconf.string(),
|
||||
user_trophy_file.string(), ec.message());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (trophy_index_map.empty()) {
|
||||
LOG_WARNING(Common_Filesystem, "No usable trophy files found in {}", trophy_dir_guest);
|
||||
}
|
||||
|
||||
return trophy_index_map;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user