system: per-content-type root overrides in ContentManager

This commit is contained in:
mchughalex 2026-07-19 23:18:43 +01:00
parent 9181630ece
commit 8130e534bc
2 changed files with 30 additions and 1 deletions

View file

@ -183,6 +183,14 @@ class ContentManager {
// and writes a .header file for XAM enumeration. // and writes a .header file for XAM enumeration.
X_RESULT InstallContent(const std::filesystem::path& package_path); X_RESULT InstallContent(const std::filesystem::path& package_path);
// Redirects all content of `content_type` to `root` with a flattened
// single-title layout instead of the shared content tree:
// root/{xuid}/{package}/ data
// root/{xuid}/Headers/{package}.header enumeration header
// The xuid level is kept so per-profile content stays isolated. Set before
// the title enumerates or opens content of this type; no data is migrated.
void SetContentTypeRoot(XContentType content_type, std::filesystem::path root);
private: private:
std::filesystem::path ResolvePackageRoot(uint64_t xuid, XContentType content_type, std::filesystem::path ResolvePackageRoot(uint64_t xuid, XContentType content_type,
uint32_t title_id = -1); uint32_t title_id = -1);
@ -199,6 +207,9 @@ class ContentManager {
KernelState* kernel_state_; KernelState* kernel_state_;
std::filesystem::path root_path_; std::filesystem::path root_path_;
// Per-content-type root overrides (SetContentTypeRoot), keyed by the raw
// XContentType value.
std::unordered_map<uint32_t, std::filesystem::path> content_type_roots_;
// TODO(benvanik): remove use of global lock, it's bad here! // TODO(benvanik): remove use of global lock, it's bad here!
rex::thread::global_critical_region global_critical_region_; rex::thread::global_critical_region global_critical_region_;

View file

@ -85,12 +85,23 @@ ContentManager::ContentManager(KernelState* kernel_state, const std::filesystem:
ContentManager::~ContentManager() = default; ContentManager::~ContentManager() = default;
void ContentManager::SetContentTypeRoot(XContentType content_type, std::filesystem::path root) {
content_type_roots_[uint32_t(content_type)] = std::move(root);
}
std::filesystem::path ContentManager::ResolvePackageRoot(uint64_t xuid, XContentType content_type, std::filesystem::path ContentManager::ResolvePackageRoot(uint64_t xuid, XContentType content_type,
uint32_t title_id) { uint32_t title_id) {
if (title_id == kCurrentlyRunningTitleId) { if (title_id == kCurrentlyRunningTitleId) {
title_id = kernel_state_->title_id(); title_id = kernel_state_->title_id();
} }
auto xuid_str = fmt::format("{:016X}", xuid); auto xuid_str = fmt::format("{:016X}", xuid);
// Overridden types use a flattened single-title layout: root/xuid/
auto override_it = content_type_roots_.find(uint32_t(content_type));
if (override_it != content_type_roots_.end()) {
return override_it->second / xuid_str;
}
auto title_id_str = fmt::format("{:08X}", title_id); auto title_id_str = fmt::format("{:08X}", title_id);
auto content_type_str = fmt::format("{:08X}", uint32_t(content_type)); auto content_type_str = fmt::format("{:08X}", uint32_t(content_type));
@ -126,9 +137,16 @@ std::filesystem::path ContentManager::ResolvePackageHeaderPath(const std::string
} }
auto xuid_str = fmt::format("{:016X}", xuid); auto xuid_str = fmt::format("{:016X}", xuid);
std::string final_name = std::string(file_name) + ".header";
// Overridden types keep headers beside their data: root/xuid/Headers/
auto override_it = content_type_roots_.find(uint32_t(content_type));
if (override_it != content_type_roots_.end()) {
return override_it->second / xuid_str / kGameContentHeaderDirName / final_name;
}
auto title_id_str = fmt::format("{:08X}", title_id); auto title_id_str = fmt::format("{:08X}", title_id);
auto content_type_str = fmt::format("{:08X}", uint32_t(content_type)); auto content_type_str = fmt::format("{:08X}", uint32_t(content_type));
std::string final_name = std::string(file_name) + ".header";
// Header root path: // Header root path:
// content_root/xuid/title_id/Headers/content_type/filename.header // content_root/xuid/title_id/Headers/content_type/filename.header