diff --git a/src/android/app/src/main/jni/game_metadata.cpp b/src/android/app/src/main/jni/game_metadata.cpp index 9acba456f1..0f23e4d2ac 100644 --- a/src/android/app/src/main/jni/game_metadata.cpp +++ b/src/android/app/src/main/jni/game_metadata.cpp @@ -20,132 +20,96 @@ struct RomMetadata { std::vector icon; bool isHomebrew; }; +static ankerl::unordered_dense::map m_rom_metadata_cache; -ankerl::unordered_dense::map m_rom_metadata_cache; +static RomMetadata CacheRomMetadata(const std::string& path) { + auto& instance = EmulationSession::GetInstance(); + const auto file = Core::GetGameFileFromPath(instance.System().GetFilesystem(), path); + if (auto loader = Loader::GetLoader(instance.System(), file, 0, 0); loader) { + RomMetadata entry; + loader->ReadTitle(entry.title); + loader->ReadProgramId(entry.programId); + loader->ReadIcon(entry.icon); -RomMetadata CacheRomMetadata(const std::string& path) { - const auto file = - Core::GetGameFileFromPath(EmulationSession::GetInstance().System().GetFilesystem(), path); - auto loader = Loader::GetLoader(EmulationSession::GetInstance().System(), file, 0, 0); + const FileSys::PatchManager pm{ + entry.programId, + instance.System().GetFileSystemController(), + instance.System().GetContentProvider() + }; + const auto control = pm.GetControlMetadata(); - RomMetadata entry; - loader->ReadTitle(entry.title); - loader->ReadProgramId(entry.programId); - loader->ReadIcon(entry.icon); - - const FileSys::PatchManager pm{ - entry.programId, EmulationSession::GetInstance().System().GetFileSystemController(), - EmulationSession::GetInstance().System().GetContentProvider()}; - const auto control = pm.GetControlMetadata(); - - if (control.first != nullptr) { - entry.developer = control.first->GetDeveloperName(); - entry.version = control.first->GetVersionString(); - } else { - FileSys::NACP nacp; - if (loader->ReadControlData(nacp) == Loader::ResultStatus::Success) { - entry.developer = nacp.GetDeveloperName(); + if (control.first != nullptr) { + entry.developer = control.first->GetDeveloperName(); + entry.version = control.first->GetVersionString(); } else { - entry.developer = ""; + FileSys::NACP nacp{}; + entry.developer = loader->ReadControlData(nacp) == Loader::ResultStatus::Success + ? nacp.GetDeveloperName() + : ""; + entry.version = "1.0.0"; } - - entry.version = "1.0.0"; + if (loader->GetFileType() == Loader::FileType::NRO) { + auto loader_nro = reinterpret_cast(loader.get()); + entry.isHomebrew = loader_nro->IsHomebrew(); + } else { + entry.isHomebrew = false; + } + m_rom_metadata_cache[path] = entry; + return entry; } - - if (loader->GetFileType() == Loader::FileType::NRO) { - auto loader_nro = reinterpret_cast(loader.get()); - entry.isHomebrew = loader_nro->IsHomebrew(); - } else { - entry.isHomebrew = false; - } - - m_rom_metadata_cache[path] = entry; - - return entry; + return {}; } -RomMetadata GetRomMetadata(const std::string& path, bool reload = false) { - if (reload) { +static RomMetadata GetRomMetadata(const std::string& path, bool reload = false) { + if (reload) return CacheRomMetadata(path); - } - - if (auto search = m_rom_metadata_cache.find(path); search != m_rom_metadata_cache.end()) { - return search->second; - } - + if (auto it = m_rom_metadata_cache.find(path); it != m_rom_metadata_cache.end()) + return it->second; return CacheRomMetadata(path); } extern "C" { -jboolean Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getIsValid(JNIEnv* env, jobject obj, - jstring jpath) { - const auto file = EmulationSession::GetInstance().System().GetFilesystem()->OpenFile( - Common::Android::GetJString(env, jpath), FileSys::OpenMode::Read); - if (!file) { - return false; +jboolean Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getIsValid(JNIEnv* env, jobject obj, jstring jpath) { + if (auto const file = EmulationSession::GetInstance().System().GetFilesystem()->OpenFile(Common::Android::GetJString(env, jpath), FileSys::OpenMode::Read); file) { + if (auto loader = Loader::GetLoader(EmulationSession::GetInstance().System(), file); loader) { + auto const file_type = loader->GetFileType(); + if (file_type == Loader::FileType::Unknown || file_type == Loader::FileType::Error) + return false; + if ((file_type == Loader::FileType::NSP || file_type == Loader::FileType::XCI) && !Loader::IsBootableGameContainer(file, file_type)) + return false; + u64 program_id = 0; + return loader->ReadProgramId(program_id) == Loader::ResultStatus::Success; + } } - - auto loader = Loader::GetLoader(EmulationSession::GetInstance().System(), file); - if (!loader) { - return false; - } - - const auto file_type = loader->GetFileType(); - if (file_type == Loader::FileType::Unknown || file_type == Loader::FileType::Error) { - return false; - } - - if ((file_type == Loader::FileType::NSP || file_type == Loader::FileType::XCI) && - !Loader::IsBootableGameContainer(file, file_type)) { - return false; - } - - u64 program_id = 0; - Loader::ResultStatus res = loader->ReadProgramId(program_id); - if (res != Loader::ResultStatus::Success) { - return false; - } - return true; + return false; } -jstring Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getTitle(JNIEnv* env, jobject obj, - jstring jpath) { - return Common::Android::ToJString( - env, GetRomMetadata(Common::Android::GetJString(env, jpath)).title); +jstring Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getTitle(JNIEnv* env, jobject obj, jstring jpath) { + return Common::Android::ToJString(env, GetRomMetadata(Common::Android::GetJString(env, jpath)).title); } -jstring Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getProgramId(JNIEnv* env, jobject obj, - jstring jpath) { - return Common::Android::ToJString( - env, std::to_string(GetRomMetadata(Common::Android::GetJString(env, jpath)).programId)); +jstring Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getProgramId(JNIEnv* env, jobject obj, jstring jpath) { + return Common::Android::ToJString(env, std::to_string(GetRomMetadata(Common::Android::GetJString(env, jpath)).programId)); } -jstring Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getDeveloper(JNIEnv* env, jobject obj, - jstring jpath) { - return Common::Android::ToJString( - env, GetRomMetadata(Common::Android::GetJString(env, jpath)).developer); +jstring Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getDeveloper(JNIEnv* env, jobject obj, jstring jpath) { + return Common::Android::ToJString(env, GetRomMetadata(Common::Android::GetJString(env, jpath)).developer); } -jstring Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getVersion(JNIEnv* env, jobject obj, - jstring jpath, jboolean jreload) { - return Common::Android::ToJString( - env, GetRomMetadata(Common::Android::GetJString(env, jpath), jreload).version); +jstring Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getVersion(JNIEnv* env, jobject obj, jstring jpath, jboolean jreload) { + return Common::Android::ToJString(env, GetRomMetadata(Common::Android::GetJString(env, jpath), jreload).version); } -jbyteArray Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getIcon(JNIEnv* env, jobject obj, - jstring jpath) { +jbyteArray Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getIcon(JNIEnv* env, jobject obj, jstring jpath) { auto icon_data = GetRomMetadata(Common::Android::GetJString(env, jpath)).icon; - jbyteArray icon = env->NewByteArray(static_cast(icon_data.size())); - env->SetByteArrayRegion(icon, 0, env->GetArrayLength(icon), - reinterpret_cast(icon_data.data())); + jbyteArray icon = env->NewByteArray(jsize(icon_data.size())); + env->SetByteArrayRegion(icon, 0, env->GetArrayLength(icon), reinterpret_cast(icon_data.data())); return icon; } -jboolean Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getIsHomebrew(JNIEnv* env, jobject obj, - jstring jpath) { - return static_cast( - GetRomMetadata(Common::Android::GetJString(env, jpath)).isHomebrew); +jboolean Java_org_yuzu_yuzu_1emu_utils_GameMetadata_getIsHomebrew(JNIEnv* env, jobject obj, jstring jpath) { + return jboolean(GetRomMetadata(Common::Android::GetJString(env, jpath)).isHomebrew); } void Java_org_yuzu_yuzu_1emu_utils_GameMetadata_resetMetadata(JNIEnv* env, jobject obj) { diff --git a/src/common/uuid.cpp b/src/common/uuid.cpp index d4a5733c26..51fe0abaa5 100644 --- a/src/common/uuid.cpp +++ b/src/common/uuid.cpp @@ -208,4 +208,12 @@ UUID UUID::MakeRandomRFC4122V4() { return uuid; } +UUID UUID::MakeRFC4122V5(std::span sha1) { + UUID uuid{}; + std::memcpy(&uuid.uuid, sha1.data(), sizeof(UUID)); + uuid.uuid[8] = 0x80 | (uuid.uuid[8] & 0x3F); + uuid.uuid[6] = 0x50 | (uuid.uuid[6] & 0xF); + return uuid; +} + } // namespace Common diff --git a/src/common/uuid.h b/src/common/uuid.h index 60c5d75f12..c3cbd7b479 100644 --- a/src/common/uuid.h +++ b/src/common/uuid.h @@ -1,3 +1,6 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + // SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later @@ -5,6 +8,7 @@ #include #include +#include #include #include "common/common_types.h" @@ -86,28 +90,20 @@ struct UUID { }; } - /** - * Creates a random UUID. - * - * @returns A random UUID. - */ - static UUID MakeRandom(); + /// @brief Creates a random UUID. + /// @returns A random UUID. + [[nodiscard]] static UUID MakeRandom(); - /** - * Creates a random UUID with a seed. - * - * @param seed A seed to initialize the Mersenne-Twister RNG - * - * @returns A random UUID. - */ - static UUID MakeRandomWithSeed(u32 seed); + /// @brief Creates a random UUID with a seed. + /// @param seed A seed to initialize the Mersenne-Twister RNG + /// @returns A random UUID. + [[nodiscard]] static UUID MakeRandomWithSeed(u32 seed); - /** - * Creates a random UUID. The generated UUID is RFC 4122 Version 4 compliant. - * - * @returns A random UUID that is RFC 4122 Version 4 compliant. - */ - static UUID MakeRandomRFC4122V4(); + /// @brief Creates a random UUID. The generated UUID is RFC 4122 Version 4 compliant. + /// @returns A random UUID that is RFC 4122 Version 4 compliant. + [[nodiscard]] static UUID MakeRandomRFC4122V4(); + + [[nodiscard]] static UUID MakeRFC4122V5(std::span sha1); friend constexpr bool operator==(const UUID& lhs, const UUID& rhs) = default; }; diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h index 7b90ba235d..670e8f7389 100644 --- a/src/core/file_sys/control_metadata.h +++ b/src/core/file_sys/control_metadata.h @@ -274,23 +274,22 @@ public: explicit NACP(VirtualFile file); ~NACP(); - const LanguageEntry& GetLanguageEntry() const; - std::string GetApplicationName() const; - std::string GetDeveloperName() const; - u64 GetTitleId() const; - u64 GetDLCBaseTitleId() const; - std::string GetVersionString() const; - u64 GetDefaultNormalSaveSize() const; - u64 GetDefaultJournalSaveSize() const; - u32 GetSupportedLanguages() const; - std::vector GetApplicationNames() const; - std::vector GetRawBytes() const; - bool GetUserAccountSwitchLock() const; - u64 GetDeviceSaveDataSize() const; - u32 GetParentalControlFlag() const; - const std::array& GetRatingAge() const; + [[nodiscard]] const LanguageEntry& GetLanguageEntry() const; + [[nodiscard]] std::string GetApplicationName() const; + [[nodiscard]] std::string GetDeveloperName() const; + [[nodiscard]] u64 GetTitleId() const; + [[nodiscard]] u64 GetDLCBaseTitleId() const; + [[nodiscard]] std::string GetVersionString() const; + [[nodiscard]] u64 GetDefaultNormalSaveSize() const; + [[nodiscard]] u64 GetDefaultJournalSaveSize() const; + [[nodiscard]] u32 GetSupportedLanguages() const; + [[nodiscard]] std::vector GetApplicationNames() const; + [[nodiscard]] std::vector GetRawBytes() const; + [[nodiscard]] bool GetUserAccountSwitchLock() const; + [[nodiscard]] u64 GetDeviceSaveDataSize() const; + [[nodiscard]] u32 GetParentalControlFlag() const; + [[nodiscard]] const std::array& GetRatingAge() const; -private: RawNACP raw{}; std::vector language_entries; }; diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp index 80372ec94e..6ae4679054 100644 --- a/src/core/file_sys/patch_manager.cpp +++ b/src/core/file_sys/patch_manager.cpp @@ -1156,4 +1156,14 @@ PatchManager::Metadata PatchManager::ParseControlNCA(const NCA& nca) const { return {std::move(nacp), icon_file}; } + +[[nodiscard]] PatchManager::Metadata PatchManager::GetMetadataFromBaseOrUpdate(Core::System& system, u64 application_id) noexcept { + const FileSys::PatchManager pm{application_id, system.GetFileSystemController(), system.GetContentProvider()}; + auto metadata = pm.GetControlMetadata(); + if (metadata.first != nullptr) + return metadata; + const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(application_id), system.GetFileSystemController(), system.GetContentProvider()}; + return pm_update.GetControlMetadata(); +} + } // namespace FileSys diff --git a/src/core/file_sys/patch_manager.h b/src/core/file_sys/patch_manager.h index 755d924fd4..5d71dbcf20 100644 --- a/src/core/file_sys/patch_manager.h +++ b/src/core/file_sys/patch_manager.h @@ -105,6 +105,9 @@ public: // 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]] std::vector CollectPatches(const std::vector& patch_dirs, const std::string& build_id) const; diff --git a/src/core/hle/service/am/service/application_functions.cpp b/src/core/hle/service/am/service/application_functions.cpp index 787c88f52d..25a666233f 100644 --- a/src/core/hle/service/am/service/application_functions.cpp +++ b/src/core/hle/service/am/service/application_functions.cpp @@ -4,6 +4,8 @@ // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include + #include "common/settings.h" #include "common/uuid.h" #include "core/file_sys/control_metadata.h" @@ -154,20 +156,7 @@ Result IApplicationFunctions::GetDesiredLanguage(Out out_language_code) { // Default to 0 (all languages supported) u32 supported_languages = 0; - const auto res = [this] { - const FileSys::PatchManager pm{m_applet->program_id, system.GetFileSystemController(), - system.GetContentProvider()}; - auto metadata = pm.GetControlMetadata(); - if (metadata.first != nullptr) { - return metadata; - } - - const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(m_applet->program_id), - system.GetFileSystemController(), - system.GetContentProvider()}; - return pm_update.GetControlMetadata(); - }(); - + const auto res = FileSys::PatchManager::GetMetadataFromBaseOrUpdate(system, m_applet->program_id); if (res.first != nullptr) { supported_languages = res.first->GetSupportedLanguages(); } @@ -205,20 +194,7 @@ Result IApplicationFunctions::SetTerminateResult(Result terminate_result) { Result IApplicationFunctions::GetDisplayVersion(Out out_display_version) { LOG_DEBUG(Service_AM, "called"); - const auto res = [this] { - const FileSys::PatchManager pm{m_applet->program_id, system.GetFileSystemController(), - system.GetContentProvider()}; - auto metadata = pm.GetControlMetadata(); - if (metadata.first != nullptr) { - return metadata; - } - - const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(m_applet->program_id), - system.GetFileSystemController(), - system.GetContentProvider()}; - return pm_update.GetControlMetadata(); - }(); - + const auto res = FileSys::PatchManager::GetMetadataFromBaseOrUpdate(system, m_applet->program_id); if (res.first != nullptr) { const auto& version = res.first->GetVersionString(); std::memcpy(out_display_version->string.data(), version.data(), @@ -347,8 +323,21 @@ Result IApplicationFunctions::NotifyRunning(Out out_became_running) { } Result IApplicationFunctions::GetPseudoDeviceId(Out out_pseudo_device_id) { - LOG_WARNING(Service_AM, "(STUBBED) called"); - *out_pseudo_device_id = {}; + LOG_WARNING(Service_AM, "(stubbed)"); + + // This should be hashed with the device specific hash + // for now this will do + const auto res = FileSys::PatchManager::GetMetadataFromBaseOrUpdate(system, m_applet->program_id); + u8 hash[EVP_MAX_MD_SIZE]; + unsigned int hash_len = 0; + auto const seed = res.first->raw.seed_for_pseudo_device_id; + EVP_MD_CTX *ctx = EVP_MD_CTX_new(); + auto const algorithm = EVP_sha1(); + EVP_DigestInit_ex(ctx, algorithm, nullptr); + EVP_DigestUpdate(ctx, &seed, sizeof(seed)); + EVP_DigestFinal_ex(ctx, hash, &hash_len); + EVP_MD_CTX_free(ctx); + *out_pseudo_device_id = Common::UUID::MakeRFC4122V5(std::span{hash, std::size(hash)}); R_SUCCEED(); } diff --git a/src/core/hle/service/am/service/library_applet_self_accessor.cpp b/src/core/hle/service/am/service/library_applet_self_accessor.cpp index b16bf87979..907be49204 100644 --- a/src/core/hle/service/am/service/library_applet_self_accessor.cpp +++ b/src/core/hle/service/am/service/library_applet_self_accessor.cpp @@ -252,19 +252,7 @@ Result ILibraryAppletSelfAccessor::GetMainAppletApplicationDesiredLanguage( // Default to 0 (all languages supported) u32 supported_languages = 0; - const auto res = [this, identity] { - const FileSys::PatchManager pm{identity.application_id, system.GetFileSystemController(), - system.GetContentProvider()}; - auto metadata = pm.GetControlMetadata(); - if (metadata.first != nullptr) { - return metadata; - } - - const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(identity.application_id), - system.GetFileSystemController(), - system.GetContentProvider()}; - return pm_update.GetControlMetadata(); - }(); + const auto res = FileSys::PatchManager::GetMetadataFromBaseOrUpdate(system, identity.application_id); if (res.first != nullptr) { supported_languages = res.first->GetSupportedLanguages(); diff --git a/src/hid_core/frontend/emulated_console.cpp b/src/hid_core/frontend/emulated_console.cpp index 3807b9e182..92e99a1f54 100644 --- a/src/hid_core/frontend/emulated_console.cpp +++ b/src/hid_core/frontend/emulated_console.cpp @@ -100,6 +100,7 @@ void EmulatedConsole::ReloadInput() { motion.gyro = emulated_motion.GetGyroscope(); motion.rotation = emulated_motion.GetRotations(); motion.orientation = emulated_motion.GetOrientation(); + motion.quaternion = emulated_motion.GetQuaternion(); motion.is_at_rest = !emulated_motion.IsMoving(motion_sensitivity); // Unique index for identifying touch device source