mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-09-26 19:11:00 +00:00
3c38afad74
- [x] I have read and followed the [Contribution Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/CONTRIBUTING.md#code-contributions). - [x] I have read and followed the [AI Policy](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/AI.md) - [x] I have read and followed the [Coding Guidelines](https://git.eden-emu.dev/eden-emu/eden/src/branch/master/docs/policies/Coding.md) to the best of my ability. ------------------- Normal games are Applications; Bundled games are Application + Programs; We've been treating both as the same thing, calling both programs, and making programs unable to see settings and saves from application. References: https://switchbrew.org/wiki/Filesystem_services https://switchbrew.org/wiki/NCM_services#ApplicationId https://switchbrew.org/wiki/Super_Mario_3D_All-Stars Ryujinx.HLE/HOS/ApplicationLoader.cs:GetMultiProgramInfo UPDATE: The first version was a big rework to make AppId/ProgId concepts proper, and it was successful in most tests, but it caused a regression with applets, which are programs that breed straight from no application. In order to simplify things i've reverted all the rework, added a helper to identify whether a program has a parent Application and bounded it to it's proper stores. Although this is no big deal coz it doesn't have impact on emulation, it permeates to several routines, so it needs to be tested broadly. Applets, Normal games, Bundled games, Blobbed NSPs/XCIs, Mods, Updates, Saves, DLCs,. Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/4319 Reviewed-by: MaranBr <maranbr@eden-emu.dev> Reviewed-by: lizzie <lizzie@eden-emu.dev>
125 lines
4.1 KiB
C++
125 lines
4.1 KiB
C++
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
|
|
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
|
|
|
#pragma once
|
|
|
|
#include <map>
|
|
#include <memory>
|
|
#include <optional>
|
|
#include <string>
|
|
#include "common/common_types.h"
|
|
#include "core/file_sys/nca_metadata.h"
|
|
#include "core/file_sys/vfs/vfs_types.h"
|
|
#include "core/memory/dmnt_cheat_types.h"
|
|
|
|
namespace Core {
|
|
class System;
|
|
}
|
|
|
|
namespace Service::FileSystem {
|
|
class FileSystemController;
|
|
}
|
|
|
|
namespace FileSys {
|
|
|
|
class ContentProvider;
|
|
class NCA;
|
|
class NACP;
|
|
|
|
enum class PatchType { Update, DLC, Mod };
|
|
|
|
enum class PatchSource {
|
|
Unknown,
|
|
NAND,
|
|
SDMC,
|
|
External,
|
|
Packed,
|
|
};
|
|
|
|
struct Patch {
|
|
bool enabled;
|
|
std::string name;
|
|
std::string version;
|
|
PatchType type;
|
|
u64 program_id;
|
|
u64 title_id;
|
|
PatchSource source;
|
|
std::string location;
|
|
u32 numeric_version{0};
|
|
};
|
|
|
|
// A centralized class to manage patches to games.
|
|
class PatchManager {
|
|
public:
|
|
using BuildID = std::array<u8, 0x20>;
|
|
using Metadata = std::pair<std::unique_ptr<NACP>, VirtualFile>;
|
|
|
|
explicit PatchManager(u64 title_id_,
|
|
const Service::FileSystem::FileSystemController& fs_controller_,
|
|
const ContentProvider& content_provider_);
|
|
~PatchManager();
|
|
|
|
[[nodiscard]] u64 GetTitleID() const;
|
|
|
|
// Currently tracked ExeFS patches:
|
|
// - Game Updates
|
|
[[nodiscard]] VirtualDir PatchExeFS(VirtualDir exefs) const;
|
|
|
|
// Currently tracked NSO patches:
|
|
// - IPS
|
|
// - IPSwitch
|
|
[[nodiscard]] std::vector<u8> PatchNSO(const std::vector<u8>& nso,
|
|
const std::string& name) const;
|
|
|
|
// Checks to see if PatchNSO() will have any effect given the NSO's build ID.
|
|
// Used to prevent expensive copies in NSO loader.
|
|
[[nodiscard]] bool HasNSOPatch(const BuildID& build_id, std::string_view name) const;
|
|
|
|
// Creates a CheatList object with all
|
|
[[nodiscard]] std::vector<Core::Memory::CheatEntry> CreateCheatList(
|
|
const BuildID& build_id) const;
|
|
|
|
// Currently tracked RomFS patches:
|
|
// - Game Updates
|
|
// - LayeredFS
|
|
[[nodiscard]] VirtualFile PatchRomFS(const NCA* base_nca, VirtualFile base_romfs,
|
|
ContentRecordType type = ContentRecordType::Program,
|
|
VirtualFile packed_update_raw = nullptr,
|
|
bool apply_layeredfs = true) const;
|
|
|
|
// Returns a vector of patches
|
|
[[nodiscard]] std::vector<Patch> GetPatches(VirtualFile update_raw = nullptr) const;
|
|
|
|
// If the game update exists, returns the u32 version field in its Meta-type NCA. If that fails,
|
|
// it will fallback to the Meta-type NCA of the base game. If that fails, the result will be
|
|
// std::nullopt
|
|
[[nodiscard]] std::optional<u32> GetGameVersion() const;
|
|
|
|
// Given title_id of the program, attempts to get the control data of the update and parse
|
|
// it, falling back to the base control data.
|
|
[[nodiscard]] Metadata GetControlMetadata() const;
|
|
|
|
// Version of GetControlMetadata that takes an arbitrary NCA
|
|
[[nodiscard]] Metadata ParseControlNCA(const NCA& nca) const;
|
|
|
|
/// @brief Gets NACP metadata (accounting for any patches or updates)
|
|
[[nodiscard]] static PatchManager::Metadata GetMetadataFromBaseOrUpdate(Core::System& system, u64 application_id) noexcept;
|
|
|
|
private:
|
|
[[nodiscard]] VirtualDir GetModificationLoadRoot(bool sdmc = false) const;
|
|
[[nodiscard]] std::vector<std::string> GetDisabledAddons() const;
|
|
void ApplyLayeredFS(VirtualFile& romfs, ContentRecordType type) const;
|
|
[[nodiscard]] std::vector<VirtualFile> CollectPatches(const std::vector<VirtualDir>& patch_dirs,
|
|
const std::string& build_id) const;
|
|
|
|
u64 title_id;
|
|
std::optional<u64> parent_title_id;
|
|
const Service::FileSystem::FileSystemController& fs_controller;
|
|
const ContentProvider& content_provider;
|
|
};
|
|
|
|
} // namespace FileSys
|