Browse Source

[hle/ns/am] Hijacks PlayerSelect Data to enable player selection and fix structs and returns on ns/am (#3374)

Makes games like Alien Hominid let you skip with only 1 user enabled :)

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3374
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Reviewed-by: DraVee <dravee@eden-emu.dev>
Co-authored-by: Maufeat <sahyno1996@gmail.com>
Co-committed-by: Maufeat <sahyno1996@gmail.com>
lizzie/audio-remove-recursive-lock
Maufeat 2 weeks ago
committed by crueter
parent
commit
f74c590a8e
No known key found for this signature in database GPG Key ID: 425ACD2D4830EBC6
  1. 66
      src/core/hle/service/am/service/library_applet_accessor.cpp
  2. 14
      src/core/hle/service/am/service/library_applet_self_accessor.cpp
  3. 5
      src/core/hle/service/am/service/library_applet_self_accessor.h
  4. 9
      src/core/hle/service/ns/application_manager_interface.cpp
  5. 2
      src/core/hle/service/ns/application_manager_interface.h
  6. 8
      src/core/hle/service/ns/dynamic_rights_interface.cpp
  7. 5
      src/core/hle/service/ns/dynamic_rights_interface.h

66
src/core/hle/service/am/service/library_applet_accessor.cpp

@ -1,18 +1,54 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/settings.h"
#include "core/hle/service/acc/profile_manager.h"
#include "core/hle/service/am/applet_data_broker.h"
#include "core/hle/service/am/applet_manager.h"
#include "core/hle/service/am/frontend/applet_profile_select.h"
#include "core/hle/service/am/frontend/applets.h"
#include "core/hle/service/am/library_applet_storage.h"
#include "core/hle/service/am/service/library_applet_accessor.h"
#include "core/hle/service/am/service/storage.h"
#include "core/hle/service/cmif_serialization.h"
namespace Service::AM {
namespace {
void EnableSingleUserPlay(const std::shared_ptr<LibraryAppletStorage>& impl) {
constexpr s64 DisplayOptionsOffset = 0x90;
constexpr s64 IsSkipEnabledOffset = 1;
constexpr s64 ShowSkipButtonOffset = 4;
constexpr bool enabled = true;
impl->Write(DisplayOptionsOffset + IsSkipEnabledOffset, &enabled, sizeof(enabled));
impl->Write(DisplayOptionsOffset + ShowSkipButtonOffset, &enabled, sizeof(enabled));
}
void ReplaceEmptyUuidWithCurrentUser(const std::shared_ptr<LibraryAppletStorage>& impl) {
Frontend::UiReturnArg return_arg{};
impl->Read(0, &return_arg, sizeof(return_arg));
if (return_arg.uuid_selected.IsValid()) {
return;
}
Service::Account::ProfileManager profile_manager;
const auto current_user_idx = Settings::values.current_user.GetValue();
if (auto uuid = profile_manager.GetUser(current_user_idx)) {
return_arg.result = 0;
return_arg.uuid_selected = *uuid;
impl->Write(0, &return_arg, sizeof(return_arg));
}
}
} // namespace
ILibraryAppletAccessor::ILibraryAppletAccessor(Core::System& system_,
std::shared_ptr<AppletDataBroker> broker,
std::shared_ptr<Applet> applet)
@ -106,19 +142,45 @@ Result ILibraryAppletAccessor::Unknown90() {
Result ILibraryAppletAccessor::PushInData(SharedPointer<IStorage> storage) {
LOG_DEBUG(Service_AM, "called");
// Special case for ProfileSelect applet, to enable single user play as
// somehow some games want an additional user and not let you continue...
if (m_applet->applet_id == AppletId::ProfileSelect) {
auto impl = storage->GetImpl();
const s64 size = impl->GetSize();
const bool is_ui_settings = size == sizeof(Frontend::UiSettings) ||
size == sizeof(Frontend::UiSettingsV1);
if (is_ui_settings) {
EnableSingleUserPlay(impl);
}
}
m_broker->GetInData().Push(storage);
R_SUCCEED();
}
Result ILibraryAppletAccessor::PopOutData(Out<SharedPointer<IStorage>> out_storage) {
LOG_DEBUG(Service_AM, "called");
if (auto caller_applet = m_applet->caller_applet.lock(); caller_applet) {
caller_applet->lifecycle_manager.GetSystemEvent().Signal();
caller_applet->lifecycle_manager.RequestResumeNotification();
caller_applet->lifecycle_manager.GetSystemEvent().Clear();
caller_applet->lifecycle_manager.UpdateRequestedFocusState();
}
R_RETURN(m_broker->GetOutData().Pop(out_storage.Get()));
R_TRY(m_broker->GetOutData().Pop(out_storage.Get()));
if (m_applet->applet_id == AppletId::ProfileSelect && *out_storage) {
auto impl = (*out_storage)->GetImpl();
if (impl->GetSize() == sizeof(Frontend::UiReturnArg)) {
ReplaceEmptyUuidWithCurrentUser(impl);
}
}
R_SUCCEED();
}
Result ILibraryAppletAccessor::PushInteractiveInData(SharedPointer<IStorage> storage) {

14
src/core/hle/service/am/service/library_applet_self_accessor.cpp

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@ -83,7 +83,7 @@ ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_,
{130, nullptr, "GetGpuErrorDetectedSystemEvent"},
{140, nullptr, "SetApplicationMemoryReservation"},
{150, D<&ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually>, "ShouldSetGpuTimeSliceManually"},
{160, D<&ILibraryAppletSelfAccessor::Cmd160>, "Cmd160"},
{160, D<&ILibraryAppletSelfAccessor::GetLibraryAppletInfoEx>, "GetLibraryAppletInfoEx"},
};
// clang-format on
RegisterHandlers(functions);
@ -323,9 +323,13 @@ Result ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually(
R_SUCCEED();
}
Result ILibraryAppletSelfAccessor::Cmd160(Out<u64> out_unknown0) {
LOG_WARNING(Service_AM, "(STUBBED) called");
*out_unknown0 = 0;
Result ILibraryAppletSelfAccessor::GetLibraryAppletInfoEx(
Out<LibraryAppletInfo> out_library_applet_info) {
LOG_INFO(Service_AM, "called");
*out_library_applet_info = {
.applet_id = m_applet->applet_id,
.library_applet_mode = m_applet->library_applet_mode,
};
R_SUCCEED();
}

5
src/core/hle/service/am/service/library_applet_self_accessor.h

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -75,7 +78,7 @@ private:
Result GetMainAppletAvailableUsers(Out<bool> out_can_select_any_user, Out<s32> out_users_count,
OutArray<Common::UUID, BufferAttr_HipcMapAlias> out_users);
Result ShouldSetGpuTimeSliceManually(Out<bool> out_should_set_gpu_time_slice_manually);
Result Cmd160(Out<u64> out_unknown0);
Result GetLibraryAppletInfoEx(Out<LibraryAppletInfo> out_library_applet_info);
const std::shared_ptr<Applet> m_applet;
const std::shared_ptr<AppletDataBroker> m_broker;

9
src/core/hle/service/ns/application_manager_interface.cpp

@ -361,7 +361,7 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
{2517, nullptr, "CreateApplicationInstance"},
{2518, nullptr, "UpdateQualificationForDebug"},
{2519, nullptr, "IsQualificationTransitionSupported"},
{2520, nullptr, "IsQualificationTransitionSupportedByProcessId"},
{2520, D<&IApplicationManagerInterface::IsQualificationTransitionSupportedByProcessId>, "IsQualificationTransitionSupportedByProcessId"},
{2521, nullptr, "GetRightsUserChangedEvent"},
{2522, nullptr, "IsRomRedirectionAvailable"},
{2523, nullptr, "GetProgramId"}, //17.0.0+
@ -769,6 +769,13 @@ Result IApplicationManagerInterface::ResumeAll() {
R_SUCCEED();
}
Result IApplicationManagerInterface::IsQualificationTransitionSupportedByProcessId(
Out<bool> out_is_supported, u64 process_id) {
LOG_WARNING(Service_NS, "(STUBBED) called, process_id={}", process_id);
*out_is_supported = true;
R_SUCCEED();
}
Result IApplicationManagerInterface::GetStorageSize(Out<s64> out_total_space_size,
Out<s64> out_free_space_size,
FileSys::StorageId storage_id) {

2
src/core/hle/service/ns/application_manager_interface.h

@ -53,6 +53,8 @@ public:
Result GetFreeSpaceSize(Out<s64> out_free_space_size, FileSys::StorageId storage_id);
Result GetGameCardUpdateDetectionEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
Result ResumeAll();
Result IsQualificationTransitionSupportedByProcessId(Out<bool> out_is_supported,
u64 process_id);
Result GetStorageSize(Out<s64> out_total_space_size, Out<s64> out_free_space_size,
FileSys::StorageId storage_id);
Result TouchApplication(u64 application_id);

8
src/core/hle/service/ns/dynamic_rights_interface.cpp

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@ -68,9 +68,9 @@ Result IDynamicRightsInterface::VerifyActivatedRightsOwners(u64 rights_handle) {
}
Result IDynamicRightsInterface::HasAccountRestrictedRightsInRunningApplications(
Out<u32> out_status, u64 rights_handle) {
LOG_WARNING(Service_NS, "(STUBBED) called, rights_handle={:#x}", rights_handle);
*out_status = 0;
Out<bool> out_is_restricted) {
LOG_WARNING(Service_NS, "(STUBBED) called");
*out_is_restricted = 0;
R_SUCCEED();
}

5
src/core/hle/service/ns/dynamic_rights_interface.h

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@ -20,8 +20,7 @@ private:
Result NotifyApplicationRightsCheckStart();
Result GetRunningApplicationStatus(Out<u32> out_status, u64 rights_handle);
Result VerifyActivatedRightsOwners(u64 rights_handle);
Result HasAccountRestrictedRightsInRunningApplications(Out<u32> out_status,
u64 rights_handle);
Result HasAccountRestrictedRightsInRunningApplications(Out<bool> out_is_restricted);
};
} // namespace Service::NS
Loading…
Cancel
Save