Compare commits
3 Commits
dmnt2
...
dynarm7345
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0490529a01 | ||
|
|
c7a7fe15e5 | ||
|
|
1d869e8495 |
@@ -6,15 +6,10 @@
|
||||
|
||||
package org.yuzu.yuzu_emu.adapters
|
||||
|
||||
import android.view.Gravity
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.constraintlayout.widget.ConstraintLayout
|
||||
import org.yuzu.yuzu_emu.R
|
||||
import org.yuzu.yuzu_emu.databinding.ListItemAddonBinding
|
||||
import org.yuzu.yuzu_emu.model.Patch
|
||||
import org.yuzu.yuzu_emu.model.PatchType
|
||||
import org.yuzu.yuzu_emu.model.AddonViewModel
|
||||
import org.yuzu.yuzu_emu.viewholder.AbstractViewHolder
|
||||
|
||||
@@ -32,95 +27,18 @@ class AddonAdapter(val addonViewModel: AddonViewModel) :
|
||||
binding.addonSwitch.performClick()
|
||||
}
|
||||
binding.title.text = model.name
|
||||
|
||||
binding.addonSwitch.setOnCheckedChangeListener(null)
|
||||
binding.version.text = model.version
|
||||
binding.addonSwitch.isChecked = model.enabled
|
||||
|
||||
binding.addonSwitch.setOnCheckedChangeListener { _, checked ->
|
||||
model.enabled = checked
|
||||
}
|
||||
|
||||
val isCheat = model.isCheat()
|
||||
val indentPx = if (isCheat) {
|
||||
binding.root.context.resources.getDimensionPixelSize(R.dimen.spacing_large)
|
||||
} else {
|
||||
0
|
||||
}
|
||||
(binding.addonCard.layoutParams as? ViewGroup.MarginLayoutParams)?.let {
|
||||
it.marginStart = indentPx
|
||||
binding.addonCard.layoutParams = it
|
||||
}
|
||||
|
||||
if (isCheat) {
|
||||
binding.version.visibility = View.GONE
|
||||
binding.deleteCard.visibility = View.GONE
|
||||
binding.buttonDelete.visibility = View.GONE
|
||||
|
||||
binding.addonSwitch.scaleX = 0.7f
|
||||
binding.addonSwitch.scaleY = 0.7f
|
||||
|
||||
val compactPaddingVertical = binding.root.context.resources.getDimensionPixelSize(R.dimen.spacing_small)
|
||||
binding.root.setPadding(
|
||||
binding.root.paddingLeft,
|
||||
compactPaddingVertical / 2,
|
||||
binding.root.paddingRight,
|
||||
compactPaddingVertical / 2
|
||||
)
|
||||
|
||||
val innerLayout = binding.addonCard.getChildAt(0) as? ViewGroup
|
||||
innerLayout?.let {
|
||||
val leftPadding = binding.root.context.resources.getDimensionPixelSize(R.dimen.spacing_large)
|
||||
val smallPadding = binding.root.context.resources.getDimensionPixelSize(R.dimen.spacing_med)
|
||||
it.setPadding(leftPadding, smallPadding, smallPadding, smallPadding)
|
||||
}
|
||||
|
||||
binding.title.textSize = 14f
|
||||
binding.title.gravity = Gravity.CENTER_VERTICAL
|
||||
|
||||
(binding.title.layoutParams as? ConstraintLayout.LayoutParams)?.let { params ->
|
||||
params.topToTop = ConstraintLayout.LayoutParams.PARENT_ID
|
||||
params.bottomToBottom = ConstraintLayout.LayoutParams.PARENT_ID
|
||||
params.topMargin = 0
|
||||
binding.title.layoutParams = params
|
||||
}
|
||||
} else {
|
||||
binding.version.visibility = View.VISIBLE
|
||||
binding.version.text = model.version
|
||||
binding.deleteCard.visibility = View.VISIBLE
|
||||
binding.buttonDelete.visibility = View.VISIBLE
|
||||
|
||||
binding.addonSwitch.scaleX = 1.0f
|
||||
binding.addonSwitch.scaleY = 1.0f
|
||||
|
||||
val normalPadding = binding.root.context.resources.getDimensionPixelSize(R.dimen.spacing_med)
|
||||
binding.root.setPadding(
|
||||
binding.root.paddingLeft,
|
||||
normalPadding,
|
||||
binding.root.paddingRight,
|
||||
normalPadding
|
||||
)
|
||||
|
||||
val innerLayout = binding.addonCard.getChildAt(0) as? ViewGroup
|
||||
innerLayout?.let {
|
||||
val normalInnerPadding = binding.root.context.resources.getDimensionPixelSize(R.dimen.spacing_medlarge)
|
||||
it.setPadding(normalInnerPadding, normalInnerPadding, normalInnerPadding, normalInnerPadding)
|
||||
}
|
||||
|
||||
binding.title.textSize = 16f
|
||||
binding.title.gravity = Gravity.START
|
||||
|
||||
(binding.title.layoutParams as? ConstraintLayout.LayoutParams)?.let { params ->
|
||||
params.topToTop = ConstraintLayout.LayoutParams.PARENT_ID
|
||||
params.bottomToBottom = ConstraintLayout.LayoutParams.UNSET
|
||||
params.topMargin = 0
|
||||
binding.title.layoutParams = params
|
||||
}
|
||||
|
||||
val deleteAction = {
|
||||
addonViewModel.setAddonToDelete(model)
|
||||
}
|
||||
binding.deleteCard.setOnClickListener { deleteAction() }
|
||||
binding.buttonDelete.setOnClickListener { deleteAction() }
|
||||
val deleteAction = {
|
||||
addonViewModel.setAddonToDelete(model)
|
||||
}
|
||||
binding.deleteCard.setOnClickListener { deleteAction() }
|
||||
binding.buttonDelete.setOnClickListener { deleteAction() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-FileCopyrightText: 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
package org.yuzu.yuzu_emu.fragments
|
||||
@@ -73,7 +73,7 @@ class AddonsFragment : Fragment() {
|
||||
}
|
||||
|
||||
addonViewModel.addonList.collect(viewLifecycleOwner) {
|
||||
(binding.listAddons.adapter as AddonAdapter).submitList(it.toList())
|
||||
(binding.listAddons.adapter as AddonAdapter).submitList(it)
|
||||
}
|
||||
addonViewModel.showModInstallPicker.collect(
|
||||
viewLifecycleOwner,
|
||||
@@ -127,9 +127,7 @@ class AddonsFragment : Fragment() {
|
||||
|
||||
override fun onDestroy() {
|
||||
super.onDestroy()
|
||||
if (!requireActivity().isChangingConfigurations) {
|
||||
addonViewModel.onCloseAddons()
|
||||
}
|
||||
addonViewModel.onCloseAddons()
|
||||
}
|
||||
|
||||
val installAddon =
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -31,14 +28,10 @@ class AddonViewModel : ViewModel() {
|
||||
val addonToDelete = _addonToDelete.asStateFlow()
|
||||
|
||||
var game: Game? = null
|
||||
private set
|
||||
|
||||
private val isRefreshing = AtomicBoolean(false)
|
||||
|
||||
fun onOpenAddons(game: Game) {
|
||||
if (this.game?.programId == game.programId && _patchList.value.isNotEmpty()) {
|
||||
return
|
||||
}
|
||||
this.game = game
|
||||
refreshAddons()
|
||||
}
|
||||
@@ -54,7 +47,8 @@ class AddonViewModel : ViewModel() {
|
||||
NativeLibrary.getPatchesForFile(game!!.path, game!!.programId)
|
||||
?: emptyArray()
|
||||
).toMutableList()
|
||||
_patchList.value = sortPatchesWithCheatsGrouped(patchList)
|
||||
patchList.sortBy { it.name }
|
||||
_patchList.value = patchList
|
||||
isRefreshing.set(false)
|
||||
}
|
||||
}
|
||||
@@ -69,9 +63,7 @@ class AddonViewModel : ViewModel() {
|
||||
PatchType.Update -> NativeLibrary.removeUpdate(patch.programId)
|
||||
PatchType.DLC -> NativeLibrary.removeDLC(patch.programId)
|
||||
PatchType.Mod -> NativeLibrary.removeMod(patch.programId, patch.name)
|
||||
PatchType.Cheat -> {}
|
||||
}
|
||||
_patchList.value.clear()
|
||||
refreshAddons()
|
||||
}
|
||||
|
||||
@@ -86,7 +78,7 @@ class AddonViewModel : ViewModel() {
|
||||
if (it.enabled) {
|
||||
null
|
||||
} else {
|
||||
it.getStorageKey()
|
||||
it.name
|
||||
}
|
||||
}.toTypedArray()
|
||||
)
|
||||
@@ -102,28 +94,4 @@ class AddonViewModel : ViewModel() {
|
||||
fun showModNoticeDialog(show: Boolean) {
|
||||
_showModNoticeDialog.value = show
|
||||
}
|
||||
|
||||
private fun sortPatchesWithCheatsGrouped(patches: MutableList<Patch>): MutableList<Patch> {
|
||||
val individualCheats = patches.filter { it.isCheat() }
|
||||
val nonCheats = patches.filter { !it.isCheat() }.sortedBy { it.name }
|
||||
|
||||
val cheatsByParent = individualCheats.groupBy { it.parentName }
|
||||
|
||||
val result = mutableListOf<Patch>()
|
||||
for (patch in nonCheats) {
|
||||
result.add(patch)
|
||||
cheatsByParent[patch.name]?.sortedBy { it.name }?.let { childCheats ->
|
||||
result.addAll(childCheats)
|
||||
}
|
||||
}
|
||||
|
||||
val knownParents = nonCheats.map { it.name }.toSet()
|
||||
for ((parentName, orphanCheats) in cheatsByParent) {
|
||||
if (parentName !in knownParents) {
|
||||
result.addAll(orphanCheats.sortedBy { it.name })
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2023 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -15,24 +12,5 @@ data class Patch(
|
||||
val version: String,
|
||||
val type: Int,
|
||||
val programId: String,
|
||||
val titleId: String,
|
||||
val parentName: String = "" // For cheats: name of the mod folder containing them
|
||||
) {
|
||||
/**
|
||||
* Returns the storage key used for saving enabled/disabled state.
|
||||
* For cheats with a parent, returns "ParentName::CheatName".
|
||||
*/
|
||||
fun getStorageKey(): String {
|
||||
return if (parentName.isNotEmpty()) {
|
||||
"$parentName::$name"
|
||||
} else {
|
||||
name
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if this patch is an individual cheat entry (not a cheat mod).
|
||||
* Individual cheats have type=Cheat and a parent mod name.
|
||||
*/
|
||||
fun isCheat(): Boolean = type == PatchType.Cheat.int && parentName.isNotEmpty()
|
||||
}
|
||||
val titleId: String
|
||||
)
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
@@ -9,8 +6,7 @@ package org.yuzu.yuzu_emu.model
|
||||
enum class PatchType(val int: Int) {
|
||||
Update(0),
|
||||
DLC(1),
|
||||
Mod(2),
|
||||
Cheat(3);
|
||||
Mod(2);
|
||||
|
||||
companion object {
|
||||
fun from(int: Int): PatchType = entries.firstOrNull { it.int == int } ?: Update
|
||||
|
||||
@@ -1298,10 +1298,7 @@ jobjectArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPatchesForFile(JNIEnv* env
|
||||
FileSys::VirtualFile update_raw;
|
||||
loader->ReadUpdateRaw(update_raw);
|
||||
|
||||
// Get build ID for individual cheat enumeration
|
||||
const auto build_id = pm.GetBuildID(update_raw);
|
||||
|
||||
auto patches = pm.GetPatches(update_raw, build_id);
|
||||
auto patches = pm.GetPatches(update_raw);
|
||||
jobjectArray jpatchArray =
|
||||
env->NewObjectArray(patches.size(), Common::Android::GetPatchClass(), nullptr);
|
||||
int i = 0;
|
||||
@@ -1311,8 +1308,7 @@ jobjectArray Java_org_yuzu_yuzu_1emu_NativeLibrary_getPatchesForFile(JNIEnv* env
|
||||
Common::Android::ToJString(env, patch.name),
|
||||
Common::Android::ToJString(env, patch.version), static_cast<jint>(patch.type),
|
||||
Common::Android::ToJString(env, std::to_string(patch.program_id)),
|
||||
Common::Android::ToJString(env, std::to_string(patch.title_id)),
|
||||
Common::Android::ToJString(env, patch.parent_name));
|
||||
Common::Android::ToJString(env, std::to_string(patch.title_id)));
|
||||
env->SetObjectArrayElement(jpatchArray, i, jpatch);
|
||||
++i;
|
||||
}
|
||||
|
||||
@@ -515,7 +515,7 @@ namespace Common::Android {
|
||||
s_patch_class = reinterpret_cast<jclass>(env->NewGlobalRef(patch_class));
|
||||
s_patch_constructor = env->GetMethodID(
|
||||
patch_class, "<init>",
|
||||
"(ZLjava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;Ljava/lang/String;)V");
|
||||
"(ZLjava/lang/String;Ljava/lang/String;ILjava/lang/String;Ljava/lang/String;)V");
|
||||
s_patch_enabled_field = env->GetFieldID(patch_class, "enabled", "Z");
|
||||
s_patch_name_field = env->GetFieldID(patch_class, "name", "Ljava/lang/String;");
|
||||
s_patch_version_field = env->GetFieldID(patch_class, "version", "Ljava/lang/String;");
|
||||
|
||||
@@ -611,18 +611,6 @@ add_library(core STATIC
|
||||
hle/service/caps/caps_u.h
|
||||
hle/service/cmif_serialization.h
|
||||
hle/service/cmif_types.h
|
||||
hle/service/dmnt/cheat_interface.cpp
|
||||
hle/service/dmnt/cheat_interface.h
|
||||
hle/service/dmnt/cheat_parser.cpp
|
||||
hle/service/dmnt/cheat_parser.h
|
||||
hle/service/dmnt/cheat_process_manager.cpp
|
||||
hle/service/dmnt/cheat_process_manager.h
|
||||
hle/service/dmnt/cheat_virtual_machine.cpp
|
||||
hle/service/dmnt/cheat_virtual_machine.h
|
||||
hle/service/dmnt/dmnt.cpp
|
||||
hle/service/dmnt/dmnt.h
|
||||
hle/service/dmnt/dmnt_results.h
|
||||
hle/service/dmnt/dmnt_types.h
|
||||
hle/service/erpt/erpt.cpp
|
||||
hle/service/erpt/erpt.h
|
||||
hle/service/es/es.cpp
|
||||
@@ -1157,6 +1145,11 @@ add_library(core STATIC
|
||||
loader/xci.h
|
||||
memory.cpp
|
||||
memory.h
|
||||
memory/cheat_engine.cpp
|
||||
memory/cheat_engine.h
|
||||
memory/dmnt_cheat_types.h
|
||||
memory/dmnt_cheat_vm.cpp
|
||||
memory/dmnt_cheat_vm.h
|
||||
perf_stats.cpp
|
||||
perf_stats.h
|
||||
reporter.cpp
|
||||
|
||||
@@ -52,12 +52,12 @@
|
||||
#include "core/internal_network/network.h"
|
||||
#include "core/loader/loader.h"
|
||||
#include "core/memory.h"
|
||||
#include "core/memory/cheat_engine.h"
|
||||
#include "core/perf_stats.h"
|
||||
#include "core/reporter.h"
|
||||
#include "core/tools/freezer.h"
|
||||
#include "core/tools/renderdoc.h"
|
||||
#include "hid_core/hid_core.h"
|
||||
#include "hle/service/dmnt/cheat_process_manager.h"
|
||||
#include "network/network.h"
|
||||
#include "video_core/host1x/host1x.h"
|
||||
#include "video_core/renderer_base.h"
|
||||
@@ -277,18 +277,9 @@ struct System::Impl {
|
||||
audio_core = std::make_unique<AudioCore::AudioCore>(system);
|
||||
|
||||
service_manager = std::make_shared<Service::SM::ServiceManager>(kernel);
|
||||
|
||||
// Create cheat_manager BEFORE services, as DMNT::LoopProcess needs it
|
||||
cheat_manager = std::make_unique<Service::DMNT::CheatProcessManager>(system);
|
||||
|
||||
services =
|
||||
std::make_unique<Service::Services>(service_manager, system, stop_event.get_token());
|
||||
|
||||
// Apply any pending cheats that were registered before cheat_manager was initialized
|
||||
if (pending_cheats.has_pending) {
|
||||
ApplyPendingCheats(system);
|
||||
}
|
||||
|
||||
is_powered_on = true;
|
||||
exit_locked = false;
|
||||
exit_requested = false;
|
||||
@@ -352,6 +343,11 @@ struct System::Impl {
|
||||
return init_result;
|
||||
}
|
||||
|
||||
// Initialize cheat engine
|
||||
if (cheat_engine) {
|
||||
cheat_engine->Initialize();
|
||||
}
|
||||
|
||||
// Register with applet manager
|
||||
// All threads are started, begin main process execution, now that we're in the clear
|
||||
applet_manager.CreateAndInsertByFrontendAppletParameters(std::move(process), params);
|
||||
@@ -419,6 +415,7 @@ struct System::Impl {
|
||||
services.reset();
|
||||
service_manager.reset();
|
||||
fs_controller.Reset();
|
||||
cheat_engine.reset();
|
||||
core_timing.ClearPendingEvents();
|
||||
app_loader.reset();
|
||||
audio_core.reset();
|
||||
@@ -494,6 +491,7 @@ struct System::Impl {
|
||||
bool nvdec_active{};
|
||||
|
||||
Reporter reporter;
|
||||
std::unique_ptr<Memory::CheatEngine> cheat_engine;
|
||||
std::unique_ptr<Tools::Freezer> memory_freezer;
|
||||
std::array<u8, 0x20> build_id{};
|
||||
|
||||
@@ -522,18 +520,6 @@ struct System::Impl {
|
||||
/// Debugger
|
||||
std::unique_ptr<Core::Debugger> debugger;
|
||||
|
||||
/// Cheat Manager (DMNT)
|
||||
std::unique_ptr<Service::DMNT::CheatProcessManager> cheat_manager;
|
||||
|
||||
/// Pending cheats to register after cheat_manager is initialized
|
||||
struct PendingCheats {
|
||||
std::vector<Service::DMNT::CheatEntry> list;
|
||||
std::array<u8, 32> build_id{};
|
||||
u64 main_region_begin{};
|
||||
u64 main_region_size{};
|
||||
bool has_pending{false};
|
||||
} pending_cheats;
|
||||
|
||||
SystemResultStatus status = SystemResultStatus::Success;
|
||||
std::string status_details = "";
|
||||
|
||||
@@ -569,61 +555,6 @@ struct System::Impl {
|
||||
general_channel_event = std::make_unique<Service::Event>(*general_channel_context);
|
||||
general_channel_initialized = true;
|
||||
}
|
||||
|
||||
void ApplyPendingCheats(System& system) {
|
||||
if (!pending_cheats.has_pending || !cheat_manager) {
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_DEBUG(Core, "Applying {} pending cheats", pending_cheats.list.size());
|
||||
|
||||
const auto result = cheat_manager->AttachToApplicationProcess(
|
||||
pending_cheats.build_id, pending_cheats.main_region_begin,
|
||||
pending_cheats.main_region_size);
|
||||
|
||||
if (result.IsError()) {
|
||||
LOG_WARNING(Core, "Failed to attach cheat process: result={}", result.raw);
|
||||
pending_cheats = {};
|
||||
return;
|
||||
}
|
||||
|
||||
LOG_DEBUG(Core, "Cheat process attached successfully");
|
||||
|
||||
for (const auto& entry : pending_cheats.list) {
|
||||
if (entry.cheat_id == 0 && entry.definition.num_opcodes != 0) {
|
||||
LOG_DEBUG(Core, "Setting master cheat '{}' with {} opcodes",
|
||||
entry.definition.readable_name.data(), entry.definition.num_opcodes);
|
||||
const auto set_result = cheat_manager->SetMasterCheat(entry.definition);
|
||||
if (set_result.IsError()) {
|
||||
LOG_WARNING(Core, "Failed to set master cheat: result={}", set_result.raw);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Add normal cheats (cheat_id != 0)
|
||||
for (const auto& entry : pending_cheats.list) {
|
||||
if (entry.cheat_id == 0 || entry.definition.num_opcodes == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
u32 assigned_id = 0;
|
||||
LOG_DEBUG(Core, "Adding cheat '{}' (enabled={}, {} opcodes)",
|
||||
entry.definition.readable_name.data(), entry.enabled,
|
||||
entry.definition.num_opcodes);
|
||||
const auto add_result = cheat_manager->AddCheat(assigned_id, entry.enabled,
|
||||
entry.definition);
|
||||
if (add_result.IsError()) {
|
||||
LOG_WARNING(Core,
|
||||
"Failed to add cheat (original_id={} enabled={} name='{}'): result={}",
|
||||
entry.cheat_id, entry.enabled,
|
||||
entry.definition.readable_name.data(), add_result.raw);
|
||||
}
|
||||
}
|
||||
|
||||
// Clear pending cheats
|
||||
pending_cheats = {};
|
||||
}
|
||||
};
|
||||
|
||||
System::System() : impl{std::make_unique<Impl>(*this)} {}
|
||||
@@ -869,61 +800,11 @@ FileSys::VirtualFilesystem System::GetFilesystem() const {
|
||||
return impl->virtual_filesystem;
|
||||
}
|
||||
|
||||
void System::RegisterCheatList(const std::vector<Service::DMNT::CheatEntry>& list,
|
||||
void System::RegisterCheatList(const std::vector<Memory::CheatEntry>& list,
|
||||
const std::array<u8, 32>& build_id, u64 main_region_begin,
|
||||
u64 main_region_size) {
|
||||
// If cheat_manager is not yet initialized, cache the cheats for later
|
||||
if (!impl->cheat_manager) {
|
||||
impl->pending_cheats.list = list;
|
||||
impl->pending_cheats.build_id = build_id;
|
||||
impl->pending_cheats.main_region_begin = main_region_begin;
|
||||
impl->pending_cheats.main_region_size = main_region_size;
|
||||
impl->pending_cheats.has_pending = true;
|
||||
LOG_INFO(Core, "Cached {} cheats for later registration", list.size());
|
||||
return;
|
||||
}
|
||||
|
||||
// Attach cheat process to the current application process
|
||||
const auto result = impl->cheat_manager->AttachToApplicationProcess(build_id, main_region_begin,
|
||||
main_region_size);
|
||||
if (result.IsError()) {
|
||||
LOG_WARNING(Core, "Failed to attach cheat process: result={}", result.raw);
|
||||
return;
|
||||
}
|
||||
|
||||
// Empty list: nothing more to do
|
||||
if (list.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Set master cheat if present (cheat_id == 0)
|
||||
for (const auto& entry : list) {
|
||||
if (entry.cheat_id == 0 && entry.definition.num_opcodes != 0) {
|
||||
const auto set_result = impl->cheat_manager->SetMasterCheat(entry.definition);
|
||||
if (set_result.IsError()) {
|
||||
LOG_WARNING(Core, "Failed to set master cheat: result={}", set_result.raw);
|
||||
}
|
||||
// Only one master cheat allowed
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Add normal cheats (cheat_id != 0)
|
||||
for (const auto& entry : list) {
|
||||
if (entry.cheat_id == 0 || entry.definition.num_opcodes == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
u32 assigned_id = 0;
|
||||
const auto add_result = impl->cheat_manager->AddCheat(assigned_id, entry.enabled,
|
||||
entry.definition);
|
||||
if (add_result.IsError()) {
|
||||
LOG_WARNING(Core,
|
||||
"Failed to add cheat (original_id={} enabled={} name='{}'): result={}",
|
||||
entry.cheat_id, entry.enabled,
|
||||
entry.definition.readable_name.data(), add_result.raw);
|
||||
}
|
||||
}
|
||||
impl->cheat_engine = std::make_unique<Memory::CheatEngine>(*this, list, build_id);
|
||||
impl->cheat_engine->SetMainMemoryParameters(main_region_begin, main_region_size);
|
||||
}
|
||||
|
||||
void System::SetFrontendAppletSet(Service::AM::Frontend::FrontendAppletSet&& set) {
|
||||
@@ -1067,15 +948,6 @@ Tools::RenderdocAPI& System::GetRenderdocAPI() {
|
||||
return *impl->renderdoc_api;
|
||||
}
|
||||
|
||||
Service::DMNT::CheatProcessManager& System::GetCheatManager()
|
||||
{
|
||||
return *impl->cheat_manager;
|
||||
}
|
||||
|
||||
const Service::DMNT::CheatProcessManager& System::GetCheatManager() const {
|
||||
return *impl->cheat_manager;
|
||||
}
|
||||
|
||||
void System::RunServer(std::unique_ptr<Service::ServerManager>&& server_manager) {
|
||||
return impl->kernel.RunServer(std::move(server_manager));
|
||||
}
|
||||
|
||||
@@ -17,7 +17,6 @@
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/file_sys/vfs/vfs_types.h"
|
||||
#include "core/hle/service/dmnt/dmnt_types.h"
|
||||
#include "core/hle/service/os/event.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
|
||||
@@ -46,14 +45,10 @@ enum class ResultStatus : u16;
|
||||
} // namespace Loader
|
||||
|
||||
namespace Core::Memory {
|
||||
struct CheatEntry;
|
||||
class Memory;
|
||||
} // namespace Core::Memory
|
||||
|
||||
namespace Service::DMNT {
|
||||
class CheatProcessManager;
|
||||
struct CheatEntry;
|
||||
}
|
||||
|
||||
namespace Service {
|
||||
|
||||
namespace Account {
|
||||
@@ -344,7 +339,7 @@ public:
|
||||
|
||||
[[nodiscard]] FileSys::VirtualFilesystem GetFilesystem() const;
|
||||
|
||||
void RegisterCheatList(const std::vector<Service::DMNT::CheatEntry>& list,
|
||||
void RegisterCheatList(const std::vector<Memory::CheatEntry>& list,
|
||||
const std::array<u8, 0x20>& build_id, u64 main_region_begin,
|
||||
u64 main_region_size);
|
||||
|
||||
@@ -388,9 +383,6 @@ public:
|
||||
|
||||
[[nodiscard]] Tools::RenderdocAPI& GetRenderdocAPI();
|
||||
|
||||
[[nodiscard]] Service::DMNT::CheatProcessManager& GetCheatManager();
|
||||
[[nodiscard]] const Service::DMNT::CheatProcessManager& GetCheatManager() const;
|
||||
|
||||
void SetExitLocked(bool locked);
|
||||
bool GetExitLocked() const;
|
||||
|
||||
|
||||
@@ -27,13 +27,12 @@
|
||||
#include "core/file_sys/vfs/vfs_cached.h"
|
||||
#include "core/file_sys/vfs/vfs_layered.h"
|
||||
#include "core/file_sys/vfs/vfs_vector.h"
|
||||
#include "core/hle/service/dmnt/cheat_parser.h"
|
||||
#include "core/hle/service/dmnt/dmnt_types.h"
|
||||
#include "core/hle/service/filesystem/filesystem.h"
|
||||
#include "core/hle/service/ns/language.h"
|
||||
#include "core/hle/service/set/settings_server.h"
|
||||
#include "core/loader/loader.h"
|
||||
#include "core/loader/nso.h"
|
||||
#include "core/memory/cheat_engine.h"
|
||||
|
||||
namespace FileSys {
|
||||
namespace {
|
||||
@@ -65,15 +64,16 @@ std::string FormatTitleVersion(u32 version,
|
||||
return fmt::format("v{}.{}.{}", bytes[3], bytes[2], bytes[1]);
|
||||
}
|
||||
|
||||
// Returns a directory with name matching case-insensitively.
|
||||
// Returns nullptr if directory doesn't contain a subdirectory with the given name.
|
||||
VirtualDir FindSubdirectoryCaseless(const VirtualDir& dir, std::string_view name) {
|
||||
// Returns a directory with name matching name case-insensitive. Returns nullptr if directory
|
||||
// doesn't have a directory with name.
|
||||
VirtualDir FindSubdirectoryCaseless(const VirtualDir dir, std::string_view name) {
|
||||
#ifdef _WIN32
|
||||
return dir->GetSubdirectory(name);
|
||||
#else
|
||||
const auto target = Common::ToLower(std::string(name));
|
||||
for (const auto& subdir : dir->GetSubdirectories()) {
|
||||
if (Common::ToLower(subdir->GetName()) == target) {
|
||||
const auto subdirs = dir->GetSubdirectories();
|
||||
for (const auto& subdir : subdirs) {
|
||||
std::string dir_name = Common::ToLower(subdir->GetName());
|
||||
if (dir_name == name) {
|
||||
return subdir;
|
||||
}
|
||||
}
|
||||
@@ -82,35 +82,36 @@ VirtualDir FindSubdirectoryCaseless(const VirtualDir& dir, std::string_view name
|
||||
#endif
|
||||
}
|
||||
|
||||
std::optional<std::vector<Service::DMNT::CheatEntry>> ReadCheatFileFromFolder(
|
||||
std::optional<std::vector<Core::Memory::CheatEntry>> ReadCheatFileFromFolder(
|
||||
u64 title_id, const PatchManager::BuildID& build_id_, const VirtualDir& base_path, bool upper) {
|
||||
|
||||
const auto build_id_raw = Common::HexToString(build_id_, upper);
|
||||
const auto build_id = build_id_raw.substr(0, std::min(build_id_raw.size(), sizeof(u64) * 2));
|
||||
const auto build_id = build_id_raw.substr(0, sizeof(u64) * 2);
|
||||
const auto file = base_path->GetFile(fmt::format("{}.txt", build_id));
|
||||
|
||||
if (file == nullptr) {
|
||||
LOG_DEBUG(Common_Filesystem, "No cheats file found for title_id={:016X}, build_id={}",
|
||||
title_id, build_id);
|
||||
LOG_INFO(Common_Filesystem, "No cheats file found for title_id={:016X}, build_id={}",
|
||||
title_id, build_id);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
std::vector<u8> data(file->GetSize());
|
||||
if (file->Read(data.data(), data.size()) != data.size()) {
|
||||
LOG_WARNING(Common_Filesystem, "Failed to read cheats file for title_id={:016X}, build_id={}",
|
||||
title_id, build_id);
|
||||
LOG_INFO(Common_Filesystem, "Failed to read cheats file for title_id={:016X}, build_id={}",
|
||||
title_id, build_id);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
const Service::DMNT::CheatParser parser;
|
||||
const Core::Memory::TextCheatParser parser;
|
||||
return parser.Parse(std::string_view(reinterpret_cast<const char*>(data.data()), data.size()));
|
||||
}
|
||||
|
||||
void AppendCommaIfNotEmpty(std::string& to, std::string_view with) {
|
||||
if (!to.empty()) {
|
||||
if (to.empty()) {
|
||||
to += with;
|
||||
} else {
|
||||
to += ", ";
|
||||
to += with;
|
||||
}
|
||||
to += with;
|
||||
}
|
||||
|
||||
bool IsDirValidAndNonEmpty(const VirtualDir& dir) {
|
||||
@@ -315,7 +316,7 @@ bool PatchManager::HasNSOPatch(const BuildID& build_id_, std::string_view name)
|
||||
return !CollectPatches(patch_dirs, build_id).empty();
|
||||
}
|
||||
|
||||
std::vector<Service::DMNT::CheatEntry> PatchManager::CreateCheatList(const BuildID& build_id_) const {
|
||||
std::vector<Core::Memory::CheatEntry> PatchManager::CreateCheatList(const BuildID& build_id_) const {
|
||||
const auto load_dir = fs_controller.GetModificationLoadRoot(title_id);
|
||||
if (load_dir == nullptr) {
|
||||
LOG_ERROR(Loader, "Cannot load mods for invalid title_id={:016X}", title_id);
|
||||
@@ -324,71 +325,36 @@ std::vector<Service::DMNT::CheatEntry> PatchManager::CreateCheatList(const Build
|
||||
|
||||
const auto& disabled = Settings::values.disabled_addons[title_id];
|
||||
auto patch_dirs = load_dir->GetSubdirectories();
|
||||
std::sort(patch_dirs.begin(), patch_dirs.end(),
|
||||
[](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); });
|
||||
std::sort(patch_dirs.begin(), patch_dirs.end(), [](auto const& l, auto const& r) { return l->GetName() < r->GetName(); });
|
||||
|
||||
std::vector<Service::DMNT::CheatEntry> out;
|
||||
|
||||
// Load cheats from: <mod dir>/<folder>/cheats/<build_id>.txt
|
||||
// <mod dir> / <folder> / cheats / <build id>.txt
|
||||
std::vector<Core::Memory::CheatEntry> out;
|
||||
for (const auto& subdir : patch_dirs) {
|
||||
const auto mod_name = subdir->GetName();
|
||||
|
||||
// Skip entirely disabled mods
|
||||
if (std::find(disabled.cbegin(), disabled.cend(), mod_name) != disabled.cend()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
auto cheats_dir = FindSubdirectoryCaseless(subdir, "cheats");
|
||||
if (cheats_dir == nullptr) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Try uppercase build_id first, then lowercase
|
||||
std::optional<std::vector<Service::DMNT::CheatEntry>> cheat_entries;
|
||||
if (auto res = ReadCheatFileFromFolder(title_id, build_id_, cheats_dir, true)) {
|
||||
cheat_entries = std::move(res);
|
||||
} else if (auto res_lower = ReadCheatFileFromFolder(title_id, build_id_, cheats_dir, false)) {
|
||||
cheat_entries = std::move(res_lower);
|
||||
}
|
||||
|
||||
if (cheat_entries) {
|
||||
for (auto& entry : *cheat_entries) {
|
||||
// Check if this individual cheat is disabled
|
||||
const std::string cheat_name = entry.definition.readable_name.data();
|
||||
const std::string cheat_key = mod_name + "::" + cheat_name;
|
||||
|
||||
if (std::find(disabled.cbegin(), disabled.cend(), cheat_key) != disabled.cend()) {
|
||||
// Individual cheat is disabled - mark it as disabled but still include it
|
||||
entry.enabled = false;
|
||||
}
|
||||
|
||||
out.push_back(entry);
|
||||
if (std::find(disabled.cbegin(), disabled.cend(), subdir->GetName()) == disabled.cend()) {
|
||||
if (auto cheats_dir = FindSubdirectoryCaseless(subdir, "cheats"); cheats_dir != nullptr) {
|
||||
if (auto const res = ReadCheatFileFromFolder(title_id, build_id_, cheats_dir, true))
|
||||
std::copy(res->begin(), res->end(), std::back_inserter(out));
|
||||
if (auto const res = ReadCheatFileFromFolder(title_id, build_id_, cheats_dir, false))
|
||||
std::copy(res->begin(), res->end(), std::back_inserter(out));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// User-friendly cheat loading from: <mod dir>/cheat_*.txt
|
||||
for (const auto& file : load_dir->GetFiles()) {
|
||||
const auto& name = file->GetName();
|
||||
if (!name.starts_with("cheat_")) {
|
||||
continue;
|
||||
// Uncareless user-friendly loading of patches (must start with 'cheat_')
|
||||
// <mod dir> / <cheat file>.txt
|
||||
auto const patch_files = load_dir->GetFiles();
|
||||
for (auto const& f : patch_files) {
|
||||
auto const name = f->GetName();
|
||||
if (name.starts_with("cheat_") && std::find(disabled.cbegin(), disabled.cend(), name) == disabled.cend()) {
|
||||
std::vector<u8> data(f->GetSize());
|
||||
if (f->Read(data.data(), data.size()) == data.size()) {
|
||||
const Core::Memory::TextCheatParser parser;
|
||||
auto const res = parser.Parse(std::string_view(reinterpret_cast<const char*>(data.data()), data.size()));
|
||||
std::copy(res.begin(), res.end(), std::back_inserter(out));
|
||||
} else {
|
||||
LOG_INFO(Common_Filesystem, "Failed to read cheats file for title_id={:016X}", title_id);
|
||||
}
|
||||
}
|
||||
if (std::find(disabled.cbegin(), disabled.cend(), name) != disabled.cend()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::vector<u8> data(file->GetSize());
|
||||
if (file->Read(data.data(), data.size()) != static_cast<size_t>(data.size())) {
|
||||
LOG_WARNING(Common_Filesystem, "Failed to read cheat file '{}' for title_id={:016X}",
|
||||
name, title_id);
|
||||
continue;
|
||||
}
|
||||
|
||||
const Service::DMNT::CheatParser parser;
|
||||
auto entries = parser.Parse(std::string_view(reinterpret_cast<const char*>(data.data()), data.size()));
|
||||
out.insert(out.end(), entries.begin(), entries.end());
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -515,53 +481,7 @@ VirtualFile PatchManager::PatchRomFS(const NCA* base_nca, VirtualFile base_romfs
|
||||
return romfs;
|
||||
}
|
||||
|
||||
PatchManager::BuildID PatchManager::GetBuildID(VirtualFile update_raw) const {
|
||||
BuildID build_id{};
|
||||
|
||||
// Get the base NCA
|
||||
const auto base_nca = content_provider.GetEntry(title_id, ContentRecordType::Program);
|
||||
if (base_nca == nullptr) {
|
||||
return build_id;
|
||||
}
|
||||
|
||||
// Try to get ExeFS from update first, then base
|
||||
VirtualDir exefs;
|
||||
const auto update_tid = GetUpdateTitleID(title_id);
|
||||
const auto update = content_provider.GetEntry(update_tid, ContentRecordType::Program);
|
||||
|
||||
if (update != nullptr && update->GetExeFS() != nullptr) {
|
||||
exefs = update->GetExeFS();
|
||||
} else if (update_raw != nullptr) {
|
||||
const auto new_nca = std::make_shared<NCA>(update_raw, base_nca.get());
|
||||
if (new_nca->GetStatus() == Loader::ResultStatus::Success &&
|
||||
new_nca->GetExeFS() != nullptr) {
|
||||
exefs = new_nca->GetExeFS();
|
||||
}
|
||||
}
|
||||
|
||||
if (exefs == nullptr) {
|
||||
exefs = base_nca->GetExeFS();
|
||||
}
|
||||
|
||||
if (exefs == nullptr) {
|
||||
return build_id;
|
||||
}
|
||||
|
||||
// Try to read the main NSO header
|
||||
const auto main_file = exefs->GetFile("main");
|
||||
if (main_file == nullptr || main_file->GetSize() < sizeof(Loader::NSOHeader)) {
|
||||
return build_id;
|
||||
}
|
||||
|
||||
Loader::NSOHeader header{};
|
||||
if (main_file->Read(reinterpret_cast<u8*>(&header), sizeof(header)) == sizeof(header)) {
|
||||
build_id = header.build_id;
|
||||
}
|
||||
|
||||
return build_id;
|
||||
}
|
||||
|
||||
std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw, const BuildID& build_id) const {
|
||||
std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const {
|
||||
if (title_id == 0) {
|
||||
return {};
|
||||
}
|
||||
@@ -582,8 +502,7 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw, const BuildI
|
||||
.version = "",
|
||||
.type = PatchType::Update,
|
||||
.program_id = title_id,
|
||||
.title_id = title_id,
|
||||
.parent_name = ""};
|
||||
.title_id = title_id};
|
||||
|
||||
if (nacp != nullptr) {
|
||||
update_patch.version = nacp->GetVersionString();
|
||||
@@ -603,15 +522,11 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw, const BuildI
|
||||
}
|
||||
}
|
||||
|
||||
// Check if we have a valid build_id for cheat enumeration
|
||||
const bool has_build_id = std::any_of(build_id.begin(), build_id.end(), [](u8 b) { return b != 0; });
|
||||
|
||||
// General Mods (LayeredFS and IPS)
|
||||
const auto mod_dir = fs_controller.GetModificationLoadRoot(title_id);
|
||||
if (mod_dir != nullptr) {
|
||||
for (const auto& mod : mod_dir->GetSubdirectories()) {
|
||||
std::string types;
|
||||
bool has_cheats = false;
|
||||
|
||||
const auto exefs_dir = FindSubdirectoryCaseless(mod, "exefs");
|
||||
if (IsDirValidAndNonEmpty(exefs_dir)) {
|
||||
@@ -640,12 +555,8 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw, const BuildI
|
||||
if (IsDirValidAndNonEmpty(FindSubdirectoryCaseless(mod, "romfs")) ||
|
||||
IsDirValidAndNonEmpty(FindSubdirectoryCaseless(mod, "romfslite")))
|
||||
AppendCommaIfNotEmpty(types, "LayeredFS");
|
||||
|
||||
const auto cheats_dir = FindSubdirectoryCaseless(mod, "cheats");
|
||||
if (IsDirValidAndNonEmpty(cheats_dir)) {
|
||||
has_cheats = true;
|
||||
if (IsDirValidAndNonEmpty(FindSubdirectoryCaseless(mod, "cheats")))
|
||||
AppendCommaIfNotEmpty(types, "Cheats");
|
||||
}
|
||||
|
||||
if (types.empty())
|
||||
continue;
|
||||
@@ -657,46 +568,7 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw, const BuildI
|
||||
.version = types,
|
||||
.type = PatchType::Mod,
|
||||
.program_id = title_id,
|
||||
.title_id = title_id,
|
||||
.parent_name = ""});
|
||||
|
||||
// Add individual cheats as sub-entries if we have a build_id
|
||||
if (has_cheats && has_build_id && !mod_disabled) {
|
||||
// Try to read cheat file (uppercase first, then lowercase)
|
||||
std::optional<std::vector<Service::DMNT::CheatEntry>> cheat_entries;
|
||||
if (auto res = ReadCheatFileFromFolder(title_id, build_id, cheats_dir, true)) {
|
||||
cheat_entries = std::move(res);
|
||||
} else if (auto res_lower = ReadCheatFileFromFolder(title_id, build_id, cheats_dir, false)) {
|
||||
cheat_entries = std::move(res_lower);
|
||||
}
|
||||
|
||||
if (cheat_entries) {
|
||||
for (const auto& cheat : *cheat_entries) {
|
||||
// Skip master cheat (id 0) with no readable name
|
||||
if (cheat.cheat_id == 0 && cheat.definition.readable_name[0] == '\0') {
|
||||
continue;
|
||||
}
|
||||
|
||||
const std::string cheat_name = cheat.definition.readable_name.data();
|
||||
if (cheat_name.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Create unique key for this cheat: "ModName::CheatName"
|
||||
const std::string cheat_key = mod->GetName() + "::" + cheat_name;
|
||||
const auto cheat_disabled =
|
||||
std::find(disabled.begin(), disabled.end(), cheat_key) != disabled.end();
|
||||
|
||||
out.push_back({.enabled = !cheat_disabled,
|
||||
.name = cheat_name,
|
||||
.version = types,
|
||||
.type = PatchType::Cheat,
|
||||
.program_id = title_id,
|
||||
.title_id = title_id,
|
||||
.parent_name = mod->GetName()});
|
||||
}
|
||||
}
|
||||
}
|
||||
.title_id = title_id});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -720,8 +592,7 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw, const BuildI
|
||||
.version = types,
|
||||
.type = PatchType::Mod,
|
||||
.program_id = title_id,
|
||||
.title_id = title_id,
|
||||
.parent_name = ""});
|
||||
.title_id = title_id});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -753,8 +624,7 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw, const BuildI
|
||||
.version = std::move(list),
|
||||
.type = PatchType::DLC,
|
||||
.program_id = title_id,
|
||||
.title_id = dlc_match.back().title_id,
|
||||
.parent_name = ""});
|
||||
.title_id = dlc_match.back().title_id});
|
||||
}
|
||||
|
||||
return out;
|
||||
|
||||
@@ -1,6 +1,3 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 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
|
||||
|
||||
@@ -13,6 +10,7 @@
|
||||
#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;
|
||||
@@ -22,17 +20,13 @@ namespace Service::FileSystem {
|
||||
class FileSystemController;
|
||||
}
|
||||
|
||||
namespace Service::DMNT {
|
||||
struct CheatEntry;
|
||||
}
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
class ContentProvider;
|
||||
class NCA;
|
||||
class NACP;
|
||||
|
||||
enum class PatchType { Update, DLC, Mod, Cheat };
|
||||
enum class PatchType { Update, DLC, Mod };
|
||||
|
||||
struct Patch {
|
||||
bool enabled;
|
||||
@@ -41,7 +35,6 @@ struct Patch {
|
||||
PatchType type;
|
||||
u64 program_id;
|
||||
u64 title_id;
|
||||
std::string parent_name;
|
||||
};
|
||||
|
||||
// A centralized class to manage patches to games.
|
||||
@@ -72,7 +65,7 @@ public:
|
||||
[[nodiscard]] bool HasNSOPatch(const BuildID& build_id, std::string_view name) const;
|
||||
|
||||
// Creates a CheatList object with all
|
||||
[[nodiscard]] std::vector<Service::DMNT::CheatEntry> CreateCheatList(
|
||||
[[nodiscard]] std::vector<Core::Memory::CheatEntry> CreateCheatList(
|
||||
const BuildID& build_id) const;
|
||||
|
||||
// Currently tracked RomFS patches:
|
||||
@@ -83,11 +76,8 @@ public:
|
||||
VirtualFile packed_update_raw = nullptr,
|
||||
bool apply_layeredfs = true) const;
|
||||
|
||||
// Returns a vector of patches including individual cheats
|
||||
[[nodiscard]] std::vector<Patch> GetPatches(VirtualFile update_raw = nullptr,
|
||||
const BuildID& build_id = {}) const;
|
||||
|
||||
[[nodiscard]] BuildID GetBuildID(VirtualFile update_raw = nullptr) 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
|
||||
|
||||
@@ -12,7 +12,7 @@
|
||||
#include "common/common_types.h"
|
||||
#include "common/expected.h"
|
||||
|
||||
// All the constants in this file come from http://switchbrew.org/index.php?title=Error_codes
|
||||
// All the constants in this file come from <http://switchbrew.org/index.php?title=Error_codes>
|
||||
|
||||
/**
|
||||
* Identifies the module which caused the error. Error codes can be propagated through a call
|
||||
@@ -87,6 +87,7 @@ enum class ErrorModule : u32 {
|
||||
AM = 128,
|
||||
PlayReport = 129,
|
||||
AHID = 130,
|
||||
APPLET = 131,
|
||||
Qlaunch = 132,
|
||||
PCV = 133,
|
||||
USBPD = 134,
|
||||
@@ -113,8 +114,8 @@ enum class ErrorModule : u32 {
|
||||
NPNSHTTPSTREAM = 155,
|
||||
IDLE = 156,
|
||||
ARP = 157,
|
||||
SWKBD = 158,
|
||||
BOOT = 159,
|
||||
UPDATER = 158,
|
||||
SWKBD = 159,
|
||||
NetDiag = 160,
|
||||
NFCMifare = 161,
|
||||
UserlandAssert = 162,
|
||||
@@ -125,7 +126,8 @@ enum class ErrorModule : u32 {
|
||||
BGTC = 167,
|
||||
UserlandCrash = 168,
|
||||
SASBUS = 169,
|
||||
PI = 170,
|
||||
PL = 170,
|
||||
CDMSC = 171,
|
||||
AudioCtrl = 172,
|
||||
LBL = 173,
|
||||
JIT = 175,
|
||||
@@ -137,23 +139,30 @@ enum class ErrorModule : u32 {
|
||||
Dauth = 181,
|
||||
STDFU = 182,
|
||||
DBG = 183,
|
||||
CDACM = 184,
|
||||
TCAP = 185,
|
||||
DHCPS = 186,
|
||||
SPI = 187,
|
||||
AVM = 188,
|
||||
PWM = 189,
|
||||
DNSServer = 190,
|
||||
RTC = 191,
|
||||
Regulator = 192,
|
||||
LED = 193,
|
||||
HTCTool = 194,
|
||||
SIO = 195,
|
||||
PCM = 196,
|
||||
CLKRST = 197,
|
||||
POWCTL = 198,
|
||||
HIDDriver = 199,
|
||||
DMA = 200,
|
||||
AudioOld = 201,
|
||||
HID = 202,
|
||||
LDN = 203,
|
||||
CS = 204,
|
||||
Irsensor = 205,
|
||||
Capture = 206,
|
||||
MM = 207,
|
||||
Manu = 208,
|
||||
ATK = 209,
|
||||
WEB = 210,
|
||||
@@ -166,19 +175,24 @@ enum class ErrorModule : u32 {
|
||||
MigrationLdcServ = 217,
|
||||
HIDBUS = 218,
|
||||
ENS = 219,
|
||||
ND = 220,
|
||||
NDD = 221,
|
||||
ToyCon = 222,
|
||||
WebSocket = 223,
|
||||
SocketIO = 224,
|
||||
DCDMTP = 227,
|
||||
PGL = 228,
|
||||
Notification = 229,
|
||||
INS = 230,
|
||||
LP2P = 231,
|
||||
RCD = 232,
|
||||
LCM40607 = 233,
|
||||
ICM40607 = 233,
|
||||
PRC = 235,
|
||||
TMAHTC = 237,
|
||||
ECTX = 238,
|
||||
BridgeCtrl = 237,
|
||||
ErrContext = 238,
|
||||
MNPP = 239,
|
||||
HSHL = 240,
|
||||
RINGCON = 241,
|
||||
CAPMTP = 242,
|
||||
DP2HDMI = 244,
|
||||
Cradle = 245,
|
||||
@@ -186,6 +200,8 @@ enum class ErrorModule : u32 {
|
||||
Icm42607p = 248,
|
||||
NDRM = 250,
|
||||
Fst2 = 251,
|
||||
TS = 253,
|
||||
SPLAY = 260,
|
||||
Nex = 306,
|
||||
NPLN = 321,
|
||||
TSPM = 499,
|
||||
|
||||
@@ -88,13 +88,13 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_, std::shared_
|
||||
{181, nullptr, "UpgradeLaunchRequiredVersion"},
|
||||
{190, nullptr, "SendServerMaintenanceOverlayNotification"},
|
||||
{200, nullptr, "GetLastApplicationExitReason"},
|
||||
{210, D<&IApplicationFunctions::GetLaunchRequiredVersionUpgrade>, "GetLaunchRequiredVersionUpgrade"}, // [20.0.0+]
|
||||
{211, nullptr, "GetLaunchRequiredVersionUpgradeStatus"}, // [20.0.0+]
|
||||
{220, nullptr, "Unknown220"}, // [20.0.0+]
|
||||
{300, nullptr, "Unknown300"}, // [20.0.0+]
|
||||
{310, nullptr, "Unknown310"}, // [20.0.0+]
|
||||
{320, nullptr, "Unknown320"}, // [20.0.0+]
|
||||
{330, nullptr, "Unknown330"}, // [20.0.0+]
|
||||
{210, D<&IApplicationFunctions::GetLaunchRequiredVersionUpgrade>, "GetLaunchRequiredVersionUpgrade"}, //20.0.0+
|
||||
{211, nullptr, "GetLaunchRequiredVersionUpgradeStatus"}, //20.0.0+
|
||||
{220, nullptr, "Unknown220"}, //20.0.0+
|
||||
{300, nullptr, "CreateMovieWriter"}, //20.0.0+
|
||||
{310, nullptr, "Unknown310"}, //20.0.0+
|
||||
{320, nullptr, "Unknown320"}, //20.0.0+
|
||||
{330, nullptr, "Unknown330"}, //20.0.0+
|
||||
{500, nullptr, "StartContinuousRecordingFlushForDebug"},
|
||||
{1000, nullptr, "CreateMovieMaker"},
|
||||
{1001, D<&IApplicationFunctions::PrepareForJit>, "PrepareForJit"},
|
||||
|
||||
@@ -18,7 +18,7 @@ IAudioController::IAudioController(Core::System& system_)
|
||||
{2, D<&IAudioController::GetLibraryAppletExpectedMasterVolume>, "GetLibraryAppletExpectedMasterVolume"},
|
||||
{3, D<&IAudioController::ChangeMainAppletMasterVolume>, "ChangeMainAppletMasterVolume"},
|
||||
{4, D<&IAudioController::SetTransparentVolumeRate>, "SetTransparentVolumeRate"},
|
||||
{5, nullptr, "Unknown5"},
|
||||
{5, nullptr, "Unknown5"}, //20.0.0+
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -30,7 +30,7 @@ IAudioController::IAudioController(Core::System& system_)
|
||||
{3, D<&IAudioController::GetTargetVolumeMax>, "GetTargetVolumeMax"},
|
||||
{4, D<&IAudioController::IsTargetMute>, "IsTargetMute"},
|
||||
{5, D<&IAudioController::SetTargetMute>, "SetTargetMute"},
|
||||
{6, nullptr, "IsTargetConnected"},
|
||||
{6, nullptr, "IsTargetConnected"}, //20.0.0+
|
||||
{7, nullptr, "SetDefaultTarget"},
|
||||
{8, nullptr, "GetDefaultTarget"},
|
||||
{9, D<&IAudioController::GetAudioOutputMode>, "GetAudioOutputMode"},
|
||||
@@ -67,7 +67,8 @@ IAudioController::IAudioController(Core::System& system_)
|
||||
{40, nullptr, "GetSystemInformationForDebug"},
|
||||
{41, nullptr, "SetVolumeButtonLongPressTime"},
|
||||
{42, nullptr, "SetNativeVolumeForDebug"},
|
||||
{5000, D<&IAudioController::Unknown5000>, "Unknown5000"},
|
||||
{43, nullptr, "Unknown43"}, //21.0.0+
|
||||
{5000, D<&IAudioController::Unknown5000>, "Unknown5000"}, //19.0.0+
|
||||
{10000, nullptr, "NotifyAudioOutputTargetForPlayReport"},
|
||||
{10001, nullptr, "NotifyAudioOutputChannelCountForPlayReport"},
|
||||
{10002, nullptr, "NotifyUnsupportedUsbOutputDeviceAttachedForPlayReport"},
|
||||
@@ -76,13 +77,13 @@ IAudioController::IAudioController(Core::System& system_)
|
||||
{10102, nullptr, "BindAudioOutputTargetUpdateEventForPlayReport"},
|
||||
{10103, nullptr, "GetAudioOutputTargetForPlayReport"},
|
||||
{10104, nullptr, "GetAudioOutputChannelCountForPlayReport"},
|
||||
{10105, nullptr, "BindAudioOutputChannelCountUpdateEventForPlayReport"},
|
||||
{10106, nullptr, "GetDefaultAudioOutputTargetForPlayReport"},
|
||||
{10200, nullptr, "Unknown10200"}, // [20.0.0+]
|
||||
{50000, nullptr, "SetAnalogInputBoostGainForPrototyping"},
|
||||
{50001, nullptr, "OverrideDefaultTargetForDebug"},
|
||||
{50003, nullptr, "SetForceOverrideExternalDeviceNameForDebug"},
|
||||
{50004, nullptr, "ClearForceOverrideExternalDeviceNameForDebug"}
|
||||
{10105, nullptr, "BindAudioOutputChannelCountUpdateEventForPlayReport"}, //14.0.0-19.0.1
|
||||
{10106, nullptr, "GetDefaultAudioOutputTargetForPlayReport"}, //14.0.0-19.0.1
|
||||
{10200, nullptr, "Unknown10200"}, //20.0.0+
|
||||
{50000, nullptr, "SetAnalogInputBoostGainForPrototyping"}, //15.0.0-18.1.0
|
||||
{50001, nullptr, "OverrideDefaultTargetForDebug"}, //19.0.0-19.0.1
|
||||
{50003, nullptr, "SetForceOverrideExternalDeviceNameForDebug"}, //19.0.0+
|
||||
{50004, nullptr, "ClearForceOverrideExternalDeviceNameForDebug"} //19.0.0+
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -32,13 +32,13 @@ IAudioDevice::IAudioDevice(Core::System& system_, u64 applet_resource_user_id, u
|
||||
{12, D<&IAudioDevice::QueryAudioDeviceOutputEvent>, "QueryAudioDeviceOutputEvent"},
|
||||
{13, D<&IAudioDevice::GetActiveAudioDeviceName>, "GetActiveAudioOutputDeviceName"},
|
||||
{14, D<&IAudioDevice::ListAudioOutputDeviceName>, "ListAudioOutputDeviceName"},
|
||||
{15, nullptr, "AcquireAudioInputDeviceNotification"}, // 17.0.0+
|
||||
{16, nullptr, "ReleaseAudioInputDeviceNotification"}, // 17.0.0+
|
||||
{17, nullptr, "AcquireAudioOutputDeviceNotification"}, // 17.0.0+
|
||||
{18, nullptr, "ReleaseAudioOutputDeviceNotification"}, // 17.0.0+
|
||||
{19, nullptr, "SetAudioDeviceOutputVolumeAutoTuneEnabled"}, // 18.0.0+
|
||||
{20, nullptr, "IsAudioDeviceOutputVolumeAutoTuneEnabled"}, // 18.0.0+
|
||||
{21, nullptr, "IsActiveOutputDeviceEstimatedLowLatency"} // 21.0.0+
|
||||
{15, nullptr, "AcquireAudioInputDeviceNotification"}, //17.0.0+
|
||||
{16, nullptr, "ReleaseAudioInputDeviceNotification"}, //17.0.0+
|
||||
{17, nullptr, "AcquireAudioOutputDeviceNotification"}, //17.0.0+
|
||||
{18, nullptr, "ReleaseAudioOutputDeviceNotification"}, //17.0.0+
|
||||
{19, nullptr, "SetAudioDeviceOutputVolumeAutoTuneEnabled"}, //18.0.0+
|
||||
{20, nullptr, "IsAudioDeviceOutputVolumeAutoTuneEnabled"}, //18.0.0+
|
||||
{21, nullptr, "IsActiveOutputDeviceEstimatedLowLatency"} //21.0.0+
|
||||
};
|
||||
RegisterHandlers(functions);
|
||||
|
||||
|
||||
@@ -43,21 +43,21 @@ IBcatService::IBcatService(Core::System& system_, BcatBackend& backend_)
|
||||
{20401, nullptr, "UnregisterSystemApplicationDeliveryTask"},
|
||||
{20410, nullptr, "SetSystemApplicationDeliveryTaskTimer"},
|
||||
{30100, D<&IBcatService::SetPassphrase>, "SetPassphrase"},
|
||||
{30101, nullptr, "Unknown30101"},
|
||||
{30102, nullptr, "Unknown30102"},
|
||||
{30101, nullptr, "Unknown30101"}, //2.0.0-2.3.0
|
||||
{30102, nullptr, "Unknown30102"}, //2.0.0-2.3.0
|
||||
{30200, nullptr, "RegisterBackgroundDeliveryTask"},
|
||||
{30201, nullptr, "UnregisterBackgroundDeliveryTask"},
|
||||
{30202, nullptr, "BlockDeliveryTask"},
|
||||
{30203, nullptr, "UnblockDeliveryTask"},
|
||||
{30210, nullptr, "SetDeliveryTaskTimer"},
|
||||
{30300, D<&IBcatService::RegisterSystemApplicationDeliveryTasks>, "RegisterSystemApplicationDeliveryTasks"},
|
||||
{90100, nullptr, "EnumerateBackgroundDeliveryTask"},
|
||||
{90101, nullptr, "Unknown90101"},
|
||||
{90100, nullptr, "GetDeliveryTaskList"},
|
||||
{90101, nullptr, "GetDeliveryTaskListForSystem"}, //11.0.0+
|
||||
{90200, nullptr, "GetDeliveryList"},
|
||||
{90201, D<&IBcatService::ClearDeliveryCacheStorage>, "ClearDeliveryCacheStorage"},
|
||||
{90202, nullptr, "ClearDeliveryTaskSubscriptionStatus"},
|
||||
{90300, nullptr, "GetPushNotificationLog"},
|
||||
{90301, nullptr, "Unknown90301"},
|
||||
{90301, nullptr, "GetDeliveryCacheStorageUsage"}, //11.0.0+
|
||||
};
|
||||
// clang-format on
|
||||
RegisterHandlers(functions);
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -12,19 +15,19 @@ INewsService::INewsService(Core::System& system_) : ServiceFramework{system_, "I
|
||||
{10100, D<&INewsService::PostLocalNews>, "PostLocalNews"},
|
||||
{20100, nullptr, "SetPassphrase"},
|
||||
{30100, D<&INewsService::GetSubscriptionStatus>, "GetSubscriptionStatus"},
|
||||
{30101, nullptr, "GetTopicList"},
|
||||
{30110, nullptr, "Unknown30110"},
|
||||
{30101, nullptr, "GetTopicList"}, //3.0.0+
|
||||
{30110, nullptr, "Unknown30110"}, //6.0.0+
|
||||
{30200, D<&INewsService::IsSystemUpdateRequired>, "IsSystemUpdateRequired"},
|
||||
{30201, nullptr, "Unknown30201"},
|
||||
{30210, nullptr, "Unknown30210"},
|
||||
{30201, nullptr, "Unknown30201"}, //8.0.0+
|
||||
{30210, nullptr, "Unknown30210"}, //10.0.0+
|
||||
{30300, nullptr, "RequestImmediateReception"},
|
||||
{30400, nullptr, "DecodeArchiveFile"},
|
||||
{30500, nullptr, "Unknown30500"},
|
||||
{30900, nullptr, "Unknown30900"},
|
||||
{30901, nullptr, "Unknown30901"},
|
||||
{30902, nullptr, "Unknown30902"},
|
||||
{30400, nullptr, "DecodeArchiveFile"}, //3.0.0-18.1.0
|
||||
{30500, nullptr, "Unknown30500"}, //8.0.0+
|
||||
{30900, nullptr, "Unknown30900"}, //1.0.0
|
||||
{30901, nullptr, "Unknown30901"}, //1.0.0
|
||||
{30902, nullptr, "Unknown30902"}, //1.0.0
|
||||
{40100, nullptr, "SetSubscriptionStatus"},
|
||||
{40101, D<&INewsService::RequestAutoSubscription>, "RequestAutoSubscription"},
|
||||
{40101, D<&INewsService::RequestAutoSubscription>, "RequestAutoSubscription"}, //3.0.0+
|
||||
{40200, nullptr, "ClearStorage"},
|
||||
{40201, nullptr, "ClearSubscriptionStatusAll"},
|
||||
{90100, nullptr, "GetNewsDatabaseDump"},
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 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
|
||||
|
||||
@@ -77,31 +80,33 @@ public:
|
||||
{57, nullptr, "RegisterAppletResourceUserId"},
|
||||
{58, nullptr, "UnregisterAppletResourceUserId"},
|
||||
{59, nullptr, "SetAppletResourceUserId"},
|
||||
{60, nullptr, "Unknown60"},
|
||||
{61, nullptr, "Unknown61"},
|
||||
{62, nullptr, "Unknown62"},
|
||||
{63, nullptr, "Unknown63"},
|
||||
{64, nullptr, "Unknown64"},
|
||||
{65, nullptr, "Unknown65"},
|
||||
{66, nullptr, "Unknown66"},
|
||||
{67, nullptr, "Unknown67"},
|
||||
{68, nullptr, "Unknown68"},
|
||||
{69, nullptr, "Unknown69"},
|
||||
{70, nullptr, "Unknown70"},
|
||||
{71, nullptr, "Unknown71"},
|
||||
{72, nullptr, "Unknown72"},
|
||||
{73, nullptr, "Unknown73"},
|
||||
{74, nullptr, "Unknown74"},
|
||||
{75, nullptr, "Unknown75"},
|
||||
{76, nullptr, "Unknown76"},
|
||||
{100, nullptr, "Unknown100"},
|
||||
{101, nullptr, "Unknown101"},
|
||||
{110, nullptr, "Unknown110"},
|
||||
{111, nullptr, "Unknown111"},
|
||||
{112, nullptr, "Unknown112"},
|
||||
{113, nullptr, "Unknown113"},
|
||||
{114, nullptr, "Unknown114"},
|
||||
{115, nullptr, "Unknown115"},
|
||||
{60, nullptr, "AcquireBleConnectionParameterUpdateEvent"}, //8.0.0+
|
||||
{61, nullptr, "SetCeLength"}, //8.0.0+
|
||||
{62, nullptr, "EnsureSlotExpansion"}, //9.0.0+
|
||||
{63, nullptr, "IsSlotExpansionEnsured"}, //9.0.0+
|
||||
{64, nullptr, "CancelConnectionTrigger"}, //10.0.0+
|
||||
{65, nullptr, "GetConnectionCapacity"}, //13.0.0+
|
||||
{66, nullptr, "GetWlanMode"}, //13.0.0+
|
||||
{67, nullptr, "IsSlotSavingEnabled"}, //13.0.0+
|
||||
{68, nullptr, "IsSlotSavingForPairingEnabled"}, //13.0.0+
|
||||
{69, nullptr, "AcquireAudioDeviceConnectionEvent"}, //13.0.0+
|
||||
{70, nullptr, "GetConnectedAudioDevices"}, //13.0.0+
|
||||
{71, nullptr, "SetAudioSourceVolume"}, //13.0.0+
|
||||
{72, nullptr, "GetAudioSourceVolume"}, //13.0.0+
|
||||
{73, nullptr, "RequestAudioDeviceConnectionRejection"}, //13.0.0+
|
||||
{74, nullptr, "CancelAudioDeviceConnectionRejection"}, //13.0.0+
|
||||
{75, nullptr, "GetPairedAudioDevices"}, //13.0.0+
|
||||
{76, nullptr, "SetWlanModeWithOption"}, //13.1.0+
|
||||
{100, nullptr, "AcquireConnectionDisallowedEvent"}, //13.0.0+
|
||||
{101, nullptr, "GetUsecaseViolationFactor"}, //13.0.0+
|
||||
{110, nullptr, "GetShortenedDeviceInfo"}, //13.0.0+
|
||||
{111, nullptr, "AcquirePairingCountUpdateEvent"},//13.0.0+
|
||||
{112, nullptr, "Unknown112"}, //14.0.0-14.1.2
|
||||
{113, nullptr, "Unknown113"}, //14.0.0-14.1.2
|
||||
{114, nullptr, "IsFirstAudioControlConnection"}, //14.0.0+
|
||||
{115, nullptr, "GetShortenedDeviceCondition"}, //14.0.0+
|
||||
{116, nullptr, "SetAudioSinkVolume"}, //15.0.0+
|
||||
{117, nullptr, "GetAudioSinkVolume"}, //15.0.0+
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
@@ -17,11 +20,15 @@ IBtmDebug::IBtmDebug(Core::System& system_) : ServiceFramework{system_, "btm:dbg
|
||||
{6, nullptr, "SetTsiMode"},
|
||||
{7, nullptr, "GeneralTest"},
|
||||
{8, nullptr, "HidConnect"},
|
||||
{9, nullptr, "GeneralGet"},
|
||||
{10, nullptr, "GetGattClientDisconnectionReason"},
|
||||
{11, nullptr, "GetBleConnectionParameter"},
|
||||
{12, nullptr, "GetBleConnectionParameterRequest"},
|
||||
{13, nullptr, "Unknown13"},
|
||||
{9, nullptr, "GeneralGet"}, //5.0.0+
|
||||
{10, nullptr, "GetGattClientDisconnectionReason"}, //5.0.0+
|
||||
{11, nullptr, "GetBleConnectionParameter"}, //5.1.0+
|
||||
{12, nullptr, "GetBleConnectionParameterRequest"}, //5.1.0+
|
||||
{13, nullptr, "GetDiscoveredDevice"}, //12.0.0+
|
||||
{14, nullptr, "SleepAwakeLoopTest"}, //15.0.0+
|
||||
{15, nullptr, "SleepTest"}, //15.0.0+
|
||||
{16, nullptr, "MinimumAwakeTest"}, //15.0.0+
|
||||
{17, nullptr, "ForceEnableBtm"}, //15.0.0+
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -1,238 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "core/hle/service/cmif_serialization.h"
|
||||
#include "core/hle/service/dmnt/cheat_interface.h"
|
||||
#include "core/hle/service/dmnt/cheat_process_manager.h"
|
||||
#include "core/hle/service/dmnt/dmnt_results.h"
|
||||
#include "core/hle/service/dmnt/dmnt_types.h"
|
||||
|
||||
namespace Service::DMNT {
|
||||
ICheatInterface::ICheatInterface(Core::System& system_, CheatProcessManager& manager)
|
||||
: ServiceFramework{system_, "dmnt:cht"}, cheat_process_manager{manager} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{65000, C<&ICheatInterface::HasCheatProcess>, "HasCheatProcess"},
|
||||
{65001, C<&ICheatInterface::GetCheatProcessEvent>, "GetCheatProcessEvent"},
|
||||
{65002, C<&ICheatInterface::GetCheatProcessMetadata>, "GetCheatProcessMetadata"},
|
||||
{65003, C<&ICheatInterface::ForceOpenCheatProcess>, "ForceOpenCheatProcess"},
|
||||
{65004, C<&ICheatInterface::PauseCheatProcess>, "PauseCheatProcess"},
|
||||
{65005, C<&ICheatInterface::ResumeCheatProcess>, "ResumeCheatProcess"},
|
||||
{65006, C<&ICheatInterface::ForceCloseCheatProcess>, "ForceCloseCheatProcess"},
|
||||
{65100, C<&ICheatInterface::GetCheatProcessMappingCount>, "GetCheatProcessMappingCount"},
|
||||
{65101, C<&ICheatInterface::GetCheatProcessMappings>, "GetCheatProcessMappings"},
|
||||
{65102, C<&ICheatInterface::ReadCheatProcessMemory>, "ReadCheatProcessMemory"},
|
||||
{65103, C<&ICheatInterface::WriteCheatProcessMemory>, "WriteCheatProcessMemory"},
|
||||
{65104, C<&ICheatInterface::QueryCheatProcessMemory>, "QueryCheatProcessMemory"},
|
||||
{65200, C<&ICheatInterface::GetCheatCount>, "GetCheatCount"},
|
||||
{65201, C<&ICheatInterface::GetCheats>, "GetCheats"},
|
||||
{65202, C<&ICheatInterface::GetCheatById>, "GetCheatById"},
|
||||
{65203, C<&ICheatInterface::ToggleCheat>, "ToggleCheat"},
|
||||
{65204, C<&ICheatInterface::AddCheat>, "AddCheat"},
|
||||
{65205, C<&ICheatInterface::RemoveCheat>, "RemoveCheat"},
|
||||
{65206, C<&ICheatInterface::ReadStaticRegister>, "ReadStaticRegister"},
|
||||
{65207, C<&ICheatInterface::WriteStaticRegister>, "WriteStaticRegister"},
|
||||
{65208, C<&ICheatInterface::ResetStaticRegisters>, "ResetStaticRegisters"},
|
||||
{65209, C<&ICheatInterface::SetMasterCheat>, "SetMasterCheat"},
|
||||
{65300, C<&ICheatInterface::GetFrozenAddressCount>, "GetFrozenAddressCount"},
|
||||
{65301, C<&ICheatInterface::GetFrozenAddresses>, "GetFrozenAddresses"},
|
||||
{65302, C<&ICheatInterface::GetFrozenAddress>, "GetFrozenAddress"},
|
||||
{65303, C<&ICheatInterface::EnableFrozenAddress>, "EnableFrozenAddress"},
|
||||
{65304, C<&ICheatInterface::DisableFrozenAddress>, "DisableFrozenAddress"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
RegisterHandlers(functions);
|
||||
}
|
||||
|
||||
ICheatInterface::~ICheatInterface() = default;
|
||||
|
||||
Result ICheatInterface::HasCheatProcess(Out<bool> out_has_cheat) {
|
||||
LOG_INFO(CheatEngine, "called");
|
||||
*out_has_cheat = cheat_process_manager.HasCheatProcess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ICheatInterface::GetCheatProcessEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
|
||||
LOG_INFO(CheatEngine, "called");
|
||||
*out_event = &cheat_process_manager.GetCheatProcessEvent();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ICheatInterface::GetCheatProcessMetadata(Out<CheatProcessMetadata> out_metadata) {
|
||||
LOG_INFO(CheatEngine, "called");
|
||||
R_RETURN(cheat_process_manager.GetCheatProcessMetadata(*out_metadata));
|
||||
}
|
||||
|
||||
Result ICheatInterface::ForceOpenCheatProcess() {
|
||||
LOG_INFO(CheatEngine, "called");
|
||||
R_UNLESS(R_SUCCEEDED(cheat_process_manager.ForceOpenCheatProcess()), ResultCheatNotAttached);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ICheatInterface::PauseCheatProcess() {
|
||||
LOG_INFO(CheatEngine, "called");
|
||||
R_RETURN(cheat_process_manager.PauseCheatProcess());
|
||||
}
|
||||
|
||||
Result ICheatInterface::ResumeCheatProcess() {
|
||||
LOG_INFO(CheatEngine, "called");
|
||||
R_RETURN(cheat_process_manager.ResumeCheatProcess());
|
||||
}
|
||||
|
||||
Result ICheatInterface::ForceCloseCheatProcess() {
|
||||
LOG_WARNING(CheatEngine, "(STUBBED) called");
|
||||
R_RETURN(cheat_process_manager.ForceCloseCheatProcess());
|
||||
}
|
||||
|
||||
Result ICheatInterface::GetCheatProcessMappingCount(Out<u64> out_count) {
|
||||
LOG_WARNING(CheatEngine, "(STUBBED) called");
|
||||
R_RETURN(cheat_process_manager.GetCheatProcessMappingCount(*out_count));
|
||||
}
|
||||
|
||||
Result ICheatInterface::GetCheatProcessMappings(
|
||||
Out<u64> out_count, u64 offset,
|
||||
OutArray<Kernel::Svc::MemoryInfo, BufferAttr_HipcMapAlias> out_mappings) {
|
||||
LOG_INFO(CheatEngine, "called, offset={}", offset);
|
||||
R_UNLESS(!out_mappings.empty(), ResultCheatNullBuffer);
|
||||
R_RETURN(cheat_process_manager.GetCheatProcessMappings(*out_count, offset, out_mappings));
|
||||
}
|
||||
|
||||
Result ICheatInterface::ReadCheatProcessMemory(u64 address, u64 size,
|
||||
OutBuffer<BufferAttr_HipcMapAlias> out_buffer) {
|
||||
LOG_DEBUG(CheatEngine, "called, address={}, size={}", address, size);
|
||||
R_UNLESS(!out_buffer.empty(), ResultCheatNullBuffer);
|
||||
R_RETURN(cheat_process_manager.ReadCheatProcessMemory(address, size, out_buffer));
|
||||
}
|
||||
|
||||
Result ICheatInterface::WriteCheatProcessMemory(u64 address, u64 size,
|
||||
InBuffer<BufferAttr_HipcMapAlias> buffer) {
|
||||
LOG_DEBUG(CheatEngine, "called, address={}, size={}", address, size);
|
||||
R_UNLESS(!buffer.empty(), ResultCheatNullBuffer);
|
||||
R_RETURN(cheat_process_manager.WriteCheatProcessMemory(address, size, buffer));
|
||||
}
|
||||
|
||||
Result ICheatInterface::QueryCheatProcessMemory(Out<Kernel::Svc::MemoryInfo> out_mapping,
|
||||
u64 address) {
|
||||
LOG_WARNING(CheatEngine, "(STUBBED) called, address={}", address);
|
||||
R_RETURN(cheat_process_manager.QueryCheatProcessMemory(out_mapping, address));
|
||||
}
|
||||
|
||||
Result ICheatInterface::GetCheatCount(Out<u64> out_count) {
|
||||
LOG_INFO(CheatEngine, "called");
|
||||
R_RETURN(cheat_process_manager.GetCheatCount(*out_count));
|
||||
}
|
||||
|
||||
Result ICheatInterface::GetCheats(Out<u64> out_count, u64 offset,
|
||||
OutArray<CheatEntry, BufferAttr_HipcMapAlias> out_cheats) {
|
||||
LOG_INFO(CheatEngine, "called, offset={}", offset);
|
||||
R_UNLESS(!out_cheats.empty(), ResultCheatNullBuffer);
|
||||
R_RETURN(cheat_process_manager.GetCheats(*out_count, offset, out_cheats));
|
||||
}
|
||||
|
||||
Result ICheatInterface::GetCheatById(OutLargeData<CheatEntry, BufferAttr_HipcMapAlias> out_cheat,
|
||||
u32 cheat_id) {
|
||||
LOG_INFO(CheatEngine, "called, cheat_id={}", cheat_id);
|
||||
R_RETURN(cheat_process_manager.GetCheatById(out_cheat, cheat_id));
|
||||
}
|
||||
|
||||
Result ICheatInterface::ToggleCheat(u32 cheat_id) {
|
||||
LOG_INFO(CheatEngine, "called, cheat_id={}", cheat_id);
|
||||
R_RETURN(cheat_process_manager.ToggleCheat(cheat_id));
|
||||
}
|
||||
|
||||
Result ICheatInterface::AddCheat(
|
||||
Out<u32> out_cheat_id, bool is_enabled,
|
||||
InLargeData<CheatDefinition, BufferAttr_HipcMapAlias> cheat_definition) {
|
||||
LOG_INFO(CheatEngine, "called, is_enabled={}", is_enabled);
|
||||
R_RETURN(cheat_process_manager.AddCheat(*out_cheat_id, is_enabled, *cheat_definition));
|
||||
}
|
||||
|
||||
Result ICheatInterface::RemoveCheat(u32 cheat_id) {
|
||||
LOG_INFO(CheatEngine, "called, cheat_id={}", cheat_id);
|
||||
R_RETURN(cheat_process_manager.RemoveCheat(cheat_id));
|
||||
}
|
||||
|
||||
Result ICheatInterface::ReadStaticRegister(Out<u64> out_value, u8 register_index) {
|
||||
LOG_DEBUG(CheatEngine, "called, register_index={}", register_index);
|
||||
R_RETURN(cheat_process_manager.ReadStaticRegister(*out_value, register_index));
|
||||
}
|
||||
|
||||
Result ICheatInterface::WriteStaticRegister(u8 register_index, u64 value) {
|
||||
LOG_DEBUG(CheatEngine, "called, register_index={}, value={}", register_index, value);
|
||||
R_RETURN(cheat_process_manager.WriteStaticRegister(register_index, value));
|
||||
}
|
||||
|
||||
Result ICheatInterface::ResetStaticRegisters() {
|
||||
LOG_INFO(CheatEngine, "called");
|
||||
R_RETURN(cheat_process_manager.ResetStaticRegisters());
|
||||
}
|
||||
|
||||
Result ICheatInterface::SetMasterCheat(
|
||||
InLargeData<CheatDefinition, BufferAttr_HipcMapAlias> cheat_definition) {
|
||||
LOG_INFO(CheatEngine, "called, name={}, num_opcodes={}", cheat_definition->readable_name.data(),
|
||||
cheat_definition->num_opcodes);
|
||||
R_RETURN(cheat_process_manager.SetMasterCheat(*cheat_definition));
|
||||
}
|
||||
|
||||
Result ICheatInterface::GetFrozenAddressCount(Out<u64> out_count) {
|
||||
LOG_INFO(CheatEngine, "called");
|
||||
R_RETURN(cheat_process_manager.GetFrozenAddressCount(*out_count));
|
||||
}
|
||||
|
||||
Result ICheatInterface::GetFrozenAddresses(
|
||||
Out<u64> out_count, u64 offset,
|
||||
OutArray<FrozenAddressEntry, BufferAttr_HipcMapAlias> out_frozen_address) {
|
||||
LOG_INFO(CheatEngine, "called, offset={}", offset);
|
||||
R_UNLESS(!out_frozen_address.empty(), ResultCheatNullBuffer);
|
||||
R_RETURN(cheat_process_manager.GetFrozenAddresses(*out_count, offset, out_frozen_address));
|
||||
}
|
||||
|
||||
Result ICheatInterface::GetFrozenAddress(Out<FrozenAddressEntry> out_frozen_address_entry,
|
||||
u64 address) {
|
||||
LOG_INFO(CheatEngine, "called, address={}", address);
|
||||
R_RETURN(cheat_process_manager.GetFrozenAddress(*out_frozen_address_entry, address));
|
||||
}
|
||||
|
||||
Result ICheatInterface::EnableFrozenAddress(Out<u64> out_value, u64 address, u64 width) {
|
||||
LOG_INFO(CheatEngine, "called, address={}, width={}", address, width);
|
||||
R_UNLESS(width > 0, ResultFrozenAddressInvalidWidth);
|
||||
R_UNLESS(width <= sizeof(u64), ResultFrozenAddressInvalidWidth);
|
||||
R_UNLESS((width & (width - 1)) == 0, ResultFrozenAddressInvalidWidth);
|
||||
R_RETURN(cheat_process_manager.EnableFrozenAddress(*out_value, address, width));
|
||||
}
|
||||
|
||||
Result ICheatInterface::DisableFrozenAddress(u64 address) {
|
||||
LOG_INFO(CheatEngine, "called, address={}", address);
|
||||
R_RETURN(cheat_process_manager.DisableFrozenAddress(address));
|
||||
}
|
||||
|
||||
void ICheatInterface::InitializeCheatManager() {
|
||||
LOG_INFO(CheatEngine, "called");
|
||||
}
|
||||
|
||||
Result ICheatInterface::ReadCheatProcessMemoryUnsafe(u64 process_addr, std::span<u8> out_data,
|
||||
size_t size) {
|
||||
LOG_DEBUG(CheatEngine, "called, process_addr={}, size={}", process_addr, size);
|
||||
R_RETURN(cheat_process_manager.ReadCheatProcessMemoryUnsafe(process_addr, &out_data, size));
|
||||
}
|
||||
|
||||
Result ICheatInterface::WriteCheatProcessMemoryUnsafe(u64 process_addr, std::span<const u8> data,
|
||||
size_t size) {
|
||||
LOG_DEBUG(CheatEngine, "called, process_addr={}, size={}", process_addr, size);
|
||||
R_RETURN(cheat_process_manager.WriteCheatProcessMemoryUnsafe(process_addr, &data, size));
|
||||
}
|
||||
|
||||
Result ICheatInterface::PauseCheatProcessUnsafe() {
|
||||
LOG_INFO(CheatEngine, "called");
|
||||
R_RETURN(cheat_process_manager.PauseCheatProcessUnsafe());
|
||||
}
|
||||
|
||||
Result ICheatInterface::ResumeCheatProcessUnsafe() {
|
||||
LOG_INFO(CheatEngine, "called");
|
||||
R_RETURN(cheat_process_manager.ResumeCheatProcessUnsafe());
|
||||
}
|
||||
} // namespace Service::DMNT
|
||||
@@ -1,88 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/service/cmif_types.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Kernel {
|
||||
class KEvent;
|
||||
class KReadableEvent;
|
||||
} // namespace Kernel
|
||||
|
||||
namespace Kernel::Svc {
|
||||
struct MemoryInfo;
|
||||
}
|
||||
|
||||
namespace Service::DMNT {
|
||||
struct CheatDefinition;
|
||||
struct CheatEntry;
|
||||
struct CheatProcessMetadata;
|
||||
struct FrozenAddressEntry;
|
||||
class CheatProcessManager;
|
||||
|
||||
class ICheatInterface final : public ServiceFramework<ICheatInterface> {
|
||||
public:
|
||||
explicit ICheatInterface(Core::System& system_, CheatProcessManager& manager);
|
||||
~ICheatInterface() override;
|
||||
|
||||
private:
|
||||
Result HasCheatProcess(Out<bool> out_has_cheat);
|
||||
Result GetCheatProcessEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||
Result GetCheatProcessMetadata(Out<CheatProcessMetadata> out_metadata);
|
||||
Result ForceOpenCheatProcess();
|
||||
Result PauseCheatProcess();
|
||||
Result ResumeCheatProcess();
|
||||
Result ForceCloseCheatProcess();
|
||||
|
||||
Result GetCheatProcessMappingCount(Out<u64> out_count);
|
||||
Result GetCheatProcessMappings(
|
||||
Out<u64> out_count, u64 offset,
|
||||
OutArray<Kernel::Svc::MemoryInfo, BufferAttr_HipcMapAlias> out_mappings);
|
||||
Result ReadCheatProcessMemory(u64 address, u64 size,
|
||||
OutBuffer<BufferAttr_HipcMapAlias> out_buffer);
|
||||
Result WriteCheatProcessMemory(u64 address, u64 size, InBuffer<BufferAttr_HipcMapAlias> buffer);
|
||||
|
||||
Result QueryCheatProcessMemory(Out<Kernel::Svc::MemoryInfo> out_mapping, u64 address);
|
||||
Result GetCheatCount(Out<u64> out_count);
|
||||
Result GetCheats(Out<u64> out_count, u64 offset,
|
||||
OutArray<CheatEntry, BufferAttr_HipcMapAlias> out_cheats);
|
||||
Result GetCheatById(OutLargeData<CheatEntry, BufferAttr_HipcMapAlias> out_cheat, u32 cheat_id);
|
||||
Result ToggleCheat(u32 cheat_id);
|
||||
|
||||
Result AddCheat(Out<u32> out_cheat_id, bool enabled,
|
||||
InLargeData<CheatDefinition, BufferAttr_HipcMapAlias> cheat_definition);
|
||||
Result RemoveCheat(u32 cheat_id);
|
||||
Result ReadStaticRegister(Out<u64> out_value, u8 register_index);
|
||||
Result WriteStaticRegister(u8 register_index, u64 value);
|
||||
Result ResetStaticRegisters();
|
||||
Result SetMasterCheat(InLargeData<CheatDefinition, BufferAttr_HipcMapAlias> cheat_definition);
|
||||
Result GetFrozenAddressCount(Out<u64> out_count);
|
||||
Result GetFrozenAddresses(
|
||||
Out<u64> out_count, u64 offset,
|
||||
OutArray<FrozenAddressEntry, BufferAttr_HipcMapAlias> out_frozen_address);
|
||||
Result GetFrozenAddress(Out<FrozenAddressEntry> out_frozen_address_entry, u64 address);
|
||||
Result EnableFrozenAddress(Out<u64> out_value, u64 address, u64 width);
|
||||
Result DisableFrozenAddress(u64 address);
|
||||
|
||||
private:
|
||||
void InitializeCheatManager();
|
||||
|
||||
Result ReadCheatProcessMemoryUnsafe(u64 process_addr, std::span<u8> out_data, size_t size);
|
||||
Result WriteCheatProcessMemoryUnsafe(u64 process_addr, std::span<const u8> data, size_t size);
|
||||
|
||||
Result PauseCheatProcessUnsafe();
|
||||
Result ResumeCheatProcessUnsafe();
|
||||
|
||||
CheatProcessManager& cheat_process_manager;
|
||||
};
|
||||
} // namespace Service::DMNT
|
||||
@@ -1,121 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include <algorithm>
|
||||
#include <cctype>
|
||||
#include <cstring>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
|
||||
#include "core/hle/service/dmnt/cheat_parser.h"
|
||||
|
||||
#include "core/hle/service/dmnt/dmnt_types.h"
|
||||
|
||||
namespace Service::DMNT {
|
||||
CheatParser::CheatParser() {}
|
||||
|
||||
CheatParser::~CheatParser() = default;
|
||||
|
||||
std::vector<CheatEntry> CheatParser::Parse(std::string_view data) const {
|
||||
std::vector<CheatEntry> out(1);
|
||||
std::optional<u64> current_entry;
|
||||
|
||||
for (std::size_t i = 0; i < data.size(); ++i) {
|
||||
if (std::isspace(data[i])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (data[i] == '{') {
|
||||
current_entry = 0;
|
||||
|
||||
if (out[*current_entry].definition.num_opcodes > 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::size_t name_size{};
|
||||
const auto name = ExtractName(name_size, data, i + 1, '}');
|
||||
if (name.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::memcpy(out[*current_entry].definition.readable_name.data(), name.data(),
|
||||
std::min<std::size_t>(out[*current_entry].definition.readable_name.size(),
|
||||
name.size()));
|
||||
out[*current_entry]
|
||||
.definition.readable_name[out[*current_entry].definition.readable_name.size() - 1] =
|
||||
'\0';
|
||||
|
||||
i += name_size + 1;
|
||||
} else if (data[i] == '[') {
|
||||
current_entry = out.size();
|
||||
out.emplace_back();
|
||||
|
||||
std::size_t name_size{};
|
||||
const auto name = ExtractName(name_size, data, i + 1, ']');
|
||||
if (name.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::memcpy(out[*current_entry].definition.readable_name.data(), name.data(),
|
||||
std::min<std::size_t>(out[*current_entry].definition.readable_name.size(),
|
||||
name.size()));
|
||||
out[*current_entry]
|
||||
.definition.readable_name[out[*current_entry].definition.readable_name.size() - 1] =
|
||||
'\0';
|
||||
|
||||
i += name_size + 1;
|
||||
} else if (std::isxdigit(data[i])) {
|
||||
if (!current_entry || out[*current_entry].definition.num_opcodes >=
|
||||
out[*current_entry].definition.opcodes.size()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto hex = std::string(data.substr(i, 8));
|
||||
if (!std::all_of(hex.begin(), hex.end(), ::isxdigit)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto value = static_cast<u32>(std::strtoul(hex.c_str(), nullptr, 0x10));
|
||||
out[*current_entry].definition.opcodes[out[*current_entry].definition.num_opcodes++] =
|
||||
value;
|
||||
|
||||
i += 7; // 7 because the for loop will increment by 1 more
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
out[0].enabled = out[0].definition.num_opcodes > 0;
|
||||
out[0].cheat_id = 0;
|
||||
|
||||
for (u32 i = 1; i < out.size(); ++i) {
|
||||
out[i].enabled = out[i].definition.num_opcodes > 0;
|
||||
out[i].cheat_id = i;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string_view CheatParser::ExtractName(std::size_t& out_name_size, std::string_view data,
|
||||
std::size_t start_index, char match) const {
|
||||
auto end_index = start_index;
|
||||
while (data[end_index] != match) {
|
||||
++end_index;
|
||||
if (end_index > data.size()) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
out_name_size = end_index - start_index;
|
||||
|
||||
// Clamp name if it's too big
|
||||
if (out_name_size > sizeof(CheatDefinition::readable_name)) {
|
||||
end_index = start_index + sizeof(CheatDefinition::readable_name);
|
||||
}
|
||||
|
||||
return data.substr(start_index, end_index - start_index);
|
||||
}
|
||||
} // namespace Service::DMNT
|
||||
@@ -1,26 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string_view>
|
||||
#include <vector>
|
||||
|
||||
namespace Service::DMNT {
|
||||
struct CheatEntry;
|
||||
|
||||
class CheatParser final {
|
||||
public:
|
||||
CheatParser();
|
||||
~CheatParser();
|
||||
|
||||
std::vector<CheatEntry> Parse(std::string_view data) const;
|
||||
|
||||
private:
|
||||
std::string_view ExtractName(std::size_t& out_name_size, std::string_view data,
|
||||
std::size_t start_index, char match) const;
|
||||
};
|
||||
} // namespace Service::DMNT
|
||||
@@ -1,599 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "core/arm/debug.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/service/cmif_serialization.h"
|
||||
#include "core/hle/service/dmnt/cheat_process_manager.h"
|
||||
#include "core/hle/service/dmnt/cheat_virtual_machine.h"
|
||||
#include "core/hle/service/dmnt/dmnt_results.h"
|
||||
#include "core/hle/service/hid/hid_server.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
#include "hid_core/resource_manager.h"
|
||||
#include "hid_core/resources/npad/npad.h"
|
||||
|
||||
namespace Service::DMNT {
|
||||
constexpr auto CHEAT_ENGINE_NS = std::chrono::nanoseconds{1000000000 / 12};
|
||||
|
||||
CheatProcessManager::CheatProcessManager(Core::System& system_)
|
||||
: system{system_}, service_context{system_, "dmnt:cht"}, core_timing{system_.CoreTiming()} {
|
||||
update_event = Core::Timing::CreateEvent("CheatEngine::FrameCallback",
|
||||
[this](s64 time, std::chrono::nanoseconds ns_late)
|
||||
-> std::optional<std::chrono::nanoseconds> {
|
||||
FrameCallback(ns_late);
|
||||
return std::nullopt;
|
||||
});
|
||||
|
||||
for (size_t i = 0; i < MaxCheatCount; i++) {
|
||||
ResetCheatEntry(i);
|
||||
}
|
||||
|
||||
cheat_vm = std::make_unique<CheatVirtualMachine>(*this);
|
||||
|
||||
cheat_process_event = service_context.CreateEvent("CheatProcessManager::ProcessEvent");
|
||||
unsafe_break_event = service_context.CreateEvent("CheatProcessManager::ProcessEvent");
|
||||
}
|
||||
|
||||
CheatProcessManager::~CheatProcessManager() {
|
||||
service_context.CloseEvent(cheat_process_event);
|
||||
service_context.CloseEvent(unsafe_break_event);
|
||||
core_timing.UnscheduleEvent(update_event);
|
||||
}
|
||||
|
||||
void CheatProcessManager::SetVirtualMachine(std::unique_ptr<CheatVirtualMachine> vm) {
|
||||
if (vm) {
|
||||
cheat_vm = std::move(vm);
|
||||
SetNeedsReloadVm(true);
|
||||
}
|
||||
}
|
||||
|
||||
bool CheatProcessManager::HasActiveCheatProcess() {
|
||||
// Note: This function *MUST* be called only with the cheat lock held.
|
||||
bool has_cheat_process =
|
||||
cheat_process_debug_handle != InvalidHandle &&
|
||||
system.ApplicationProcess()->GetProcessId() == cheat_process_metadata.process_id;
|
||||
|
||||
if (!has_cheat_process) {
|
||||
CloseActiveCheatProcess();
|
||||
}
|
||||
|
||||
return has_cheat_process;
|
||||
}
|
||||
|
||||
void CheatProcessManager::CloseActiveCheatProcess() {
|
||||
if (cheat_process_debug_handle != InvalidHandle) {
|
||||
broken_unsafe = false;
|
||||
unsafe_break_event->Signal();
|
||||
core_timing.UnscheduleEvent(update_event);
|
||||
|
||||
// Close resources.
|
||||
cheat_process_debug_handle = InvalidHandle;
|
||||
|
||||
// Save cheat toggles.
|
||||
if (always_save_cheat_toggles || should_save_cheat_toggles) {
|
||||
// TODO: save cheat toggles
|
||||
should_save_cheat_toggles = false;
|
||||
}
|
||||
|
||||
cheat_process_metadata = {};
|
||||
|
||||
ResetAllCheatEntries();
|
||||
|
||||
{
|
||||
auto it = frozen_addresses_map.begin();
|
||||
while (it != frozen_addresses_map.end()) {
|
||||
it = frozen_addresses_map.erase(it);
|
||||
}
|
||||
}
|
||||
|
||||
cheat_process_event->Signal();
|
||||
}
|
||||
}
|
||||
|
||||
Result CheatProcessManager::EnsureCheatProcess() {
|
||||
R_UNLESS(HasActiveCheatProcess(), ResultCheatNotAttached);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
void CheatProcessManager::SetNeedsReloadVm(bool reload) {
|
||||
needs_reload_vm = reload;
|
||||
}
|
||||
|
||||
void CheatProcessManager::ResetCheatEntry(size_t i) {
|
||||
if (i < MaxCheatCount) {
|
||||
cheat_entries[i] = {};
|
||||
cheat_entries[i].cheat_id = static_cast<u32>(i);
|
||||
|
||||
SetNeedsReloadVm(true);
|
||||
}
|
||||
}
|
||||
|
||||
void CheatProcessManager::ResetAllCheatEntries() {
|
||||
for (size_t i = 0; i < MaxCheatCount; i++) {
|
||||
ResetCheatEntry(i);
|
||||
}
|
||||
|
||||
cheat_vm->ResetStaticRegisters();
|
||||
}
|
||||
|
||||
CheatEntry* CheatProcessManager::GetCheatEntryById(size_t i) {
|
||||
if (i < MaxCheatCount) {
|
||||
return cheat_entries.data() + i;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CheatEntry* CheatProcessManager::GetCheatEntryByReadableName(const char* readable_name) {
|
||||
for (size_t i = 1; i < MaxCheatCount; i++) {
|
||||
if (std::strncmp(cheat_entries[i].definition.readable_name.data(), readable_name,
|
||||
sizeof(cheat_entries[i].definition.readable_name)) == 0) {
|
||||
return cheat_entries.data() + i;
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CheatEntry* CheatProcessManager::GetFreeCheatEntry() {
|
||||
// Check all non-master cheats for availability.
|
||||
for (size_t i = 1; i < MaxCheatCount; i++) {
|
||||
if (cheat_entries[i].definition.num_opcodes == 0) {
|
||||
return cheat_entries.data() + i;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
bool CheatProcessManager::HasCheatProcess() {
|
||||
std::scoped_lock lk(cheat_lock);
|
||||
return HasActiveCheatProcess();
|
||||
}
|
||||
|
||||
Kernel::KReadableEvent& CheatProcessManager::GetCheatProcessEvent() const {
|
||||
return cheat_process_event->GetReadableEvent();
|
||||
}
|
||||
|
||||
Result CheatProcessManager::AttachToApplicationProcess(const std::array<u8, 0x20>& build_id,
|
||||
VAddr main_region_begin,
|
||||
u64 main_region_size) {
|
||||
std::scoped_lock lk(cheat_lock);
|
||||
|
||||
{
|
||||
if (this->HasActiveCheatProcess()) {
|
||||
this->CloseActiveCheatProcess();
|
||||
}
|
||||
}
|
||||
|
||||
cheat_process_metadata.process_id = system.ApplicationProcess()->GetProcessId();
|
||||
|
||||
{
|
||||
const auto& page_table = system.ApplicationProcess()->GetPageTable();
|
||||
cheat_process_metadata.program_id = system.GetApplicationProcessProgramID();
|
||||
cheat_process_metadata.heap_extents = {
|
||||
.base = GetInteger(page_table.GetHeapRegionStart()),
|
||||
.size = page_table.GetHeapRegionSize(),
|
||||
};
|
||||
cheat_process_metadata.aslr_extents = {
|
||||
.base = GetInteger(page_table.GetAliasCodeRegionStart()),
|
||||
.size = page_table.GetAliasCodeRegionSize(),
|
||||
};
|
||||
cheat_process_metadata.alias_extents = {
|
||||
.base = GetInteger(page_table.GetAliasRegionStart()),
|
||||
.size = page_table.GetAliasRegionSize(),
|
||||
};
|
||||
}
|
||||
|
||||
{
|
||||
cheat_process_metadata.main_nso_extents = {
|
||||
.base = main_region_begin,
|
||||
.size = main_region_size,
|
||||
};
|
||||
cheat_process_metadata.main_nso_build_id = build_id;
|
||||
}
|
||||
|
||||
cheat_process_debug_handle = cheat_process_metadata.process_id;
|
||||
|
||||
broken_unsafe = false;
|
||||
unsafe_break_event->Signal();
|
||||
|
||||
core_timing.ScheduleLoopingEvent(CHEAT_ENGINE_NS, CHEAT_ENGINE_NS, update_event);
|
||||
LOG_INFO(CheatEngine, "Cheat engine started");
|
||||
|
||||
// Signal to our fans.
|
||||
cheat_process_event->Signal();
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result CheatProcessManager::GetCheatProcessMetadata(CheatProcessMetadata& out_metadata) {
|
||||
std::scoped_lock lk(cheat_lock);
|
||||
R_TRY(EnsureCheatProcess());
|
||||
|
||||
out_metadata = cheat_process_metadata;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result CheatProcessManager::ForceOpenCheatProcess() {
|
||||
// R_RETURN(AttachToApplicationProcess(false));
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result CheatProcessManager::PauseCheatProcess() {
|
||||
std::scoped_lock lk(cheat_lock);
|
||||
|
||||
R_TRY(EnsureCheatProcess());
|
||||
R_RETURN(PauseCheatProcessUnsafe());
|
||||
}
|
||||
|
||||
Result CheatProcessManager::PauseCheatProcessUnsafe() {
|
||||
broken_unsafe = true;
|
||||
unsafe_break_event->Clear();
|
||||
if (system.ApplicationProcess()->IsSuspended()) {
|
||||
R_SUCCEED();
|
||||
}
|
||||
R_RETURN(system.ApplicationProcess()->SetActivity(Kernel::Svc::ProcessActivity::Paused));
|
||||
}
|
||||
|
||||
Result CheatProcessManager::ResumeCheatProcess() {
|
||||
std::scoped_lock lk(cheat_lock);
|
||||
|
||||
R_TRY(EnsureCheatProcess());
|
||||
R_RETURN(ResumeCheatProcessUnsafe());
|
||||
}
|
||||
|
||||
Result CheatProcessManager::ResumeCheatProcessUnsafe() {
|
||||
broken_unsafe = true;
|
||||
unsafe_break_event->Clear();
|
||||
if (!system.ApplicationProcess()->IsSuspended()) {
|
||||
R_SUCCEED();
|
||||
}
|
||||
system.ApplicationProcess()->SetActivity(Kernel::Svc::ProcessActivity::Runnable);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result CheatProcessManager::ForceCloseCheatProcess() {
|
||||
CloseActiveCheatProcess();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result CheatProcessManager::GetCheatProcessMappingCount(u64& out_count) {
|
||||
std::scoped_lock lk(cheat_lock);
|
||||
R_TRY(this->EnsureCheatProcess());
|
||||
|
||||
// TODO: Call svc::QueryDebugProcessMemory
|
||||
|
||||
out_count = 0;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result CheatProcessManager::GetCheatProcessMappings(
|
||||
u64& out_count, u64 offset, std::span<Kernel::Svc::MemoryInfo> out_mappings) {
|
||||
std::scoped_lock lk(cheat_lock);
|
||||
R_TRY(this->EnsureCheatProcess());
|
||||
|
||||
// TODO: Call svc::QueryDebugProcessMemory
|
||||
|
||||
out_count = 0;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result CheatProcessManager::ReadCheatProcessMemory(u64 process_address, u64 size,
|
||||
std::span<u8> out_data) {
|
||||
std::scoped_lock lk(cheat_lock);
|
||||
|
||||
R_TRY(EnsureCheatProcess());
|
||||
R_RETURN(ReadCheatProcessMemoryUnsafe(process_address, &out_data, size));
|
||||
}
|
||||
|
||||
Result CheatProcessManager::ReadCheatProcessMemoryUnsafe(u64 process_address, void* out_data,
|
||||
size_t size) {
|
||||
if (!system.ApplicationMemory().IsValidVirtualAddress(process_address)) {
|
||||
std::memset(out_data, 0, size);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
system.ApplicationMemory().ReadBlock(process_address, out_data, size);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result CheatProcessManager::WriteCheatProcessMemory(u64 process_address, u64 size,
|
||||
std::span<const u8> data) {
|
||||
std::scoped_lock lk(cheat_lock);
|
||||
|
||||
R_TRY(EnsureCheatProcess());
|
||||
R_RETURN(WriteCheatProcessMemoryUnsafe(process_address, &data, size));
|
||||
}
|
||||
|
||||
Result CheatProcessManager::WriteCheatProcessMemoryUnsafe(u64 process_address, const void* data,
|
||||
size_t size) {
|
||||
if (!system.ApplicationMemory().IsValidVirtualAddress(process_address)) {
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
if (system.ApplicationMemory().WriteBlock(process_address, data, size)) {
|
||||
Core::InvalidateInstructionCacheRange(system.ApplicationProcess(), process_address, size);
|
||||
}
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result CheatProcessManager::QueryCheatProcessMemory(Out<Kernel::Svc::MemoryInfo> mapping,
|
||||
u64 address) {
|
||||
std::scoped_lock lk(cheat_lock);
|
||||
R_TRY(this->EnsureCheatProcess());
|
||||
|
||||
// TODO: Call svc::QueryDebugProcessMemory
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result CheatProcessManager::GetCheatCount(u64& out_count) {
|
||||
std::scoped_lock lk(cheat_lock);
|
||||
R_TRY(EnsureCheatProcess());
|
||||
|
||||
out_count = std::count_if(cheat_entries.begin(), cheat_entries.end(),
|
||||
[](const auto& entry) { return entry.definition.num_opcodes != 0; });
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result CheatProcessManager::GetCheats(u64& out_count, u64 offset,
|
||||
std::span<CheatEntry> out_cheats) {
|
||||
std::scoped_lock lk(cheat_lock);
|
||||
R_TRY(EnsureCheatProcess());
|
||||
|
||||
size_t count = 0, total_count = 0;
|
||||
for (size_t i = 0; i < MaxCheatCount && count < out_cheats.size(); i++) {
|
||||
if (cheat_entries[i].definition.num_opcodes) {
|
||||
total_count++;
|
||||
if (total_count > offset) {
|
||||
out_cheats[count++] = cheat_entries[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
out_count = count;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result CheatProcessManager::GetCheatById(CheatEntry* out_cheat, u32 cheat_id) {
|
||||
std::scoped_lock lk(cheat_lock);
|
||||
R_TRY(EnsureCheatProcess());
|
||||
|
||||
const CheatEntry* entry = GetCheatEntryById(cheat_id);
|
||||
R_UNLESS(entry != nullptr, ResultCheatUnknownId);
|
||||
R_UNLESS(entry->definition.num_opcodes != 0, ResultCheatUnknownId);
|
||||
|
||||
*out_cheat = *entry;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result CheatProcessManager::ToggleCheat(u32 cheat_id) {
|
||||
std::scoped_lock lk(cheat_lock);
|
||||
R_TRY(EnsureCheatProcess());
|
||||
|
||||
CheatEntry* entry = GetCheatEntryById(cheat_id);
|
||||
R_UNLESS(entry != nullptr, ResultCheatUnknownId);
|
||||
R_UNLESS(entry->definition.num_opcodes != 0, ResultCheatUnknownId);
|
||||
|
||||
R_UNLESS(cheat_id != 0, ResultCheatCannotDisable);
|
||||
|
||||
entry->enabled = !entry->enabled;
|
||||
|
||||
SetNeedsReloadVm(true);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result CheatProcessManager::AddCheat(u32& out_cheat_id, bool enabled,
|
||||
const CheatDefinition& cheat_definition) {
|
||||
std::scoped_lock lk(cheat_lock);
|
||||
R_TRY(EnsureCheatProcess());
|
||||
|
||||
R_UNLESS(cheat_definition.num_opcodes != 0, ResultCheatInvalid);
|
||||
R_UNLESS(cheat_definition.num_opcodes <= cheat_definition.opcodes.size(), ResultCheatInvalid);
|
||||
|
||||
CheatEntry* new_entry = GetFreeCheatEntry();
|
||||
R_UNLESS(new_entry != nullptr, ResultCheatOutOfResource);
|
||||
|
||||
new_entry->enabled = enabled;
|
||||
new_entry->definition = cheat_definition;
|
||||
|
||||
SetNeedsReloadVm(true);
|
||||
|
||||
out_cheat_id = new_entry->cheat_id;
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result CheatProcessManager::RemoveCheat(u32 cheat_id) {
|
||||
std::scoped_lock lk(cheat_lock);
|
||||
R_TRY(EnsureCheatProcess());
|
||||
R_UNLESS(cheat_id < MaxCheatCount, ResultCheatUnknownId);
|
||||
|
||||
ResetCheatEntry(cheat_id);
|
||||
SetNeedsReloadVm(true);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result CheatProcessManager::ReadStaticRegister(u64& out_value, u64 register_index) {
|
||||
std::scoped_lock lk(cheat_lock);
|
||||
R_TRY(EnsureCheatProcess());
|
||||
R_UNLESS(register_index < CheatVirtualMachine::NumStaticRegisters, ResultCheatInvalid);
|
||||
|
||||
out_value = cheat_vm->GetStaticRegister(register_index);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result CheatProcessManager::WriteStaticRegister(u64 register_index, u64 value) {
|
||||
std::scoped_lock lk(cheat_lock);
|
||||
R_TRY(EnsureCheatProcess());
|
||||
R_UNLESS(register_index < CheatVirtualMachine::NumStaticRegisters, ResultCheatInvalid);
|
||||
|
||||
cheat_vm->SetStaticRegister(register_index, value);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result CheatProcessManager::ResetStaticRegisters() {
|
||||
std::scoped_lock lk(cheat_lock);
|
||||
R_TRY(EnsureCheatProcess());
|
||||
|
||||
cheat_vm->ResetStaticRegisters();
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result CheatProcessManager::SetMasterCheat(const CheatDefinition& cheat_definition) {
|
||||
std::scoped_lock lk(cheat_lock);
|
||||
R_TRY(EnsureCheatProcess());
|
||||
|
||||
R_UNLESS(cheat_definition.num_opcodes != 0, ResultCheatInvalid);
|
||||
R_UNLESS(cheat_definition.num_opcodes <= cheat_definition.opcodes.size(), ResultCheatInvalid);
|
||||
|
||||
cheat_entries[0] = {
|
||||
.enabled = true,
|
||||
.definition = cheat_definition,
|
||||
};
|
||||
|
||||
SetNeedsReloadVm(true);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result CheatProcessManager::GetFrozenAddressCount(u64& out_count) {
|
||||
std::scoped_lock lk(cheat_lock);
|
||||
R_TRY(EnsureCheatProcess());
|
||||
|
||||
out_count = std::distance(frozen_addresses_map.begin(), frozen_addresses_map.end());
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result CheatProcessManager::GetFrozenAddresses(u64& out_count, u64 offset,
|
||||
std::span<FrozenAddressEntry> out_frozen_address) {
|
||||
std::scoped_lock lk(cheat_lock);
|
||||
R_TRY(EnsureCheatProcess());
|
||||
|
||||
u64 total_count = 0, written_count = 0;
|
||||
for (const auto& [address, value] : frozen_addresses_map) {
|
||||
if (written_count >= out_frozen_address.size()) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (offset <= total_count) {
|
||||
out_frozen_address[written_count].address = address;
|
||||
out_frozen_address[written_count].value = value;
|
||||
written_count++;
|
||||
}
|
||||
total_count++;
|
||||
}
|
||||
|
||||
out_count = written_count;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result CheatProcessManager::GetFrozenAddress(FrozenAddressEntry& out_frozen_address_entry,
|
||||
u64 address) {
|
||||
std::scoped_lock lk(cheat_lock);
|
||||
R_TRY(EnsureCheatProcess());
|
||||
|
||||
const auto it = frozen_addresses_map.find(address);
|
||||
R_UNLESS(it != frozen_addresses_map.end(), ResultFrozenAddressNotFound);
|
||||
|
||||
out_frozen_address_entry = {
|
||||
.address = it->first,
|
||||
.value = it->second,
|
||||
};
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result CheatProcessManager::EnableFrozenAddress(u64& out_value, u64 address, u64 width) {
|
||||
std::scoped_lock lk(cheat_lock);
|
||||
R_TRY(EnsureCheatProcess());
|
||||
|
||||
const auto it = frozen_addresses_map.find(address);
|
||||
R_UNLESS(it == frozen_addresses_map.end(), ResultFrozenAddressAlreadyExists);
|
||||
|
||||
FrozenAddressValue value{};
|
||||
value.width = static_cast<u8>(width);
|
||||
R_TRY(ReadCheatProcessMemoryUnsafe(address, &value.value, width));
|
||||
|
||||
frozen_addresses_map.insert({address, value});
|
||||
out_value = value.value;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result CheatProcessManager::DisableFrozenAddress(u64 address) {
|
||||
std::scoped_lock lk(cheat_lock);
|
||||
R_TRY(EnsureCheatProcess());
|
||||
|
||||
const auto it = frozen_addresses_map.find(address);
|
||||
R_UNLESS(it != frozen_addresses_map.end(), ResultFrozenAddressNotFound);
|
||||
|
||||
frozen_addresses_map.erase(it);
|
||||
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
u64 CheatProcessManager::HidKeysDown() const {
|
||||
const auto hid = system.ServiceManager().GetService<Service::HID::IHidServer>("hid");
|
||||
if (hid == nullptr) {
|
||||
LOG_WARNING(CheatEngine, "Attempted to read input state, but hid is not initialized!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto applet_resource = hid->GetResourceManager();
|
||||
if (applet_resource == nullptr || applet_resource->GetNpad() == nullptr) {
|
||||
LOG_WARNING(CheatEngine,
|
||||
"Attempted to read input state, but applet resource is not initialized!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto press_state = applet_resource->GetNpad()->GetAndResetPressState();
|
||||
return static_cast<u64>(press_state & Core::HID::NpadButton::All);
|
||||
}
|
||||
|
||||
void CheatProcessManager::DebugLog(u8 id, u64 value) const {
|
||||
LOG_INFO(CheatEngine, "Cheat triggered DebugLog: ID '{:01X}' Value '{:016X}'", id, value);
|
||||
}
|
||||
|
||||
void CheatProcessManager::CommandLog(std::string_view data) const {
|
||||
LOG_DEBUG(CheatEngine, "[DmntCheatVm]: {}",
|
||||
data.back() == '\n' ? data.substr(0, data.size() - 1) : data);
|
||||
}
|
||||
|
||||
void CheatProcessManager::FrameCallback(std::chrono::nanoseconds ns_late) {
|
||||
std::scoped_lock lk(cheat_lock);
|
||||
|
||||
if (cheat_vm == nullptr) {
|
||||
LOG_DEBUG(CheatEngine, "FrameCallback: VM is null");
|
||||
return;
|
||||
}
|
||||
|
||||
if (needs_reload_vm) {
|
||||
LOG_INFO(CheatEngine, "Reloading cheat VM with {} entries", cheat_entries.size());
|
||||
|
||||
size_t enabled_count = 0;
|
||||
for (const auto& entry : cheat_entries) {
|
||||
if (entry.enabled && entry.definition.num_opcodes > 0) {
|
||||
enabled_count++;
|
||||
LOG_INFO(CheatEngine, " Cheat '{}': {} opcodes, enabled={}",
|
||||
entry.definition.readable_name.data(),
|
||||
entry.definition.num_opcodes, entry.enabled);
|
||||
}
|
||||
}
|
||||
LOG_INFO(CheatEngine, "Total enabled cheats: {}", enabled_count);
|
||||
|
||||
cheat_vm->LoadProgram(cheat_entries);
|
||||
LOG_INFO(CheatEngine, "Cheat VM loaded, program size: {}", cheat_vm->GetProgramSize());
|
||||
needs_reload_vm = false;
|
||||
}
|
||||
|
||||
if (cheat_vm->GetProgramSize() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
cheat_vm->Execute(cheat_process_metadata);
|
||||
}
|
||||
} // namespace Service::DMNT
|
||||
@@ -1,126 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <map>
|
||||
#include <span>
|
||||
|
||||
#include "core/hle/service/cmif_types.h"
|
||||
#include "core/hle/service/dmnt/dmnt_types.h"
|
||||
#include "core/hle/service/kernel_helpers.h"
|
||||
#include "core/hle/service/service.h"
|
||||
|
||||
#include "common/intrusive_red_black_tree.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Kernel {
|
||||
class KEvent;
|
||||
class KReadableEvent;
|
||||
} // namespace Kernel
|
||||
|
||||
namespace Kernel::Svc {
|
||||
struct MemoryInfo;
|
||||
}
|
||||
|
||||
namespace Service::DMNT {
|
||||
class CheatVirtualMachine;
|
||||
|
||||
class CheatProcessManager final {
|
||||
public:
|
||||
static constexpr size_t MaxCheatCount = 0x80;
|
||||
static constexpr size_t MaxFrozenAddressCount = 0x80;
|
||||
|
||||
CheatProcessManager(Core::System& system_);
|
||||
~CheatProcessManager();
|
||||
|
||||
void SetVirtualMachine(std::unique_ptr<CheatVirtualMachine> vm);
|
||||
|
||||
bool HasCheatProcess();
|
||||
Kernel::KReadableEvent& GetCheatProcessEvent() const;
|
||||
Result GetCheatProcessMetadata(CheatProcessMetadata& out_metadata);
|
||||
Result AttachToApplicationProcess(const std::array<u8, 0x20>& build_id, VAddr main_region_begin,
|
||||
u64 main_region_size);
|
||||
Result ForceOpenCheatProcess();
|
||||
Result PauseCheatProcess();
|
||||
Result PauseCheatProcessUnsafe();
|
||||
Result ResumeCheatProcess();
|
||||
Result ResumeCheatProcessUnsafe();
|
||||
Result ForceCloseCheatProcess();
|
||||
|
||||
Result GetCheatProcessMappingCount(u64& out_count);
|
||||
Result GetCheatProcessMappings(u64& out_count, u64 offset,
|
||||
std::span<Kernel::Svc::MemoryInfo> out_mappings);
|
||||
Result ReadCheatProcessMemory(u64 process_address, u64 size, std::span<u8> out_data);
|
||||
Result ReadCheatProcessMemoryUnsafe(u64 process_address, void* out_data, size_t size);
|
||||
Result WriteCheatProcessMemory(u64 process_address, u64 size, std::span<const u8> data);
|
||||
Result WriteCheatProcessMemoryUnsafe(u64 process_address, const void* data, size_t size);
|
||||
|
||||
Result QueryCheatProcessMemory(Out<Kernel::Svc::MemoryInfo> mapping, u64 address);
|
||||
Result GetCheatCount(u64& out_count);
|
||||
Result GetCheats(u64& out_count, u64 offset, std::span<CheatEntry> out_cheats);
|
||||
Result GetCheatById(CheatEntry* out_cheat, u32 cheat_id);
|
||||
Result ToggleCheat(u32 cheat_id);
|
||||
|
||||
Result AddCheat(u32& out_cheat_id, bool enabled, const CheatDefinition& cheat_definition);
|
||||
Result RemoveCheat(u32 cheat_id);
|
||||
Result ReadStaticRegister(u64& out_value, u64 register_index);
|
||||
Result WriteStaticRegister(u64 register_index, u64 value);
|
||||
Result ResetStaticRegisters();
|
||||
Result SetMasterCheat(const CheatDefinition& cheat_definition);
|
||||
Result GetFrozenAddressCount(u64& out_count);
|
||||
Result GetFrozenAddresses(u64& out_count, u64 offset,
|
||||
std::span<FrozenAddressEntry> out_frozen_address);
|
||||
Result GetFrozenAddress(FrozenAddressEntry& out_frozen_address_entry, u64 address);
|
||||
Result EnableFrozenAddress(u64& out_value, u64 address, u64 width);
|
||||
Result DisableFrozenAddress(u64 address);
|
||||
|
||||
u64 HidKeysDown() const;
|
||||
void DebugLog(u8 id, u64 value) const;
|
||||
void CommandLog(std::string_view data) const;
|
||||
|
||||
private:
|
||||
bool HasActiveCheatProcess();
|
||||
void CloseActiveCheatProcess();
|
||||
Result EnsureCheatProcess();
|
||||
void SetNeedsReloadVm(bool reload);
|
||||
void ResetCheatEntry(size_t i);
|
||||
void ResetAllCheatEntries();
|
||||
CheatEntry* GetCheatEntryById(size_t i);
|
||||
CheatEntry* GetCheatEntryByReadableName(const char* readable_name);
|
||||
CheatEntry* GetFreeCheatEntry();
|
||||
|
||||
void FrameCallback(std::chrono::nanoseconds ns_late);
|
||||
|
||||
static constexpr u64 InvalidHandle = 0;
|
||||
|
||||
mutable std::mutex cheat_lock;
|
||||
Kernel::KEvent* unsafe_break_event;
|
||||
|
||||
Kernel::KEvent* cheat_process_event;
|
||||
u64 cheat_process_debug_handle = InvalidHandle;
|
||||
CheatProcessMetadata cheat_process_metadata = {};
|
||||
|
||||
bool broken_unsafe = false;
|
||||
bool needs_reload_vm = false;
|
||||
std::unique_ptr<CheatVirtualMachine> cheat_vm;
|
||||
|
||||
bool enable_cheats_by_default = true;
|
||||
bool always_save_cheat_toggles = false;
|
||||
bool should_save_cheat_toggles = false;
|
||||
std::array<CheatEntry, MaxCheatCount> cheat_entries = {};
|
||||
// TODO: Replace with IntrusiveRedBlackTree
|
||||
std::map<u64, FrozenAddressValue> frozen_addresses_map = {};
|
||||
|
||||
Core::System& system;
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
std::shared_ptr<Core::Timing::EventType> update_event;
|
||||
Core::Timing::CoreTiming& core_timing;
|
||||
};
|
||||
} // namespace Service::DMNT
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,323 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <span>
|
||||
#include <variant>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/service/dmnt/dmnt_types.h"
|
||||
|
||||
namespace Service::DMNT {
|
||||
class CheatProcessManager;
|
||||
|
||||
enum class CheatVmOpcodeType : u32 {
|
||||
StoreStatic = 0,
|
||||
BeginConditionalBlock = 1,
|
||||
EndConditionalBlock = 2,
|
||||
ControlLoop = 3,
|
||||
LoadRegisterStatic = 4,
|
||||
LoadRegisterMemory = 5,
|
||||
StoreStaticToAddress = 6,
|
||||
PerformArithmeticStatic = 7,
|
||||
BeginKeypressConditionalBlock = 8,
|
||||
|
||||
// These are not implemented by Gateway's VM.
|
||||
PerformArithmeticRegister = 9,
|
||||
StoreRegisterToAddress = 10,
|
||||
Reserved11 = 11,
|
||||
|
||||
// This is a meta entry, and not a real opcode.
|
||||
// This is to facilitate multi-nybble instruction decoding.
|
||||
ExtendedWidth = 12,
|
||||
|
||||
// Extended width opcodes.
|
||||
BeginRegisterConditionalBlock = 0xC0,
|
||||
SaveRestoreRegister = 0xC1,
|
||||
SaveRestoreRegisterMask = 0xC2,
|
||||
ReadWriteStaticRegister = 0xC3,
|
||||
|
||||
// This is a meta entry, and not a real opcode.
|
||||
// This is to facilitate multi-nybble instruction decoding.
|
||||
DoubleExtendedWidth = 0xF0,
|
||||
|
||||
// Double-extended width opcodes.
|
||||
PauseProcess = 0xFF0,
|
||||
ResumeProcess = 0xFF1,
|
||||
DebugLog = 0xFFF,
|
||||
};
|
||||
|
||||
enum class MemoryAccessType : u32 {
|
||||
MainNso = 0,
|
||||
Heap = 1,
|
||||
Alias = 2,
|
||||
Aslr = 3,
|
||||
};
|
||||
|
||||
enum class ConditionalComparisonType : u32 {
|
||||
GT = 1,
|
||||
GE = 2,
|
||||
LT = 3,
|
||||
LE = 4,
|
||||
EQ = 5,
|
||||
NE = 6,
|
||||
};
|
||||
|
||||
enum class RegisterArithmeticType : u32 {
|
||||
Addition = 0,
|
||||
Subtraction = 1,
|
||||
Multiplication = 2,
|
||||
LeftShift = 3,
|
||||
RightShift = 4,
|
||||
|
||||
// These are not supported by Gateway's VM.
|
||||
LogicalAnd = 5,
|
||||
LogicalOr = 6,
|
||||
LogicalNot = 7,
|
||||
LogicalXor = 8,
|
||||
|
||||
None = 9,
|
||||
};
|
||||
|
||||
enum class StoreRegisterOffsetType : u32 {
|
||||
None = 0,
|
||||
Reg = 1,
|
||||
Imm = 2,
|
||||
MemReg = 3,
|
||||
MemImm = 4,
|
||||
MemImmReg = 5,
|
||||
};
|
||||
|
||||
enum class CompareRegisterValueType : u32 {
|
||||
MemoryRelAddr = 0,
|
||||
MemoryOfsReg = 1,
|
||||
RegisterRelAddr = 2,
|
||||
RegisterOfsReg = 3,
|
||||
StaticValue = 4,
|
||||
OtherRegister = 5,
|
||||
};
|
||||
|
||||
enum class SaveRestoreRegisterOpType : u32 {
|
||||
Restore = 0,
|
||||
Save = 1,
|
||||
ClearSaved = 2,
|
||||
ClearRegs = 3,
|
||||
};
|
||||
|
||||
enum class DebugLogValueType : u32 {
|
||||
MemoryRelAddr = 0,
|
||||
MemoryOfsReg = 1,
|
||||
RegisterRelAddr = 2,
|
||||
RegisterOfsReg = 3,
|
||||
RegisterValue = 4,
|
||||
};
|
||||
|
||||
union VmInt {
|
||||
u8 bit8;
|
||||
u16 bit16;
|
||||
u32 bit32;
|
||||
u64 bit64;
|
||||
};
|
||||
|
||||
struct StoreStaticOpcode {
|
||||
u32 bit_width{};
|
||||
MemoryAccessType mem_type{};
|
||||
u32 offset_register{};
|
||||
u64 rel_address{};
|
||||
VmInt value{};
|
||||
};
|
||||
|
||||
struct BeginConditionalOpcode {
|
||||
u32 bit_width{};
|
||||
MemoryAccessType mem_type{};
|
||||
ConditionalComparisonType cond_type{};
|
||||
u64 rel_address{};
|
||||
VmInt value{};
|
||||
};
|
||||
|
||||
struct EndConditionalOpcode {
|
||||
bool is_else;
|
||||
};
|
||||
|
||||
struct ControlLoopOpcode {
|
||||
bool start_loop{};
|
||||
u32 reg_index{};
|
||||
u32 num_iters{};
|
||||
};
|
||||
|
||||
struct LoadRegisterStaticOpcode {
|
||||
u32 reg_index{};
|
||||
u64 value{};
|
||||
};
|
||||
|
||||
struct LoadRegisterMemoryOpcode {
|
||||
u32 bit_width{};
|
||||
MemoryAccessType mem_type{};
|
||||
u32 reg_index{};
|
||||
bool load_from_reg{};
|
||||
u64 rel_address{};
|
||||
};
|
||||
|
||||
struct StoreStaticToAddressOpcode {
|
||||
u32 bit_width{};
|
||||
u32 reg_index{};
|
||||
bool increment_reg{};
|
||||
bool add_offset_reg{};
|
||||
u32 offset_reg_index{};
|
||||
u64 value{};
|
||||
};
|
||||
|
||||
struct PerformArithmeticStaticOpcode {
|
||||
u32 bit_width{};
|
||||
u32 reg_index{};
|
||||
RegisterArithmeticType math_type{};
|
||||
u32 value{};
|
||||
};
|
||||
|
||||
struct BeginKeypressConditionalOpcode {
|
||||
u32 key_mask{};
|
||||
};
|
||||
|
||||
struct PerformArithmeticRegisterOpcode {
|
||||
u32 bit_width{};
|
||||
RegisterArithmeticType math_type{};
|
||||
u32 dst_reg_index{};
|
||||
u32 src_reg_1_index{};
|
||||
u32 src_reg_2_index{};
|
||||
bool has_immediate{};
|
||||
VmInt value{};
|
||||
};
|
||||
|
||||
struct StoreRegisterToAddressOpcode {
|
||||
u32 bit_width{};
|
||||
u32 str_reg_index{};
|
||||
u32 addr_reg_index{};
|
||||
bool increment_reg{};
|
||||
StoreRegisterOffsetType ofs_type{};
|
||||
MemoryAccessType mem_type{};
|
||||
u32 ofs_reg_index{};
|
||||
u64 rel_address{};
|
||||
};
|
||||
|
||||
struct BeginRegisterConditionalOpcode {
|
||||
u32 bit_width{};
|
||||
ConditionalComparisonType cond_type{};
|
||||
u32 val_reg_index{};
|
||||
CompareRegisterValueType comp_type{};
|
||||
MemoryAccessType mem_type{};
|
||||
u32 addr_reg_index{};
|
||||
u32 other_reg_index{};
|
||||
u32 ofs_reg_index{};
|
||||
u64 rel_address{};
|
||||
VmInt value{};
|
||||
};
|
||||
|
||||
struct SaveRestoreRegisterOpcode {
|
||||
u32 dst_index{};
|
||||
u32 src_index{};
|
||||
SaveRestoreRegisterOpType op_type{};
|
||||
};
|
||||
|
||||
struct SaveRestoreRegisterMaskOpcode {
|
||||
SaveRestoreRegisterOpType op_type{};
|
||||
std::array<bool, 0x10> should_operate{};
|
||||
};
|
||||
|
||||
struct ReadWriteStaticRegisterOpcode {
|
||||
u32 static_idx{};
|
||||
u32 idx{};
|
||||
};
|
||||
|
||||
struct PauseProcessOpcode {};
|
||||
|
||||
struct ResumeProcessOpcode {};
|
||||
|
||||
struct DebugLogOpcode {
|
||||
u32 bit_width{};
|
||||
u32 log_id{};
|
||||
DebugLogValueType val_type{};
|
||||
MemoryAccessType mem_type{};
|
||||
u32 addr_reg_index{};
|
||||
u32 val_reg_index{};
|
||||
u32 ofs_reg_index{};
|
||||
u64 rel_address{};
|
||||
};
|
||||
|
||||
struct UnrecognizedInstruction {
|
||||
CheatVmOpcodeType opcode{};
|
||||
};
|
||||
|
||||
struct CheatVmOpcode {
|
||||
bool begin_conditional_block{};
|
||||
std::variant<StoreStaticOpcode, BeginConditionalOpcode, EndConditionalOpcode, ControlLoopOpcode,
|
||||
LoadRegisterStaticOpcode, LoadRegisterMemoryOpcode, StoreStaticToAddressOpcode,
|
||||
PerformArithmeticStaticOpcode, BeginKeypressConditionalOpcode,
|
||||
PerformArithmeticRegisterOpcode, StoreRegisterToAddressOpcode,
|
||||
BeginRegisterConditionalOpcode, SaveRestoreRegisterOpcode,
|
||||
SaveRestoreRegisterMaskOpcode, ReadWriteStaticRegisterOpcode, PauseProcessOpcode,
|
||||
ResumeProcessOpcode, DebugLogOpcode, UnrecognizedInstruction>
|
||||
opcode{};
|
||||
};
|
||||
|
||||
class CheatVirtualMachine {
|
||||
public:
|
||||
static constexpr std::size_t MaximumProgramOpcodeCount = 0x400;
|
||||
static constexpr std::size_t NumRegisters = 0x10;
|
||||
static constexpr std::size_t NumReadableStaticRegisters = 0x80;
|
||||
static constexpr std::size_t NumWritableStaticRegisters = 0x80;
|
||||
static constexpr std::size_t NumStaticRegisters =
|
||||
NumReadableStaticRegisters + NumWritableStaticRegisters;
|
||||
|
||||
explicit CheatVirtualMachine(CheatProcessManager& cheat_manager);
|
||||
~CheatVirtualMachine();
|
||||
|
||||
std::size_t GetProgramSize() const {
|
||||
return this->num_opcodes;
|
||||
}
|
||||
|
||||
bool LoadProgram(std::span<const CheatEntry> cheats);
|
||||
void Execute(const CheatProcessMetadata& metadata);
|
||||
|
||||
u64 GetStaticRegister(std::size_t register_index) const {
|
||||
return static_registers[register_index];
|
||||
}
|
||||
|
||||
void SetStaticRegister(std::size_t register_index, u64 value) {
|
||||
static_registers[register_index] = value;
|
||||
}
|
||||
|
||||
void ResetStaticRegisters() {
|
||||
static_registers = {};
|
||||
}
|
||||
|
||||
private:
|
||||
bool DecodeNextOpcode(CheatVmOpcode& out);
|
||||
void SkipConditionalBlock(bool is_if);
|
||||
void ResetState();
|
||||
|
||||
// For implementing the DebugLog opcode.
|
||||
void DebugLog(u32 log_id, u64 value) const;
|
||||
|
||||
void LogOpcode(const CheatVmOpcode& opcode) const;
|
||||
|
||||
static u64 GetVmInt(VmInt value, u32 bit_width);
|
||||
static u64 GetCheatProcessAddress(const CheatProcessMetadata& metadata,
|
||||
MemoryAccessType mem_type, u64 rel_address);
|
||||
|
||||
CheatProcessManager& manager;
|
||||
|
||||
std::size_t num_opcodes = 0;
|
||||
std::size_t instruction_ptr = 0;
|
||||
std::size_t condition_depth = 0;
|
||||
bool decode_success = false;
|
||||
std::array<u32, MaximumProgramOpcodeCount> program{};
|
||||
std::array<u64, NumRegisters> registers{};
|
||||
std::array<u64, NumRegisters> saved_values{};
|
||||
std::array<u64, NumStaticRegisters> static_registers{};
|
||||
std::array<std::size_t, NumRegisters> loop_tops{};
|
||||
};
|
||||
}// namespace Service::DMNT
|
||||
@@ -1,26 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#include "core/core.h"
|
||||
#include "core/hle/service/dmnt/cheat_interface.h"
|
||||
#include "core/hle/service/dmnt/cheat_process_manager.h"
|
||||
#include "core/hle/service/dmnt/cheat_virtual_machine.h"
|
||||
#include "core/hle/service/dmnt/dmnt.h"
|
||||
#include "core/hle/service/server_manager.h"
|
||||
|
||||
namespace Service::DMNT {
|
||||
void LoopProcess(Core::System& system) {
|
||||
auto server_manager = std::make_unique<ServerManager>(system);
|
||||
|
||||
auto& cheat_manager = system.GetCheatManager();
|
||||
auto cheat_vm = std::make_unique<CheatVirtualMachine>(cheat_manager);
|
||||
cheat_manager.SetVirtualMachine(std::move(cheat_vm));
|
||||
|
||||
server_manager->RegisterNamedService("dmnt:cht",
|
||||
std::make_shared<ICheatInterface>(system, cheat_manager));
|
||||
ServerManager::RunServer(std::move(server_manager));
|
||||
}
|
||||
} // namespace Service::DMNT
|
||||
@@ -1,15 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
};
|
||||
|
||||
namespace Service::DMNT {
|
||||
void LoopProcess(Core::System& system);
|
||||
} // namespace Service::DMNT
|
||||
@@ -1,26 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "core/hle/result.h"
|
||||
|
||||
namespace Service::DMNT {
|
||||
constexpr Result ResultDebuggingDisabled(ErrorModule::DMNT, 2);
|
||||
|
||||
constexpr Result ResultCheatNotAttached(ErrorModule::DMNT, 6500);
|
||||
constexpr Result ResultCheatNullBuffer(ErrorModule::DMNT, 6501);
|
||||
constexpr Result ResultCheatInvalidBuffer(ErrorModule::DMNT, 6502);
|
||||
constexpr Result ResultCheatUnknownId(ErrorModule::DMNT, 6503);
|
||||
constexpr Result ResultCheatOutOfResource(ErrorModule::DMNT, 6504);
|
||||
constexpr Result ResultCheatInvalid(ErrorModule::DMNT, 6505);
|
||||
constexpr Result ResultCheatCannotDisable(ErrorModule::DMNT, 6506);
|
||||
constexpr Result ResultFrozenAddressInvalidWidth(ErrorModule::DMNT, 6600);
|
||||
constexpr Result ResultFrozenAddressAlreadyExists(ErrorModule::DMNT, 6601);
|
||||
constexpr Result ResultFrozenAddressNotFound(ErrorModule::DMNT, 6602);
|
||||
constexpr Result ResultFrozenAddressOutOfResource(ErrorModule::DMNT, 6603);
|
||||
constexpr Result ResultVirtualMachineInvalidConditionDepth(ErrorModule::DMNT, 6700);
|
||||
} // namespace Service::DMNT
|
||||
@@ -1,55 +0,0 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Service::DMNT {
|
||||
struct MemoryRegionExtents {
|
||||
u64 base{};
|
||||
u64 size{};
|
||||
};
|
||||
static_assert(sizeof(MemoryRegionExtents) == 0x10, "MemoryRegionExtents is an invalid size");
|
||||
|
||||
struct CheatProcessMetadata {
|
||||
u64 process_id{};
|
||||
u64 program_id{};
|
||||
MemoryRegionExtents main_nso_extents{};
|
||||
MemoryRegionExtents heap_extents{};
|
||||
MemoryRegionExtents alias_extents{};
|
||||
MemoryRegionExtents aslr_extents{};
|
||||
std::array<u8, 0x20> main_nso_build_id{};
|
||||
};
|
||||
static_assert(sizeof(CheatProcessMetadata) == 0x70, "CheatProcessMetadata is an invalid size");
|
||||
|
||||
struct CheatDefinition {
|
||||
std::array<char, 0x40> readable_name;
|
||||
u32 num_opcodes;
|
||||
std::array<u32, 0x100> opcodes;
|
||||
};
|
||||
static_assert(sizeof(CheatDefinition) == 0x444, "CheatDefinition is an invalid size");
|
||||
|
||||
struct CheatEntry {
|
||||
bool enabled;
|
||||
u32 cheat_id;
|
||||
CheatDefinition definition;
|
||||
};
|
||||
static_assert(sizeof(CheatEntry) == 0x44C, "CheatEntry is an invalid size");
|
||||
static_assert(std::is_trivial_v<CheatEntry>, "CheatEntry type must be trivially copyable.");
|
||||
|
||||
struct FrozenAddressValue {
|
||||
u64 value;
|
||||
u8 width;
|
||||
};
|
||||
static_assert(sizeof(FrozenAddressValue) == 0x10, "FrozenAddressValue is an invalid size");
|
||||
|
||||
struct FrozenAddressEntry {
|
||||
u64 address;
|
||||
FrozenAddressValue value;
|
||||
};
|
||||
static_assert(sizeof(FrozenAddressEntry) == 0x18, "FrozenAddressEntry is an invalid size");
|
||||
} // namespace Service::DMNT
|
||||
@@ -60,6 +60,16 @@ public:
|
||||
{38, nullptr, "OwnTicket3"},
|
||||
{39, nullptr, "DeleteAllInactivePersonalizedTicket"},
|
||||
{40, nullptr, "DeletePrepurchaseRecordByNintendoAccountId"},
|
||||
{101, nullptr, "Unknown101"}, //18.0.0+
|
||||
{102, nullptr, "Unknown102"}, //18.0.0+
|
||||
{103, nullptr, "Unknown103"}, //18.0.0+
|
||||
{104, nullptr, "Unknown104"}, //18.0.0+
|
||||
{105, nullptr, "Unknown105"}, //20.0.0+
|
||||
{201, nullptr, "Unknown201"}, //18.0.0+
|
||||
{202, nullptr, "Unknown202"}, //18.0.0+
|
||||
{203, nullptr, "Unknown203"}, //18.0.0+
|
||||
{204, nullptr, "Unknown204"}, //18.0.0+
|
||||
{205, nullptr, "Unknown205"}, //18.0.0+
|
||||
{501, nullptr, "Unknown501"},
|
||||
{502, nullptr, "Unknown502"},
|
||||
{503, nullptr, "GetTitleKey"},
|
||||
|
||||
@@ -125,13 +125,10 @@ IHidDebugServer::IHidDebugServer(Core::System& system_, std::shared_ptr<Resource
|
||||
{250, nullptr, "IsVirtual"},
|
||||
{251, nullptr, "GetAnalogStickModuleParam"},
|
||||
{253, nullptr, "ClearStorageForShipment"}, //19.0.0+
|
||||
{254, nullptr, "Unknown254"},
|
||||
{255, nullptr, "Unknown255"},
|
||||
{256, nullptr, "Unknown256"},
|
||||
{261, nullptr, "UpdateDesignInfo12"},
|
||||
{262, nullptr, "GetUniquePadButtonCount"},
|
||||
{267, nullptr, "Unknown267"},
|
||||
{268, nullptr, "Unknown268"},
|
||||
{261, nullptr, "UpdateDesignInfo12"}, //21.0.0+
|
||||
{262, nullptr, "GetUniquePadButtonCount"}, //21.0.0+
|
||||
{267, nullptr, "SetAnalogStickCalibration"}, //21.0.0+
|
||||
{268, nullptr, "ResetAnalogStickCalibration"}, //21.0.0+
|
||||
{301, nullptr, "GetAbstractedPadHandles"},
|
||||
{302, nullptr, "GetAbstractedPadState"},
|
||||
{303, nullptr, "GetAbstractedPadsState"},
|
||||
@@ -148,6 +145,8 @@ IHidDebugServer::IHidDebugServer(Core::System& system_, std::shared_ptr<Resource
|
||||
{331, nullptr, "DetachHdlsVirtualDevice"},
|
||||
{332, nullptr, "SetHdlsState"},
|
||||
{350, nullptr, "AddRegisteredDevice"},
|
||||
{351, nullptr, "GetRegisteredDevicesCountDebug"}, //17.0.0-18.1.0
|
||||
{352, nullptr, "DeleteRegisteredDevicesDebug"}, //17.0.0-18.1.0
|
||||
{400, nullptr, "DisableExternalMcuOnNxDevice"},
|
||||
{401, nullptr, "DisableRailDeviceFiltering"},
|
||||
{402, nullptr, "EnableWiredPairing"},
|
||||
@@ -159,14 +158,30 @@ IHidDebugServer::IHidDebugServer(Core::System& system_, std::shared_ptr<Resource
|
||||
{551, nullptr, "GetAnalogStickModelData"},
|
||||
{552, nullptr, "ResetAnalogStickModelData"},
|
||||
{600, nullptr, "ConvertPadState"},
|
||||
{601, nullptr, "IsButtonConfigSupported"}, //18.0.0+
|
||||
{602, nullptr, "IsButtonConfigEmbeddedSupported"}, //18.0.0+
|
||||
{603, nullptr, "DeleteButtonConfig"}, //18.0.0+
|
||||
{604, nullptr, "DeleteButtonConfigEmbedded"}, //18.0.0+
|
||||
{605, nullptr, "SetButtonConfigEnabled"}, //18.0.0+
|
||||
{606, nullptr, "SetButtonConfigEmbeddedEnabled"}, //18.0.0+
|
||||
{607, nullptr, "IsButtonConfigEnabled"}, //18.0.0+
|
||||
{608, nullptr, "IsButtonConfigEmbeddedEnabled"}, //18.0.0+
|
||||
{609, nullptr, "SetButtonConfigEmbedded"}, //18.0.0+
|
||||
{610, nullptr, "SetButtonConfigFull"}, //18.0.0+
|
||||
{611, nullptr, "SetButtonConfigLeft"}, //18.0.0+
|
||||
{612, nullptr, "SetButtonConfigRight"}, //18.0.0+
|
||||
{613, nullptr, "GetButtonConfigEmbedded"}, //18.0.0+
|
||||
{614, nullptr, "GetButtonConfigFull"}, //18.0.0+
|
||||
{615, nullptr, "GetButtonConfigLeft"}, //18.0.0+
|
||||
{616, nullptr, "GetButtonConfigRight"}, //18.0.0+
|
||||
{650, nullptr, "AddButtonPlayData"},
|
||||
{651, nullptr, "StartButtonPlayData"},
|
||||
{652, nullptr, "StopButtonPlayData"},
|
||||
{700, nullptr, "Unknown700"},
|
||||
{700, nullptr, "GetRailAttachEventCount"}, //21.0.0+
|
||||
{2000, nullptr, "DeactivateDigitizer"},
|
||||
{2001, nullptr, "SetDigitizerAutoPilotState"},
|
||||
{2002, nullptr, "UnsetDigitizerAutoPilotState"},
|
||||
{2002, nullptr, "ReloadFirmwareDebugSettings"},
|
||||
{3000, nullptr, "ReloadFirmwareDebugSettings"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -70,7 +70,9 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour
|
||||
{328, nullptr, "AttachAbstractedPadToNpad"},
|
||||
{329, nullptr, "DetachAbstractedPadAll"},
|
||||
{330, nullptr, "CheckAbstractedPadConnection"},
|
||||
{500, nullptr, "SetAppletResourceUserId"},
|
||||
{332, nullptr, "ConvertAppletDetailedUiTypeFromPlayReportType"}, //19.0.0+
|
||||
{333, nullptr, "SetNpadUserSpgApplet"}, //20.0.0+
|
||||
{334, nullptr, "AcquireUniquePadButtonStateChangedEventHandle"}, //20.0.0+
|
||||
{501, &IHidSystemServer::RegisterAppletResourceUserId, "RegisterAppletResourceUserId"},
|
||||
{502, &IHidSystemServer::UnregisterAppletResourceUserId, "UnregisterAppletResourceUserId"},
|
||||
{503, &IHidSystemServer::EnableAppletToGetInput, "EnableAppletToGetInput"},
|
||||
@@ -99,7 +101,7 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour
|
||||
{547, nullptr, "GetAllowedBluetoothLinksCount"},
|
||||
{548, &IHidSystemServer::GetRegisteredDevices, "GetRegisteredDevices"},
|
||||
{549, nullptr, "GetConnectableRegisteredDevices"},
|
||||
{551, nullptr, "GetRegisteredDevicesForControllerSupport"},
|
||||
{551, nullptr, "GetRegisteredDevicesForControllerSupport"}, //20.0.0+
|
||||
{700, nullptr, "ActivateUniquePad"},
|
||||
{702, &IHidSystemServer::AcquireUniquePadConnectionEventHandle, "AcquireUniquePadConnectionEventHandle"},
|
||||
{703, &IHidSystemServer::GetUniquePadIds, "GetUniquePadIds"},
|
||||
@@ -119,6 +121,7 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour
|
||||
{810, nullptr, "GetUniquePadControllerNumber"},
|
||||
{811, nullptr, "GetSixAxisSensorUserCalibrationStage"},
|
||||
{812, nullptr, "GetConsoleUniqueSixAxisSensorHandle"},
|
||||
{813, nullptr, "GetDeviceType"},
|
||||
{821, nullptr, "StartAnalogStickManualCalibration"},
|
||||
{822, nullptr, "RetryCurrentAnalogStickManualCalibrationStage"},
|
||||
{823, nullptr, "CancelAnalogStickManualCalibration"},
|
||||
@@ -149,6 +152,7 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour
|
||||
{1009, nullptr, "AcquireAudioControlEventHandle"},
|
||||
{1010, nullptr, "GetAudioControlStates"},
|
||||
{1011, nullptr, "DeactivateAudioControl"},
|
||||
{1012, nullptr, "GetFirmwareVersionStringForUserSupportPage"},
|
||||
{1050, nullptr, "IsSixAxisSensorAccurateUserCalibrationSupported"},
|
||||
{1051, nullptr, "StartSixAxisSensorAccurateUserCalibration"},
|
||||
{1052, nullptr, "CancelSixAxisSensorAccurateUserCalibration"},
|
||||
@@ -169,6 +173,8 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour
|
||||
{1155, &IHidSystemServer::SetForceHandheldStyleVibration, "SetForceHandheldStyleVibration"},
|
||||
{1156, nullptr, "SendConnectionTriggerWithoutTimeoutEvent"},
|
||||
{1157, nullptr, "CancelConnectionTrigger"},
|
||||
{1158, nullptr, "SetConnectionLimitForSplay"}, //20.1.0+
|
||||
{1159, nullptr, "ClearConnectionLimitForSplay"}, //20.1.0+
|
||||
{1200, nullptr, "IsButtonConfigSupported"},
|
||||
{1201, nullptr, "IsButtonConfigEmbeddedSupported"},
|
||||
{1202, nullptr, "DeleteButtonConfig"},
|
||||
@@ -227,16 +233,17 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour
|
||||
{1289, nullptr, "SetButtonConfigStorageFull"},
|
||||
{1290, nullptr, "DeleteButtonConfigStorageRight"},
|
||||
{1291, nullptr, "DeleteButtonConfigStorageRight"},
|
||||
{1308, nullptr, "SetButtonConfigVisible"}, // 18.0.0+
|
||||
{1309, nullptr, "IsButtonConfigVisible"}, // 18.0.0+
|
||||
{1320, nullptr, "WakeTouchScreenUp"}, // 17.0.0+
|
||||
{1321, nullptr, "PutTouchScreenToSleep"}, // 17.0.0+
|
||||
{1322, nullptr, "AcquireTouchScreenAsyncWakeCompletedEvent"}, // 20.0.0+
|
||||
{1323, nullptr, "StartTouchScreenAutoTuneForSystemSettings"}, // 21.0.0+
|
||||
{1324, nullptr, "AcquireTouchScreenAutoTuneCompletedEvent"}, // 21.0.0+
|
||||
{1325, nullptr, "IsTouchScreenAutoTuneRequiredForRepairProviderReplacement"}, // 21.0.0+
|
||||
{1326, nullptr, "Unknown1326"}, // 21.0.0+
|
||||
{1420, nullptr, "GetAppletResourceProperty"}, // 19.0.0+
|
||||
{1308, nullptr, "SetButtonConfigVisible"}, //18.0.0+
|
||||
{1309, nullptr, "IsButtonConfigVisible"}, //18.0.0+
|
||||
{1320, nullptr, "WakeTouchScreenUp"}, //17.0.0+
|
||||
{1321, nullptr, "PutTouchScreenToSleep"}, //17.0.0+
|
||||
{1322, nullptr, "AcquireTouchScreenAsyncWakeCompletedEvent"}, //20.0.0+
|
||||
{1323, nullptr, "StartTouchScreenAutoTuneForSystemSettings"}, //21.0.0+
|
||||
{1324, nullptr, "AcquireTouchScreenAutoTuneCompletedEvent"}, //21.0.0+
|
||||
{1325, nullptr, "IsTouchScreenAutoTuneRequiredForRepairProviderReplacement"}, //21.0.0+
|
||||
{1326, nullptr, "SetTouchScreenOffset"}, //21.0.0+
|
||||
{1420, nullptr, "GetAppletResourceProperty"}, //19.0.0+
|
||||
{12010, nullptr, "SetButtonConfigLeft"} //11.0.0-17.0.1
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 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
|
||||
|
||||
@@ -14,17 +17,42 @@ public:
|
||||
explicit MIG_USR(Core::System& system_) : ServiceFramework{system_, "mig:usr"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "Unknown0"}, //19.0.0+
|
||||
{1, nullptr, "Unknown1"}, //20.0.0+
|
||||
{2, nullptr, "Unknown2"}, //20.0.0+
|
||||
{10, nullptr, "TryGetLastMigrationInfo"},
|
||||
{100, nullptr, "CreateServer"},
|
||||
{101, nullptr, "ResumeServer"},
|
||||
{200, nullptr, "CreateClient"},
|
||||
{201, nullptr, "ResumeClient"},
|
||||
{1001, nullptr, "Unknown1001"},
|
||||
{1010, nullptr, "Unknown1010"},
|
||||
{1100, nullptr, "Unknown1100"},
|
||||
{1101, nullptr, "Unknown1101"},
|
||||
{1200, nullptr, "Unknown1200"},
|
||||
{1201, nullptr, "Unknown1201"}
|
||||
{11, nullptr, "Unknown11"}, //20.0.0+
|
||||
{100, nullptr, "CreateUserMigrationServer"}, //7.0.0+
|
||||
{101, nullptr, "ResumeUserMigrationServer"}, //7.0.0+
|
||||
{200, nullptr, "CreateUserMigrationClient"}, //7.0.0+
|
||||
{201, nullptr, "ResumeUserMigrationClient"}, //7.0.0+
|
||||
{1001, nullptr, "GetSaveDataMigrationPolicyInfoAsync"}, //8.0.0-20.5.0
|
||||
{1010, nullptr, "TryGetLastSaveDataMigrationInfo"}, //7.0.0+
|
||||
{1100, nullptr, "CreateSaveDataMigrationServer"}, //7.0.0-19.0.1
|
||||
{1101, nullptr, "ResumeSaveDataMigrationServer"}, //7.0.0+
|
||||
{1110, nullptr, "Unknown1101"}, //17.0.0+
|
||||
{1200, nullptr, "CreateSaveDataMigrationClient"}, //7.0.0+
|
||||
{1201, nullptr, "ResumeSaveDataMigrationClient"}, //7.0.0+
|
||||
{2001, nullptr, "Unknown2001"}, //20.0.0+
|
||||
{2010, nullptr, "Unknown2010"}, //20.0.0+
|
||||
{2100, nullptr, "Unknown2100"}, //20.0.0+
|
||||
{2110, nullptr, "Unknown2110"}, //20.0.0+
|
||||
{2200, nullptr, "Unknown2200"}, //20.0.0+
|
||||
{2210, nullptr, "Unknown2210"}, //20.0.0+
|
||||
{2220, nullptr, "Unknown2220"}, //20.0.0+
|
||||
{2230, nullptr, "Unknown2230"}, //20.0.0+
|
||||
{2231, nullptr, "Unknown2231"}, //20.0.0+
|
||||
{2232, nullptr, "Unknown2232"}, //20.0.0+
|
||||
{2233, nullptr, "Unknown2233"}, //20.0.0+
|
||||
{2234, nullptr, "Unknown2234"}, //20.0.0+
|
||||
{2250, nullptr, "Unknown2250"}, //20.0.0+
|
||||
{2260, nullptr, "Unknown2260"}, //20.0.0+
|
||||
{2270, nullptr, "Unknown2270"}, //20.0.0+
|
||||
{2280, nullptr, "Unknown2280"}, //20.0.0+
|
||||
{2300, nullptr, "Unknown2300"}, //20.0.0+
|
||||
{2310, nullptr, "Unknown2310"}, //20.0.0+
|
||||
{2400, nullptr, "Unknown2400"}, //20.0.0+
|
||||
{2420, nullptr, "Unknown2420"}, //20.0.0+
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -167,57 +167,146 @@ public:
|
||||
{81, nullptr, "ListLocalCommunicationSendSystemUpdateTask"},
|
||||
{82, nullptr, "GetReceivedSystemDataPath"},
|
||||
{83, nullptr, "CalculateApplyDeltaTaskOccupiedSize"},
|
||||
{84, nullptr, "Unknown84"},
|
||||
{84, nullptr, "ReloadErrorSimulation"},
|
||||
{85, nullptr, "ListNetworkInstallTaskContentMetaFromInstallMeta"},
|
||||
{86, nullptr, "ListNetworkInstallTaskOccupiedSize"},
|
||||
{87, nullptr, "Unknown87"},
|
||||
{88, nullptr, "Unknown88"},
|
||||
{89, nullptr, "Unknown89"},
|
||||
{90, nullptr, "Unknown90"},
|
||||
{91, nullptr, "Unknown91"},
|
||||
{92, nullptr, "Unknown92"},
|
||||
{93, nullptr, "Unknown93"},
|
||||
{94, nullptr, "Unknown94"},
|
||||
{95, nullptr, "Unknown95"},
|
||||
{96, nullptr, "Unknown96"},
|
||||
{97, nullptr, "Unknown97"},
|
||||
{98, nullptr, "Unknown98"},
|
||||
{99, nullptr, "Unknown99"},
|
||||
{100, nullptr, "Unknown100"},
|
||||
{101, nullptr, "Unknown101"},
|
||||
{102, nullptr, "Unknown102"},
|
||||
{103, nullptr, "Unknown103"},
|
||||
{104, nullptr, "Unknown104"},
|
||||
{105, nullptr, "Unknown105"},
|
||||
{106, nullptr, "Unknown106"},
|
||||
{107, nullptr, "Unknown107"},
|
||||
{108, nullptr, "Unknown108"},
|
||||
{109, nullptr, "Unknown109"},
|
||||
{110, nullptr, "Unknown110"},
|
||||
{111, nullptr, "Unknown111"},
|
||||
{112, nullptr, "Unknown112"},
|
||||
{113, nullptr, "Unknown113"},
|
||||
{114, nullptr, "Unknown114"},
|
||||
{115, nullptr, "Unknown115"},
|
||||
{116, nullptr, "Unknown116"},
|
||||
{117, nullptr, "Unknown117"},
|
||||
{118, nullptr, "Unknown118"},
|
||||
{119, nullptr, "Unknown119"},
|
||||
{120, nullptr, "Unknown120"},
|
||||
{121, nullptr, "Unknown121"},
|
||||
{122, nullptr, "Unknown122"},
|
||||
{123, nullptr, "Unknown123"},
|
||||
{124, nullptr, "Unknown124"},
|
||||
{125, nullptr, "Unknown125"},
|
||||
{126, nullptr, "Unknown126"},
|
||||
{127, nullptr, "Unknown127"},
|
||||
{128, nullptr, "Unknown128"},
|
||||
{129, nullptr, "Unknown129"},
|
||||
{130, nullptr, "Unknown130"},
|
||||
{131, nullptr, "Unknown131"},
|
||||
{132, nullptr, "Unknown132"},
|
||||
{133, nullptr, "Unknown133"},
|
||||
{134, nullptr, "Unknown134"},
|
||||
{87, nullptr, "RequestQueryAvailableELicenses"},
|
||||
{88, nullptr, "RequestAssignELicenses"},
|
||||
{89, nullptr, "RequestExtendELicenses"},
|
||||
{90, nullptr, "RequestSyncELicenses"},
|
||||
{91, nullptr, "Unknown91"}, //6.0.0-14.1.2
|
||||
{92, nullptr, "Unknown92"}, //21.0.0+
|
||||
{93, nullptr, "RequestReportActiveELicenses"},
|
||||
{94, nullptr, "RequestReportActiveELicensesPassively"},
|
||||
{95, nullptr, "RequestRegisterDynamicRightsNotificationToken"},
|
||||
{96, nullptr, "RequestAssignAllDeviceLinkedELicenses"},
|
||||
{97, nullptr, "RequestRevokeAllELicenses"},
|
||||
{98, nullptr, "RequestPrefetchForDynamicRights"},
|
||||
{99, nullptr, "CreateNetworkInstallTask"},
|
||||
{100, nullptr, "ListNetworkInstallTaskRightsIds"},
|
||||
{101, nullptr, "RequestDownloadETickets"},
|
||||
{102, nullptr, "RequestQueryDownloadableContents"},
|
||||
{103, nullptr, "DeleteNetworkInstallTaskContentMeta"},
|
||||
{104, nullptr, "RequestIssueEdgeTokenForDebug"},
|
||||
{105, nullptr, "RequestQueryAvailableELicenses2"},
|
||||
{106, nullptr, "RequestAssignELicenses2"},
|
||||
{107, nullptr, "GetNetworkInstallTaskStateCounter"},
|
||||
{108, nullptr, "InvalidateDynamicRightsNaIdTokenCacheForDebug"},
|
||||
{109, nullptr, "ListNetworkInstallTaskPartialInstallContentMeta"},
|
||||
{110, nullptr, "ListNetworkInstallTaskRightsIdsFromIndex"},
|
||||
{111, nullptr, "AddNetworkInstallTaskContentMetaForUser"},
|
||||
{112, nullptr, "RequestAssignELicensesAndDownloadETickets"},
|
||||
{113, nullptr, "RequestQueryAvailableCommonELicenses"},
|
||||
{114, nullptr, "SetNetworkInstallTaskExtendedAttribute"},
|
||||
{115, nullptr, "GetNetworkInstallTaskExtendedAttribute"},
|
||||
{116, nullptr, "GetAllocatorInfo"},
|
||||
{117, nullptr, "RequestQueryDownloadableContentsByApplicationId"},
|
||||
{118, nullptr, "MarkNoDownloadRightsErrorResolved"},
|
||||
{119, nullptr, "GetApplyDeltaTaskAllAppliedContentMeta"},
|
||||
{120, nullptr, "PrioritizeNetworkInstallTask"},
|
||||
{121, nullptr, "RequestQueryAvailableCommonELicenses2"},
|
||||
{122, nullptr, "RequestAssignCommonELicenses"},
|
||||
{123, nullptr, "RequestAssignCommonELicenses2"},
|
||||
{124, nullptr, "IsNetworkInstallTaskFrontOfQueue"},
|
||||
{125, nullptr, "PrioritizeApplyDeltaTask"},
|
||||
{126, nullptr, "RerouteDownloadingPatch"},
|
||||
{127, nullptr, "UnmarkNoDownloadRightsErrorResolved"},
|
||||
{128, nullptr, "RequestContentsSize"},
|
||||
{129, nullptr, "RequestContentsAuthorizationToken"},
|
||||
{130, nullptr, "RequestCdnVendorDiscovery"},
|
||||
{131, nullptr, "RefreshDebugAvailability"},
|
||||
{132, nullptr, "ClearResponseSimulationEntry"},
|
||||
{133, nullptr, "RegisterResponseSimulationEntry"},
|
||||
{134, nullptr, "GetProcessedCdnVendors"},
|
||||
{135, nullptr, "RefreshRuntimeBehaviorsForDebug"},
|
||||
{136, nullptr, "RequestOnlineSubscriptionFreeTrialAvailability"},
|
||||
{137, nullptr, "GetNetworkInstallTaskContentMetaCount"},
|
||||
{138, nullptr, "RequestRevokeELicenses"},
|
||||
{139, nullptr, "EnableNetworkConnectionToUseApplicationCore"},
|
||||
{140, nullptr, "DisableNetworkConnectionToUseApplicationCore"},
|
||||
{141, nullptr, "IsNetworkConnectionEnabledToUseApplicationCore"},
|
||||
{142, nullptr, "RequestCheckSafeSystemVersion"},
|
||||
{143, nullptr, "RequestApplicationIcon"},
|
||||
{144, nullptr, "RequestDownloadIdbeIconFile"},
|
||||
{147, nullptr, "Unknown147"}, //18.0.0+
|
||||
{148, nullptr, "Unknown148"}, //18.0.0+
|
||||
{150, nullptr, "Unknown150"}, //19.0.0+
|
||||
{151, nullptr, "Unknown151"}, //20.0.0+
|
||||
{152, nullptr, "Unknown152"}, //20.0.0+
|
||||
{153, nullptr, "Unknown153"}, //20.0.0+
|
||||
{154, nullptr, "Unknown154"}, //20.0.0+
|
||||
{155, nullptr, "Unknown155"}, //20.0.0+
|
||||
{156, nullptr, "Unknown156"}, //20.0.0+
|
||||
{157, nullptr, "Unknown157"}, //20.0.0+
|
||||
{158, nullptr, "Unknown158"}, //20.0.0+
|
||||
{159, nullptr, "Unknown159"}, //20.0.0+
|
||||
{160, nullptr, "Unknown160"}, //20.0.0+
|
||||
{161, nullptr, "Unknown161"}, //20.0.0+
|
||||
{162, nullptr, "Unknown162"}, //20.0.0+
|
||||
{163, nullptr, "Unknown163"}, //20.0.0+
|
||||
{164, nullptr, "Unknown164"}, //20.0.0+
|
||||
{165, nullptr, "Unknown165"}, //20.0.0+
|
||||
{166, nullptr, "Unknown166"}, //20.0.0+
|
||||
{167, nullptr, "Unknown167"}, //20.0.0+
|
||||
{168, nullptr, "Unknown168"}, //20.0.0+
|
||||
{169, nullptr, "Unknown169"}, //20.0.0+
|
||||
{170, nullptr, "Unknown170"}, //20.0.0+
|
||||
{171, nullptr, "Unknown171"}, //20.0.0+
|
||||
{172, nullptr, "Unknown172"}, //20.0.0+
|
||||
{173, nullptr, "Unknown173"}, //20.0.0+
|
||||
{174, nullptr, "Unknown174"}, //20.0.0+
|
||||
{175, nullptr, "Unknown175"}, //20.0.0+
|
||||
{176, nullptr, "Unknown176"}, //20.0.0+
|
||||
{177, nullptr, "Unknown177"}, //20.0.0+
|
||||
{2000, nullptr, "Unknown2000"}, //20.0.0+
|
||||
{2001, nullptr, "Unknown2001"}, //20.0.0+
|
||||
{2002, nullptr, "Unknown2002"}, //20.0.0+
|
||||
{2003, nullptr, "Unknown2003"}, //20.0.0+
|
||||
{2004, nullptr, "Unknown2004"}, //20.0.0+
|
||||
{2007, nullptr, "Unknown2007"}, //20.0.0+
|
||||
{2011, nullptr, "Unknown2011"}, //20.0.0+
|
||||
{2012, nullptr, "Unknown2012"}, //20.0.0+
|
||||
{2013, nullptr, "Unknown2013"}, //20.0.0+
|
||||
{2014, nullptr, "Unknown2014"}, //20.0.0+
|
||||
{2015, nullptr, "Unknown2015"}, //20.0.0+
|
||||
{2016, nullptr, "Unknown2016"}, //20.0.0+
|
||||
{2017, nullptr, "Unknown2017"}, //20.0.0+
|
||||
{2018, nullptr, "Unknown2018"}, //20.0.0+
|
||||
{2019, nullptr, "Unknown2019"}, //20.0.0+
|
||||
{2020, nullptr, "Unknown2020"}, //20.0.0+
|
||||
{2021, nullptr, "Unknown2021"}, //20.0.0+
|
||||
{2022, nullptr, "Unknown2022"}, //20.0.0+
|
||||
{2023, nullptr, "Unknown2023"}, //20.0.0+
|
||||
{2024, nullptr, "Unknown2024"}, //20.0.0+
|
||||
{2025, nullptr, "Unknown2025"}, //20.0.0+
|
||||
{2026, nullptr, "Unknown2026"}, //20.0.0+
|
||||
{2027, nullptr, "Unknown2027"}, //20.0.0+
|
||||
{2028, nullptr, "Unknown2028"}, //20.0.0+
|
||||
{2029, nullptr, "Unknown2029"}, //20.0.0+
|
||||
{2030, nullptr, "Unknown2030"}, //20.0.0+
|
||||
{2031, nullptr, "Unknown2031"}, //20.0.0+
|
||||
{2032, nullptr, "Unknown2032"}, //20.0.0+
|
||||
{2033, nullptr, "Unknown2033"}, //20.0.0+
|
||||
{2034, nullptr, "Unknown2034"}, //20.0.0+
|
||||
{2035, nullptr, "Unknown2035"}, //20.0.0+
|
||||
{2036, nullptr, "Unknown2036"}, //20.0.0+
|
||||
{2037, nullptr, "Unknown2037"}, //20.0.0+
|
||||
{2038, nullptr, "Unknown2038"}, //20.0.0+
|
||||
{2039, nullptr, "Unknown2039"}, //20.0.0+
|
||||
{2040, nullptr, "Unknown2040"}, //20.0.0+
|
||||
{2041, nullptr, "Unknown2041"}, //20.0.0+
|
||||
{2042, nullptr, "Unknown2042"}, //20.0.0+
|
||||
{2043, nullptr, "Unknown2043"}, //20.0.0+
|
||||
{2044, nullptr, "Unknown2044"}, //20.0.0+
|
||||
{2045, nullptr, "Unknown2045"}, //20.0.0+
|
||||
{2046, nullptr, "Unknown2046"}, //20.0.0+
|
||||
{2047, nullptr, "Unknown2047"}, //20.0.0+
|
||||
{2048, nullptr, "Unknown2048"}, //20.0.0+
|
||||
{2049, nullptr, "Unknown2049"}, //20.0.0+
|
||||
{2050, nullptr, "Unknown2050"}, //20.0.0+
|
||||
{2051, nullptr, "Unknown2051"}, //20.0.0+
|
||||
{3000, nullptr, "RequestLatestApplicationIcon"}, //17.0.0+
|
||||
{3001, nullptr, "RequestDownloadIdbeLatestIconFile"}, //17.0.0+
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -134,7 +134,26 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
|
||||
{406, nullptr, "GetApplicationControlProperty"},
|
||||
{407, nullptr, "ListApplicationTitle"},
|
||||
{408, nullptr, "ListApplicationIcon"},
|
||||
{411, nullptr, "Unknown411"}, //19.0.0+
|
||||
{412, nullptr, "Unknown412"}, //19.0.0+
|
||||
{413, nullptr, "Unknown413"}, //19.0.0+
|
||||
{414, nullptr, "Unknown414"}, //19.0.0+
|
||||
{415, nullptr, "Unknown415"}, //19.0.0+
|
||||
{416, nullptr, "Unknown416"}, //19.0.0+
|
||||
{417, nullptr, "InvalidateAllApplicationControlCacheOfTheStage"}, //19.0.0+
|
||||
{418, nullptr, "InvalidateApplicationControlCacheOfTheStage"}, //19.0.0+
|
||||
{419, D<&IApplicationManagerInterface::RequestDownloadApplicationControlDataInBackground>, "RequestDownloadApplicationControlDataInBackground"},
|
||||
{420, nullptr, "CloneApplicationControlDataCacheForDebug"},
|
||||
{421, nullptr, "Unknown421"}, //20.0.0+
|
||||
{422, nullptr, "Unknown422"}, //20.0.0+
|
||||
{423, nullptr, "Unknown423"}, //20.0.0+
|
||||
{424, nullptr, "Unknown424"}, //20.0.0+
|
||||
{425, nullptr, "Unknown425"}, //20.0.0+
|
||||
{426, nullptr, "Unknown426"}, //20.0.0+
|
||||
{427, nullptr, "Unknown427"}, //20.0.0+
|
||||
{428, nullptr, "Unknown428"}, //21.0.0+
|
||||
{429, nullptr, "Unknown429"}, //21.0.0+
|
||||
{430, nullptr, "Unknown430"}, //21.0.0+
|
||||
{502, nullptr, "RequestCheckGameCardRegistration"},
|
||||
{503, nullptr, "RequestGameCardRegistrationGoldPoint"},
|
||||
{504, nullptr, "RequestRegisterGameCard"},
|
||||
@@ -146,6 +165,13 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
|
||||
{510, nullptr, "GetGameCardPlatformRegion"},
|
||||
{511, D<&IApplicationManagerInterface::GetGameCardWakenReadyEvent>, "GetGameCardWakenReadyEvent"},
|
||||
{512, D<&IApplicationManagerInterface::IsGameCardApplicationRunning>, "IsGameCardApplicationRunning"},
|
||||
{513, nullptr, "Unknown513"}, //20.0.0+
|
||||
{514, nullptr, "Unknown514"}, //20.0.0+
|
||||
{515, nullptr, "Unknown515"}, //20.0.0+
|
||||
{516, nullptr, "Unknown516"}, //21.0.0+
|
||||
{517, nullptr, "Unknown517"}, //21.0.0+
|
||||
{518, nullptr, "Unknown518"}, //21.0.0+
|
||||
{519, nullptr, "Unknown519"}, //21.0.0+
|
||||
{600, nullptr, "CountApplicationContentMeta"},
|
||||
{601, nullptr, "ListApplicationContentMetaStatus"},
|
||||
{602, nullptr, "ListAvailableAddOnContent"},
|
||||
@@ -183,6 +209,22 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
|
||||
{914, nullptr, "HideApplicationRecord"},
|
||||
{915, nullptr, "ShowApplicationRecord"},
|
||||
{916, nullptr, "IsApplicationAutoDeleteDisabled"},
|
||||
{916, nullptr, "Unknown916"}, //20.0.0+
|
||||
{917, nullptr, "Unknown917"}, //20.0.0+
|
||||
{918, nullptr, "Unknown918"}, //20.0.0+
|
||||
{919, nullptr, "Unknown919"}, //20.0.0+
|
||||
{920, nullptr, "Unknown920"}, //20.0.0+
|
||||
{921, nullptr, "Unknown921"}, //20.0.0+
|
||||
{922, nullptr, "Unknown922"}, //20.0.0+
|
||||
{923, nullptr, "Unknown923"}, //20.0.0+
|
||||
{928, nullptr, "Unknown928"}, //20.0.0+
|
||||
{929, nullptr, "Unknown929"}, //20.0.0+
|
||||
{930, nullptr, "Unknown930"}, //20.0.0+
|
||||
{931, nullptr, "Unknown931"}, //20.0.0+
|
||||
{933, nullptr, "Unknown933"}, //20.0.0+
|
||||
{934, nullptr, "Unknown934"}, //20.0.0+
|
||||
{935, nullptr, "Unknown935"}, //20.0.0+
|
||||
{936, nullptr, "Unknown936"}, //20.0.0+
|
||||
{1000, nullptr, "RequestVerifyApplicationDeprecated"},
|
||||
{1001, nullptr, "CorruptApplicationForDebug"},
|
||||
{1002, nullptr, "RequestVerifyAddOnContentsRights"},
|
||||
@@ -211,6 +253,11 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
|
||||
{1504, nullptr, "InsertSdCard"},
|
||||
{1505, nullptr, "RemoveSdCard"},
|
||||
{1506, nullptr, "GetSdCardStartupStatus"},
|
||||
{1508, nullptr, "Unknown1508"}, //20.0.0+
|
||||
{1509, nullptr, "Unknown1509"}, //20.0.0+
|
||||
{1510, nullptr, "Unknown1510"}, //20.0.0+
|
||||
{1511, nullptr, "Unknown1511"}, //20.0.0+
|
||||
{1512, nullptr, "Unknown1512"}, //20.0.0+
|
||||
{1600, nullptr, "GetSystemSeedForPseudoDeviceId"},
|
||||
{1601, nullptr, "ResetSystemSeedForPseudoDeviceId"},
|
||||
{1700, nullptr, "ListApplicationDownloadingContentMeta"},
|
||||
@@ -247,8 +294,11 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
|
||||
{2016, nullptr, "ListNotCommittedContentMeta"},
|
||||
{2017, nullptr, "CreateDownloadTask"},
|
||||
{2018, nullptr, "GetApplicationDeliveryInfoHash"},
|
||||
{2019, nullptr, "Unknown2019"}, //20.0.0+
|
||||
{2050, D<&IApplicationManagerInterface::GetApplicationRightsOnClient>, "GetApplicationRightsOnClient"},
|
||||
{2051, nullptr, "InvalidateRightsIdCache"},
|
||||
{2052, nullptr, "Unknown2052"}, //20.0.0+
|
||||
{2053, nullptr, "Unknown2053"}, //20.0.0+
|
||||
{2100, D<&IApplicationManagerInterface::GetApplicationTerminateResult>, "GetApplicationTerminateResult"},
|
||||
{2101, nullptr, "GetRawApplicationTerminateResult"},
|
||||
{2150, nullptr, "CreateRightsEnvironment"},
|
||||
@@ -265,6 +315,7 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
|
||||
{2180, nullptr, "RequestExtendRightsInRightsEnvironment"},
|
||||
{2181, nullptr, "GetResultOfExtendRightsInRightsEnvironment"},
|
||||
{2182, nullptr, "SetActiveRightsContextUsingStateToRightsEnvironment"},
|
||||
{2183, nullptr, "Unknown2183"}, //20.1.0+
|
||||
{2190, nullptr, "GetRightsEnvironmentHandleForApplication"},
|
||||
{2199, nullptr, "GetRightsEnvironmentCountForDebug"},
|
||||
{2200, nullptr, "GetGameCardApplicationCopyIdentifier"},
|
||||
@@ -281,6 +332,16 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
|
||||
{2357, nullptr, "EnableMultiCoreDownload"},
|
||||
{2358, nullptr, "DisableMultiCoreDownload"},
|
||||
{2359, nullptr, "IsMultiCoreDownloadEnabled"},
|
||||
{2360, nullptr, "GetApplicationDownloadTaskCount"}, //19.0.0+
|
||||
{2361, nullptr, "GetMaxApplicationDownloadTaskCount"}, //19.0.0+
|
||||
{2362, nullptr, "Unknown2362"}, //20.0.0+
|
||||
{2363, nullptr, "Unknown2363"}, //20.0.0+
|
||||
{2364, nullptr, "Unknown2364"}, //20.0.0+
|
||||
{2365, nullptr, "Unknown2365"}, //20.0.0+
|
||||
{2366, nullptr, "Unknown2366"}, //20.0.0+
|
||||
{2367, nullptr, "Unknown2367"}, //20.0.0+
|
||||
{2368, nullptr, "Unknown2368"}, //20.0.0+
|
||||
{2369, nullptr, "Unknown2369"}, //21.0.0+
|
||||
{2400, nullptr, "GetPromotionInfo"},
|
||||
{2401, nullptr, "CountPromotionInfo"},
|
||||
{2402, nullptr, "ListPromotionInfo"},
|
||||
@@ -299,6 +360,9 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
|
||||
{2520, nullptr, "IsQualificationTransitionSupportedByProcessId"},
|
||||
{2521, nullptr, "GetRightsUserChangedEvent"},
|
||||
{2522, nullptr, "IsRomRedirectionAvailable"},
|
||||
{2523, nullptr, "GetProgramId"}, //17.0.0+
|
||||
{2524, nullptr, "Unknown2524"}, //19.0.0+
|
||||
{2525, nullptr, "Unknown2525"}, //20.0.0+
|
||||
{2800, nullptr, "GetApplicationIdOfPreomia"},
|
||||
{3000, nullptr, "RegisterDeviceLockKey"},
|
||||
{3001, nullptr, "UnregisterDeviceLockKey"},
|
||||
@@ -316,11 +380,99 @@ IApplicationManagerInterface::IApplicationManagerInterface(Core::System& system_
|
||||
{3013, nullptr, "IsGameCardEnabled"},
|
||||
{3014, nullptr, "IsLocalContentShareEnabled"},
|
||||
{3050, nullptr, "ListAssignELicenseTaskResult"},
|
||||
{4022, D<&IApplicationManagerInterface::Unknown4022>, "Unknown4022"},
|
||||
{4023, D<&IApplicationManagerInterface::Unknown4023>, "Unknown4023"},
|
||||
{4088, D<&IApplicationManagerInterface::Unknown4022>, "Unknown4088"},
|
||||
{4053, D<&IApplicationManagerInterface::Unknown4053>, "Unknown4053"},
|
||||
{9999, nullptr, "GetApplicationCertificate"},
|
||||
{3104, nullptr, "GetApplicationNintendoLogo"}, //18.0.0+
|
||||
{3105, nullptr, "GetApplicationStartupMovie"}, //18.0.0+
|
||||
{4000, nullptr, "Unknown4000"}, //20.0.0+
|
||||
{4004, nullptr, "Unknown4004"}, //20.0.0+
|
||||
{4006, nullptr, "Unknown4006"}, //20.0.0+
|
||||
{4007, nullptr, "Unknown4007"}, //20.0.0+
|
||||
{4008, nullptr, "Unknown4008"}, //20.0.0+
|
||||
{4009, nullptr, "Unknown4009"}, //20.0.0+
|
||||
{4010, nullptr, "Unknown4010"}, //20.0.0+
|
||||
{4011, nullptr, "Unknown4011"}, //20.0.0+
|
||||
{4012, nullptr, "Unknown4012"}, //20.0.0+
|
||||
{4013, nullptr, "Unknown4013"}, //20.0.0+
|
||||
{4015, nullptr, "Unknown4015"}, //20.0.0+
|
||||
{4017, nullptr, "Unknown4017"}, //20.0.0+
|
||||
{4019, nullptr, "Unknown4019"}, //20.0.0+
|
||||
{4020, nullptr, "Unknown4020"}, //20.0.0+
|
||||
{4021, nullptr, "Unknown4021"}, //20.0.0+
|
||||
{4022, D<&IApplicationManagerInterface::Unknown4022>, "Unknown4022"}, //20.0.0+
|
||||
{4023, D<&IApplicationManagerInterface::Unknown4023>, "Unknown4023"}, //20.0.0+
|
||||
{4024, nullptr, "Unknown4024"}, //20.0.0+
|
||||
{4025, nullptr, "Unknown4025"}, //20.0.0+
|
||||
{4026, nullptr, "Unknown4026"}, //20.0.0+
|
||||
{4027, nullptr, "Unknown4027"}, //20.0.0+
|
||||
{4028, nullptr, "Unknown4028"}, //20.0.0+
|
||||
{4029, nullptr, "Unknown4029"}, //20.0.0+
|
||||
{4030, nullptr, "Unknown4030"}, //20.0.0+
|
||||
{4031, nullptr, "Unknown4031"}, //20.0.0+
|
||||
{4032, nullptr, "Unknown4032"}, //20.0.0+
|
||||
{4033, nullptr, "Unknown4033"}, //20.0.0+
|
||||
{4034, nullptr, "Unknown4034"}, //20.0.0+
|
||||
{4035, nullptr, "Unknown4035"}, //20.0.0+
|
||||
{4037, nullptr, "Unknown4037"}, //20.0.0+
|
||||
{4038, nullptr, "Unknown4038"}, //20.0.0+
|
||||
{4039, nullptr, "Unknown4039"}, //20.0.0+
|
||||
{4040, nullptr, "Unknown4040"}, //20.0.0+
|
||||
{4041, nullptr, "Unknown4041"}, //20.0.0+
|
||||
{4042, nullptr, "Unknown4042"}, //20.0.0+
|
||||
{4043, nullptr, "Unknown4043"}, //20.0.0+
|
||||
{4044, nullptr, "Unknown4044"}, //20.0.0+
|
||||
{4045, nullptr, "Unknown4045"}, //20.0.0+
|
||||
{4046, nullptr, "Unknown4046"}, //20.0.0+
|
||||
{4049, nullptr, "Unknown4049"}, //20.0.0+
|
||||
{4050, nullptr, "Unknown4050"}, //20.0.0+
|
||||
{4051, nullptr, "Unknown4051"}, //20.0.0+
|
||||
{4052, nullptr, "Unknown4052"}, //20.0.0+
|
||||
{4053, D<&IApplicationManagerInterface::Unknown4053>, "Unknown4053"}, //20.0.0+
|
||||
{4054, nullptr, "Unknown4054"}, //20.0.0+
|
||||
{4055, nullptr, "Unknown4055"}, //20.0.0+
|
||||
{4056, nullptr, "Unknown4056"}, //20.0.0+
|
||||
{4057, nullptr, "Unknown4057"}, //20.0.0+
|
||||
{4058, nullptr, "Unknown4058"}, //20.0.0+
|
||||
{4059, nullptr, "Unknown4059"}, //20.0.0+
|
||||
{4060, nullptr, "Unknown4060"}, //20.0.0+
|
||||
{4061, nullptr, "Unknown4061"}, //20.0.0+
|
||||
{4062, nullptr, "Unknown4062"}, //20.0.0+
|
||||
{4063, nullptr, "Unknown4063"}, //20.0.0+
|
||||
{4064, nullptr, "Unknown4064"}, //20.0.0+
|
||||
{4065, nullptr, "Unknown4065"}, //20.0.0+
|
||||
{4066, nullptr, "Unknown4066"}, //20.0.0+
|
||||
{4067, nullptr, "Unknown4067"}, //20.0.0+
|
||||
{4068, nullptr, "Unknown4068"}, //20.0.0+
|
||||
{4069, nullptr, "Unknown4069"}, //20.0.0+
|
||||
{4070, nullptr, "Unknown4070"}, //20.0.0+
|
||||
{4071, nullptr, "Unknown4071"}, //20.0.0+
|
||||
{4072, nullptr, "Unknown4072"}, //20.0.0+
|
||||
{4073, nullptr, "Unknown4073"}, //20.0.0+
|
||||
{4074, nullptr, "Unknown4074"}, //20.0.0+
|
||||
{4075, nullptr, "Unknown4075"}, //20.0.0+
|
||||
{4076, nullptr, "Unknown4076"}, //20.0.0+
|
||||
{4077, nullptr, "Unknown4077"}, //20.0.0+
|
||||
{4078, nullptr, "Unknown4078"}, //20.0.0+
|
||||
{4079, nullptr, "Unknown4079"}, //20.0.0+
|
||||
{4080, nullptr, "Unknown4080"}, //20.0.0+
|
||||
{4081, nullptr, "Unknown4081"}, //20.0.0+
|
||||
{4083, nullptr, "Unknown4083"}, //20.0.0+
|
||||
{4084, nullptr, "Unknown4084"}, //20.0.0+
|
||||
{4085, nullptr, "Unknown4085"}, //20.0.0+
|
||||
{4086, nullptr, "Unknown4086"}, //20.0.0+
|
||||
{4087, nullptr, "Unknown4087"}, //20.0.0+
|
||||
{4088, D<&IApplicationManagerInterface::Unknown4022>, "Unknown4088"}, //20.0.0+
|
||||
{4089, nullptr, "Unknown4089"}, //20.0.0+
|
||||
{4090, nullptr, "Unknown4090"}, //20.0.0+
|
||||
{4091, nullptr, "Unknown4091"}, //20.0.0+
|
||||
{4092, nullptr, "Unknown4092"}, //20.0.0+
|
||||
{4093, nullptr, "Unknown4093"}, //20.0.0+
|
||||
{4094, nullptr, "Unknown4094"}, //20.0.0+
|
||||
{4095, nullptr, "Unknown4095"}, //20.0.0+
|
||||
{4096, nullptr, "Unknown4096"}, //20.0.0+
|
||||
{4097, nullptr, "Unknown4097"}, //20.0.0+
|
||||
{4099, nullptr, "Unknown4099"}, //21.0.0+
|
||||
{5000, nullptr, "Unknown5000"}, //18.0.0+
|
||||
{5001, nullptr, "Unknown5001"}, //18.0.0+
|
||||
{9999, nullptr, "GetApplicationCertificate"}, //10.0.0-10.2.0
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 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
|
||||
|
||||
@@ -22,6 +25,7 @@ IContentManagementInterface::IContentManagementInterface(Core::System& system_)
|
||||
{601, nullptr, "ListApplicationContentMetaStatus"},
|
||||
{605, nullptr, "ListApplicationContentMetaStatusWithRightsCheck"},
|
||||
{607, nullptr, "IsAnyApplicationRunning"},
|
||||
{608, nullptr, "Unknown608"}, //21.0.0+
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -37,7 +37,11 @@ IDynamicRightsInterface::IDynamicRightsInterface(Core::System& system_)
|
||||
{23, nullptr, "GetLimitedApplicationLicenseUpgradableEvent"},
|
||||
{24, nullptr, "NotifyLimitedApplicationLicenseUpgradableEventForDebug"},
|
||||
{25, nullptr, "RequestProceedDynamicRightsState"},
|
||||
{26, D<&IDynamicRightsInterface::HasAccountRestrictedRightsInRunningApplications>, "HasAccountRestrictedRightsInRunningApplications"}
|
||||
{26, D<&IDynamicRightsInterface::HasAccountRestrictedRightsInRunningApplications>, "HasAccountRestrictedRightsInRunningApplications"},
|
||||
{27, nullptr, "Unknown27"}, //20.0.0+
|
||||
{28, nullptr, "Unknown28"}, //20.0.0+
|
||||
{29, nullptr, "Unknown29"}, //21.0.0+
|
||||
{30, nullptr, "Unknown30"}, //21.0.0+
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -16,64 +16,67 @@ IOlscServiceForSystemService::IOlscServiceForSystemService(Core::System& system_
|
||||
: ServiceFramework{system_, "olsc:s"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, D<&IOlscServiceForSystemService::OpenTransferTaskListController>, "OpenTransferTaskListController"},
|
||||
{1, D<&IOlscServiceForSystemService::OpenRemoteStorageController>, "OpenRemoteStorageController"},
|
||||
{2, D<&IOlscServiceForSystemService::OpenDaemonController>, "OpenDaemonController"},
|
||||
{10, nullptr, "Unknown10"},
|
||||
{11, nullptr, "Unknown11"},
|
||||
{12, nullptr, "Unknown12"},
|
||||
{13, nullptr, "Unknown13"},
|
||||
{0, D<&IOlscServiceForSystemService::GetTransferTaskListController>, "GetTransferTaskListController"},
|
||||
{1, D<&IOlscServiceForSystemService::GetRemoteStorageController>, "GetRemoteStorageController"},
|
||||
{2, D<&IOlscServiceForSystemService::GetDaemonController>, "GetDaemonController"},
|
||||
{10, nullptr, "PrepareDeleteUserProperty"},
|
||||
{11, nullptr, "DeleteUserSaveDataProperty"},
|
||||
{12, nullptr, "InvalidateMountCache"},
|
||||
{13, nullptr, "DeleteDeviceSaveDataProperty"},
|
||||
{100, nullptr, "ListLastTransferTaskErrorInfo"},
|
||||
{101, nullptr, "GetLastErrorInfoCount"},
|
||||
{102, nullptr, "RemoveLastErrorInfoOld"},
|
||||
{103, nullptr, "GetLastErrorInfo"},
|
||||
{104, nullptr, "GetLastErrorEventHolder"},
|
||||
{105, nullptr, "GetLastTransferTaskErrorInfo"},
|
||||
{200, D<&IOlscServiceForSystemService::GetDataTransferPolicyInfo>, "GetDataTransferPolicyInfo"},
|
||||
{201, nullptr, "RemoveDataTransferPolicyInfo"},
|
||||
{202, nullptr, "UpdateDataTransferPolicyOld"},
|
||||
{203, nullptr, "UpdateDataTransferPolicy"},
|
||||
{204, nullptr, "CleanupDataTransferPolicyInfo"},
|
||||
{205, nullptr, "RequestDataTransferPolicy"},
|
||||
{300, nullptr, "GetAutoTransferSeriesInfo"},
|
||||
{301, nullptr, "UpdateAutoTransferSeriesInfo"},
|
||||
{400, nullptr, "CleanupSaveDataArchiveInfoType1"},
|
||||
{900, nullptr, "CleanupTransferTask"},
|
||||
{902, nullptr, "CleanupSeriesInfoType0"},
|
||||
{903, nullptr, "CleanupSaveDataArchiveInfoType0"},
|
||||
{904, nullptr, "CleanupApplicationAutoTransferSetting"},
|
||||
{905, nullptr, "CleanupErrorHistory"},
|
||||
{906, nullptr, "SetLastError"},
|
||||
{907, nullptr, "AddSaveDataArchiveInfoType0"},
|
||||
{908, nullptr, "RemoveSeriesInfoType0"},
|
||||
{909, nullptr, "GetSeriesInfoType0"},
|
||||
{910, nullptr, "RemoveLastErrorInfo"},
|
||||
{911, nullptr, "CleanupSeriesInfoType1"},
|
||||
{912, nullptr, "RemoveSeriesInfoType1"},
|
||||
{913, nullptr, "GetSeriesInfoType1"},
|
||||
{200, D<&IOlscServiceForSystemService::GetDataTransferPolicy>, "GetDataTransferPolicy"},
|
||||
{201, nullptr, "DeleteDataTransferPolicyCache"},
|
||||
{202, nullptr, "Unknown202"},
|
||||
{203, nullptr, "RequestUpdateDataTransferPolicyCacheAsync"},
|
||||
{204, nullptr, "ClearDataTransferPolicyCache"},
|
||||
{205, nullptr, "RequestGetDataTransferPolicyAsync"},
|
||||
{206, nullptr, "Unknown206"}, //21.0.0+
|
||||
{300, nullptr, "GetUserSaveDataProperty"},
|
||||
{301, nullptr, "SetUserSaveDataProperty"},
|
||||
{302, nullptr, "Unknown302"}, //21.0.0+
|
||||
{400, nullptr, "CleanupSaveDataBackupContextForSpecificApplications"},
|
||||
{900, nullptr, "DeleteAllTransferTask"},
|
||||
{902, nullptr, "DeleteAllSeriesInfo"},
|
||||
{903, nullptr, "DeleteAllSdaInfoCache"},
|
||||
{904, nullptr, "DeleteAllApplicationSetting"},
|
||||
{905, nullptr, "DeleteAllTransferTaskErrorInfo"},
|
||||
{906, nullptr, "RegisterTransferTaskErrorInfo"},
|
||||
{907, nullptr, "AddSaveDataArchiveInfoCache"},
|
||||
{908, nullptr, "DeleteSeriesInfo"},
|
||||
{909, nullptr, "GetSeriesInfo"},
|
||||
{910, nullptr, "RemoveTransferTaskErrorInfo"},
|
||||
{911, nullptr, "DeleteAllSeriesInfoForSaveDataBackup"},
|
||||
{912, nullptr, "DeleteSeriesInfoForSaveDataBackup"},
|
||||
{913, nullptr, "GetSeriesInfoForSaveDataBackup"},
|
||||
{914, nullptr, "Unknown914"}, //20.2.0+
|
||||
{1000, nullptr, "UpdateIssueOld"},
|
||||
{1010, nullptr, "Unknown1010"},
|
||||
{1011, nullptr, "ListIssueInfoOld"},
|
||||
{1012, nullptr, "GetIssueOld"},
|
||||
{1013, nullptr, "GetIssue2Old"},
|
||||
{1014, nullptr, "GetIssue3Old"},
|
||||
{1020, nullptr, "RepairIssueOld"},
|
||||
{1021, nullptr, "RepairIssueWithUserIdOld"},
|
||||
{1022, nullptr, "RepairIssue2Old"},
|
||||
{1023, nullptr, "RepairIssue3Old"},
|
||||
{1011, nullptr, "Unknown1011"},
|
||||
{1012, nullptr, "Unknown1012"},
|
||||
{1013, nullptr, "Unkown1013"},
|
||||
{1014, nullptr, "Unknown1014"},
|
||||
{1020, nullptr, "Unknown1020"},
|
||||
{1021, nullptr, "Unknown1021"},
|
||||
{1022, nullptr, "Unknown1022"},
|
||||
{1023, nullptr, "Unknown1023"},
|
||||
{1024, nullptr, "Unknown1024"},
|
||||
{1100, nullptr, "UpdateIssue"},
|
||||
{1110, nullptr, "Unknown1110"},
|
||||
{1111, nullptr, "ListIssueInfo"},
|
||||
{1112, nullptr, "GetIssue"},
|
||||
{1113, nullptr, "GetIssue2"},
|
||||
{1114, nullptr, "GetIssue3"},
|
||||
{1120, nullptr, "RepairIssue"},
|
||||
{1121, nullptr, "RepairIssueWithUserId"},
|
||||
{1122, nullptr, "RepairIssue2"},
|
||||
{1123, nullptr, "RepairIssue3"},
|
||||
{1124, nullptr, "Unknown1124"},
|
||||
{10000, D<&IOlscServiceForSystemService::CloneService>, "CloneService"},
|
||||
{1100, nullptr, "RepairUpdateIssueInfoCacheAync"},
|
||||
{1110, nullptr, "RepairGetIssueInfo"},
|
||||
{1111, nullptr, "RepairListIssueInfo"},
|
||||
{1112, nullptr, "RepairListOperationPermissionInfo"},
|
||||
{1113, nullptr, "RepairListDataInfoForRepairedSaveDataDownload"},
|
||||
{1114, nullptr, "RepairListDataInfoForOriginalSaveDataDownload"},
|
||||
{1120, nullptr, "RepairUploadSaveDataAsync"},
|
||||
{1121, nullptr, "RepairUploadSaveDataAsync1"},
|
||||
{1122, nullptr, "RepairDownloadRepairedSaveDataAsync"},
|
||||
{1123, nullptr, "RepairDownloadOriginalSaveDataAsync"},
|
||||
{1124, nullptr, "RepairGetOperationProgressInfo"},
|
||||
{10000, D<&IOlscServiceForSystemService::GetOlscServiceForSystemService>, "GetOlscServiceForSystemService"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -82,38 +85,38 @@ IOlscServiceForSystemService::IOlscServiceForSystemService(Core::System& system_
|
||||
|
||||
IOlscServiceForSystemService::~IOlscServiceForSystemService() = default;
|
||||
|
||||
Result IOlscServiceForSystemService::OpenTransferTaskListController(
|
||||
Result IOlscServiceForSystemService::GetTransferTaskListController(
|
||||
Out<SharedPointer<ITransferTaskListController>> out_interface) {
|
||||
LOG_INFO(Service_OLSC, "called");
|
||||
*out_interface = std::make_shared<ITransferTaskListController>(system);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IOlscServiceForSystemService::OpenRemoteStorageController(
|
||||
Result IOlscServiceForSystemService::GetRemoteStorageController(
|
||||
Out<SharedPointer<IRemoteStorageController>> out_interface) {
|
||||
LOG_INFO(Service_OLSC, "called");
|
||||
*out_interface = std::make_shared<IRemoteStorageController>(system);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IOlscServiceForSystemService::OpenDaemonController(
|
||||
Result IOlscServiceForSystemService::GetDaemonController(
|
||||
Out<SharedPointer<IDaemonController>> out_interface) {
|
||||
LOG_INFO(Service_OLSC, "called");
|
||||
*out_interface = std::make_shared<IDaemonController>(system);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IOlscServiceForSystemService::GetDataTransferPolicyInfo(
|
||||
Out<DataTransferPolicy> out_policy_info, u64 application_id) {
|
||||
Result IOlscServiceForSystemService::GetDataTransferPolicy(
|
||||
Out<DataTransferPolicy> out_policy, u64 application_id) {
|
||||
LOG_WARNING(Service_OLSC, "(STUBBED) called");
|
||||
DataTransferPolicy policy{};
|
||||
policy.upload_policy = 0;
|
||||
policy.download_policy = 0;
|
||||
*out_policy_info = policy;
|
||||
*out_policy = policy;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IOlscServiceForSystemService::CloneService(
|
||||
Result IOlscServiceForSystemService::GetOlscServiceForSystemService(
|
||||
Out<SharedPointer<IOlscServiceForSystemService>> out_interface) {
|
||||
LOG_INFO(Service_OLSC, "called");
|
||||
*out_interface = std::static_pointer_cast<IOlscServiceForSystemService>(shared_from_this());
|
||||
|
||||
@@ -24,12 +24,12 @@ public:
|
||||
~IOlscServiceForSystemService() override;
|
||||
|
||||
private:
|
||||
Result OpenTransferTaskListController(
|
||||
Result GetTransferTaskListController(
|
||||
Out<SharedPointer<ITransferTaskListController>> out_interface);
|
||||
Result OpenRemoteStorageController(Out<SharedPointer<IRemoteStorageController>> out_interface);
|
||||
Result OpenDaemonController(Out<SharedPointer<IDaemonController>> out_interface);
|
||||
Result GetDataTransferPolicyInfo(Out<DataTransferPolicy> out_policy_info, u64 application_id);
|
||||
Result CloneService(Out<SharedPointer<IOlscServiceForSystemService>> out_interface);
|
||||
Result GetRemoteStorageController(Out<SharedPointer<IRemoteStorageController>> out_interface);
|
||||
Result GetDaemonController(Out<SharedPointer<IDaemonController>> out_interface);
|
||||
Result GetDataTransferPolicy(Out<DataTransferPolicy> out_policy, u64 application_id);
|
||||
Result GetOlscServiceForSystemService(Out<SharedPointer<IOlscServiceForSystemService>> out_interface);
|
||||
};
|
||||
|
||||
} // namespace Service::OLSC
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 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
|
||||
|
||||
@@ -11,32 +14,37 @@ ITransferTaskListController::ITransferTaskListController(Core::System& system_)
|
||||
: ServiceFramework{system_, "ITransferTaskListController"} {
|
||||
// clang-format off
|
||||
static const FunctionInfo functions[] = {
|
||||
{0, nullptr, "Unknown0"},
|
||||
{1, nullptr, "Unknown1"},
|
||||
{2, nullptr, "Unknown2"},
|
||||
{3, nullptr, "Unknown3"},
|
||||
{4, nullptr, "Unknown4"},
|
||||
{5, D<&ITransferTaskListController::GetNativeHandleHolder>, "GetNativeHandleHolder"},
|
||||
{6, nullptr, "Unknown6"},
|
||||
{7, nullptr, "Unknown7"},
|
||||
{8, nullptr, "GetRemoteStorageController"},
|
||||
{9, D<&ITransferTaskListController::GetNativeHandleHolder>, "GetNativeHandleHolder2"},
|
||||
{10, nullptr, "Unknown10"},
|
||||
{11, nullptr, "Unknown11"},
|
||||
{12, nullptr, "Unknown12"},
|
||||
{13, nullptr, "Unknown13"},
|
||||
{14, nullptr, "Unknown14"},
|
||||
{15, nullptr, "Unknown15"},
|
||||
{16, nullptr, "Unknown16"},
|
||||
{17, nullptr, "Unknown17"},
|
||||
{18, nullptr, "Unknown18"},
|
||||
{19, nullptr, "Unknown19"},
|
||||
{20, nullptr, "Unknown20"},
|
||||
{21, nullptr, "Unknown21"},
|
||||
{22, nullptr, "Unknown22"},
|
||||
{23, nullptr, "Unknown23"},
|
||||
{24, nullptr, "Unknown24"},
|
||||
{25, nullptr, "Unknown25"},
|
||||
{0, nullptr, "GetTransferTaskCountForOcean"},
|
||||
{1, nullptr, "GetTransferTaskInfoForOcean"},
|
||||
{2, nullptr, "ListTransferTaskInfoForOcean"},
|
||||
{3, nullptr, "DeleteTransferTaskForOcean"},
|
||||
{4, nullptr, "RaiseTransferTaskPriorityForOcean"},
|
||||
{5, D<&ITransferTaskListController::GetTransferTaskEndEventNativeHandleHolder>, "GetTransferTaskEndEventNativeHandleHolder"},
|
||||
{6, nullptr, "GetTransferTaskProgressForOcean"},
|
||||
{7, nullptr, "GetTransferTaskLastResultForOcean"},
|
||||
{8, nullptr, "StopNextTransferTaskExecution"},
|
||||
{9, D<&ITransferTaskListController::GetTransferTaskStartEventNativeHandleHolder>, "GetTransferTaskStartEventNativeHandleHolder"},
|
||||
{10, nullptr, "SuspendTransferTaskForOcean"},
|
||||
{11, nullptr, "GetCurrentTransferTaskInfoForOcean"},
|
||||
{12, nullptr, "FindTransferTaskInfoForOcean"},
|
||||
{13, nullptr, "CancelCurrentRepairTransferTask"},
|
||||
{14, nullptr, "GetRepairTransferTaskProgress"},
|
||||
{15, nullptr, "EnsureExecutableForRepairTransferTask"},
|
||||
{16, nullptr, "GetTransferTaskCount"},
|
||||
{17, nullptr, "GetTransferTaskInfo"},
|
||||
{18, nullptr, "ListTransferTaskInfo"},
|
||||
{19, nullptr, "DeleteTransferTask"},
|
||||
{20, nullptr, "RaiseTransferTaskPriority"},
|
||||
{21, nullptr, "GetTransferTaskProgress"},
|
||||
{22, nullptr, "GetTransferTaskLastResult"},
|
||||
{23, nullptr, "SuspendTransferTask"},
|
||||
{24, nullptr, "GetCurrentTransferTaskInfo"},
|
||||
{25, nullptr, "Unknown25"}, //20.1.0+
|
||||
{26, nullptr, "Unknown26"}, //20.1.0+
|
||||
{27, nullptr, "Unknown27"}, //20.1.0+
|
||||
{28, nullptr, "Unknown28"}, //20.1.0+
|
||||
{29, nullptr, "Unknown29"}, //20.1.0+
|
||||
{30, nullptr, "Unknown30"}, //20.1.0+
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
@@ -45,7 +53,14 @@ ITransferTaskListController::ITransferTaskListController(Core::System& system_)
|
||||
|
||||
ITransferTaskListController::~ITransferTaskListController() = default;
|
||||
|
||||
Result ITransferTaskListController::GetNativeHandleHolder(
|
||||
Result ITransferTaskListController::GetTransferTaskEndEventNativeHandleHolder(
|
||||
Out<SharedPointer<INativeHandleHolder>> out_holder) {
|
||||
LOG_WARNING(Service_OLSC, "(STUBBED) called");
|
||||
*out_holder = std::make_shared<INativeHandleHolder>(system);
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result ITransferTaskListController::GetTransferTaskStartEventNativeHandleHolder(
|
||||
Out<SharedPointer<INativeHandleHolder>> out_holder) {
|
||||
LOG_WARNING(Service_OLSC, "(STUBBED) called");
|
||||
*out_holder = std::make_shared<INativeHandleHolder>(system);
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 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
|
||||
|
||||
@@ -14,7 +17,8 @@ public:
|
||||
~ITransferTaskListController() override;
|
||||
|
||||
private:
|
||||
Result GetNativeHandleHolder(Out<SharedPointer<INativeHandleHolder>> out_holder);
|
||||
Result GetTransferTaskEndEventNativeHandleHolder(Out<SharedPointer<INativeHandleHolder>> out_holder);
|
||||
Result GetTransferTaskStartEventNativeHandleHolder(Out<SharedPointer<INativeHandleHolder>> out_holder);
|
||||
};
|
||||
|
||||
} // namespace Service::OLSC
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 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
|
||||
|
||||
@@ -34,10 +37,10 @@ public:
|
||||
{17, nullptr, "AcquireIrq"},
|
||||
{18, nullptr, "ReleaseIrq"},
|
||||
{19, nullptr, "SetIrqEnable"},
|
||||
{20, nullptr, "SetAspmEnable"},
|
||||
{21, nullptr, "SetResetUponResumeEnable"},
|
||||
{22, nullptr, "ResetFunction"},
|
||||
{23, nullptr, "Unknown23"},
|
||||
{20, nullptr, "GetIrqEvent"},
|
||||
{21, nullptr, "SetAspmEnable"},
|
||||
{22, nullptr, "SetResetUponResumeEnable"},
|
||||
{23, nullptr, "ResetFunction"},
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
|
||||
@@ -39,6 +39,9 @@ IParentalControlService::IParentalControlService(Core::System& system_, Capabili
|
||||
{1017, D<&IParentalControlService::EndFreeCommunication>, "EndFreeCommunication"},
|
||||
{1018, D<&IParentalControlService::IsFreeCommunicationAvailable>, "IsFreeCommunicationAvailable"},
|
||||
{1019, D<&IParentalControlService::ConfirmLaunchApplicationPermission>, "ConfirmLaunchApplicationPermission"},
|
||||
{1020, nullptr, "ConfirmLaunchSharedApplicationPermission"}, //20.0.0+
|
||||
{1021, nullptr, "TryBeginFreeCommunicationForStreamPlay"}, //21.0.0+
|
||||
{1022, nullptr, "EndFreeCommunicationForStreamPlay"}, //21.0.0+
|
||||
{1031, D<&IParentalControlService::IsRestrictionEnabled>, "IsRestrictionEnabled"},
|
||||
{1032, D<&IParentalControlService::GetSafetyLevel>, "GetSafetyLevel"},
|
||||
{1033, nullptr, "SetSafetyLevel"},
|
||||
@@ -56,6 +59,8 @@ IParentalControlService::IParentalControlService(Core::System& system_, Capabili
|
||||
{1047, nullptr, "NotifyApplicationDownloadStarted"},
|
||||
{1048, nullptr, "NotifyNetworkProfileCreated"},
|
||||
{1049, nullptr, "ResetFreeCommunicationApplicationList"},
|
||||
{1050, nullptr, "AddToFreeCommunicationApplicationList"}, //20.0.0+
|
||||
{1051, nullptr, "NotifyApplicationDownloadStarted"}, //20.0.0+
|
||||
{1061, D<&IParentalControlService::ConfirmStereoVisionRestrictionConfigurable>, "ConfirmStereoVisionRestrictionConfigurable"},
|
||||
{1062, D<&IParentalControlService::GetStereoVisionRestriction>, "GetStereoVisionRestriction"},
|
||||
{1063, D<&IParentalControlService::SetStereoVisionRestriction>, "SetStereoVisionRestriction"},
|
||||
@@ -126,8 +131,17 @@ IParentalControlService::IParentalControlService(Core::System& system_, Capabili
|
||||
{2013, nullptr, "SynchronizeParentalControlSettingsAsync"},
|
||||
{2014, nullptr, "FinishSynchronizeParentalControlSettings"},
|
||||
{2015, nullptr, "FinishSynchronizeParentalControlSettingsWithLastUpdated"},
|
||||
{2016, nullptr, "RequestUpdateExemptionListAsync"},
|
||||
{145601, D<&IParentalControlService::GetPlayTimerSettings>, "GetPlayTimerSettings"} // 18.0.0+
|
||||
{2016, nullptr, "RequestUpdateExemptionListAsync"}, //5.0.0+
|
||||
{145601, D<&IParentalControlService::GetPlayTimerSettings>, "GetPlayTimerSettings"}, // 18.0.0+
|
||||
{2017, nullptr, "AuthorizePairingAsync"}, //19.0.0+
|
||||
{2019, nullptr, "RequestUpdateDeviceUsersBackground"}, //19.0.0+
|
||||
{2021, nullptr, "RequestCopyPairingAsync"}, //20.0.0+
|
||||
{2022, nullptr, "FinishRequestCopyPairing"}, //20.0.0+
|
||||
{2023, nullptr, "IsFromPairingActiveDevice"}, //20.0.0+
|
||||
{2024, nullptr, "RollbackCopyPairing"}, //21.0.0+
|
||||
{3001, nullptr, "GetErrorContextChangedEvent"}, //20.0.0+
|
||||
{145601, D<&IParentalControlService::GetPlayTimerSettings>, "GetPlayTimerSettings"}, // 18.0.0+
|
||||
{195101, D<&IParentalControlService::SetPlayTimerSettings>, "SetPlayTimerSettingsForDebug"}, //18.0.0+
|
||||
};
|
||||
// clang-format on
|
||||
RegisterHandlers(functions);
|
||||
@@ -393,16 +407,21 @@ Result IParentalControlService::IsRestrictedByPlayTimer(Out<bool> out_is_restric
|
||||
}
|
||||
|
||||
Result IParentalControlService::GetPlayTimerSettingsOld(
|
||||
Out<PlayTimerSettings> out_play_timer_settings) {
|
||||
Out<PlayTimerSettingsOld> out_play_timer_settings) {
|
||||
LOG_WARNING(Service_PCTL, "(STUBBED) called");
|
||||
*out_play_timer_settings = {};
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IParentalControlService::GetPlayTimerSettings(
|
||||
Out<PlayTimerSettings> out_play_timer_settings) {
|
||||
Result IParentalControlService::GetPlayTimerSettings(Out<PlayTimerSettings> out_play_timer_settings) {
|
||||
LOG_WARNING(Service_PCTL, "(STUBBED) called");
|
||||
*out_play_timer_settings = {};
|
||||
*out_play_timer_settings = raw_play_timer_settings;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
Result IParentalControlService::SetPlayTimerSettings(PlayTimerSettings play_timer_settings) {
|
||||
LOG_WARNING(Service_PCTL, "(STUBBED) called");
|
||||
raw_play_timer_settings = play_timer_settings;
|
||||
R_SUCCEED();
|
||||
}
|
||||
|
||||
|
||||
@@ -51,7 +51,7 @@ private:
|
||||
Result IsPlayTimerEnabled(Out<bool> out_is_play_timer_enabled);
|
||||
Result GetPlayTimerRemainingTime(Out<s32> out_remaining_time);
|
||||
Result IsRestrictedByPlayTimer(Out<bool> out_is_restricted_by_play_timer);
|
||||
Result GetPlayTimerSettingsOld(Out<PlayTimerSettings> out_play_timer_settings);
|
||||
Result GetPlayTimerSettingsOld(Out<PlayTimerSettingsOld> out_play_timer_settings);
|
||||
Result GetPlayTimerEventToRequestSuspension(OutCopyHandle<Kernel::KReadableEvent> out_event);
|
||||
Result IsPlayTimerAlarmDisabled(Out<bool> out_play_timer_alarm_disabled);
|
||||
Result GetPlayTimerRemainingTimeDisplayInfo();
|
||||
@@ -60,6 +60,7 @@ private:
|
||||
Result SetStereoVisionRestriction(bool stereo_vision_restriction);
|
||||
Result ResetConfirmedStereoVisionPermission();
|
||||
Result GetPlayTimerSettings(Out<PlayTimerSettings> out_play_timer_settings);
|
||||
Result SetPlayTimerSettings(PlayTimerSettings out_play_timer_settings);
|
||||
|
||||
struct States {
|
||||
u64 current_tid{};
|
||||
@@ -83,6 +84,8 @@ private:
|
||||
RestrictionSettings restriction_settings{};
|
||||
std::array<char, 8> pin_code{};
|
||||
Capability capability{};
|
||||
// TODO: this is RAW as fuck
|
||||
PlayTimerSettings raw_play_timer_settings{};
|
||||
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
Event synchronization_event;
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 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
|
||||
|
||||
@@ -34,10 +37,16 @@ struct RestrictionSettings {
|
||||
};
|
||||
static_assert(sizeof(RestrictionSettings) == 0x3, "RestrictionSettings has incorrect size.");
|
||||
|
||||
// This is nn::pctl::PlayTimerSettings
|
||||
struct PlayTimerSettings {
|
||||
// This is nn::pctl::PlayTimerSettingsOld
|
||||
struct PlayTimerSettingsOld {
|
||||
std::array<u32, 13> settings;
|
||||
};
|
||||
static_assert(sizeof(PlayTimerSettings) == 0x34, "PlayTimerSettings has incorrect size.");
|
||||
static_assert(sizeof(PlayTimerSettingsOld) == 0x34, "PlayTimerSettingsOld has incorrect size.");
|
||||
|
||||
// This is nn::pctl::PlayTimerSettings
|
||||
struct PlayTimerSettings {
|
||||
std::array<u32, 17> settings; //21.0.0+ now takes 0x44
|
||||
};
|
||||
static_assert(sizeof(PlayTimerSettings) == 0x44, "PlayTimerSettings has incorrect size.");
|
||||
|
||||
} // namespace Service::PCTL
|
||||
|
||||
@@ -34,9 +34,9 @@ public:
|
||||
{10300, &PlayReport::GetTransmissionStatus, "GetTransmissionStatus"},
|
||||
{10400, &PlayReport::GetSystemSessionId, "GetSystemSessionId"},
|
||||
{20100, &PlayReport::SaveSystemReportOld, "SaveSystemReport"},
|
||||
{20101, &PlayReport::SaveSystemReportWithUserOld, "SaveSystemReportWithUser"},
|
||||
{20102, &PlayReport::SaveSystemReport, "SaveSystemReport"},
|
||||
{20103, &PlayReport::SaveSystemReportWithUser, "SaveSystemReportWithUser"},
|
||||
{20101, &PlayReport::SaveSystemReportWithUserOld, "SaveSystemReportWithUser"},
|
||||
{20102, &PlayReport::SaveSystemReport, "SaveSystemReport"},
|
||||
{20103, &PlayReport::SaveSystemReportWithUser, "SaveSystemReportWithUser"},
|
||||
{20200, nullptr, "SetOperationMode"},
|
||||
{30100, nullptr, "ClearStorage"},
|
||||
{30200, nullptr, "ClearStatistics"},
|
||||
|
||||
@@ -18,49 +18,43 @@
|
||||
|
||||
namespace Service {
|
||||
|
||||
/**
|
||||
* Creates a function string for logging, complete with the name (or header code, depending
|
||||
* on what's passed in) the port name, and all the cmd_buff arguments.
|
||||
*/
|
||||
[[maybe_unused]] static std::string MakeFunctionString(std::string_view name,
|
||||
std::string_view port_name,
|
||||
const u32* cmd_buff) {
|
||||
/// @brief Creates a function string for logging, complete with the name (or header code, depending
|
||||
/// on what's passed in) the port name, and all the cmd_buff arguments.
|
||||
[[maybe_unused]] static std::string MakeFunctionString(std::string_view name, std::string_view port_name, const u32* cmd_buff) {
|
||||
// Number of params == bits 0-5 + bits 6-11
|
||||
int num_params = (cmd_buff[0] & 0x3F) + ((cmd_buff[0] >> 6) & 0x3F);
|
||||
|
||||
std::string function_string = fmt::format("function '{}': port={}", name, port_name);
|
||||
for (int i = 1; i <= num_params; ++i) {
|
||||
|
||||
for (int i = 1; i <= num_params; ++i)
|
||||
function_string += fmt::format(", cmd_buff[{}]={:#X}", i, cmd_buff[i]);
|
||||
}
|
||||
|
||||
return function_string;
|
||||
}
|
||||
|
||||
ServiceFrameworkBase::ServiceFrameworkBase(Core::System& system_, const char* service_name_,
|
||||
u32 max_sessions_, InvokerFn* handler_invoker_)
|
||||
: SessionRequestHandler(system_.Kernel(), service_name_), system{system_},
|
||||
service_name{service_name_}, max_sessions{max_sessions_}, handler_invoker{handler_invoker_} {}
|
||||
service_name{service_name_}, handler_invoker{handler_invoker_}, max_sessions{max_sessions_} {}
|
||||
|
||||
ServiceFrameworkBase::~ServiceFrameworkBase() {
|
||||
// Wait for other threads to release access before destroying
|
||||
const auto guard = LockService();
|
||||
const auto guard = ServiceFrameworkBase::LockService();
|
||||
}
|
||||
|
||||
void ServiceFrameworkBase::RegisterHandlersBase(const FunctionInfoBase* functions, std::size_t n) {
|
||||
// Usually this array is sorted by id already, so hint to insert at the end
|
||||
handlers.reserve(handlers.size() + n);
|
||||
for (std::size_t i = 0; i < n; ++i) {
|
||||
// Usually this array is sorted by id already, so hint to insert at the end
|
||||
for (std::size_t i = 0; i < n; ++i)
|
||||
handlers.emplace_hint(handlers.cend(), functions[i].expected_header, functions[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void ServiceFrameworkBase::RegisterHandlersBaseTipc(const FunctionInfoBase* functions,
|
||||
std::size_t n) {
|
||||
void ServiceFrameworkBase::RegisterHandlersBaseTipc(const FunctionInfoBase* functions, std::size_t n) {
|
||||
// Usually this array is sorted by id already, so hint to insert at the end
|
||||
handlers_tipc.reserve(handlers_tipc.size() + n);
|
||||
for (std::size_t i = 0; i < n; ++i) {
|
||||
// Usually this array is sorted by id already, so hint to insert at the end
|
||||
for (std::size_t i = 0; i < n; ++i)
|
||||
handlers_tipc.emplace_hint(handlers_tipc.cend(), functions[i].expected_header,
|
||||
functions[i]);
|
||||
}
|
||||
}
|
||||
|
||||
void ServiceFrameworkBase::ReportUnimplementedFunction(HLERequestContext& ctx,
|
||||
@@ -69,15 +63,12 @@ void ServiceFrameworkBase::ReportUnimplementedFunction(HLERequestContext& ctx,
|
||||
std::string function_name = info == nullptr ? "<unknown>" : info->name;
|
||||
|
||||
fmt::memory_buffer buf;
|
||||
fmt::format_to(std::back_inserter(buf), "function '{}({})': port='{}' cmd_buf={{[0]={:#X}",
|
||||
ctx.GetCommand(), function_name, service_name, cmd_buf[0]);
|
||||
for (int i = 1; i <= 8; ++i) {
|
||||
fmt::format_to(std::back_inserter(buf), "function '{}({})': port='{}' cmd_buf={{[0]={:#X}", ctx.GetCommand(), function_name, service_name, cmd_buf[0]);
|
||||
for (int i = 1; i <= 8; ++i)
|
||||
fmt::format_to(std::back_inserter(buf), ", [{}]={:#X}", i, cmd_buf[i]);
|
||||
}
|
||||
buf.push_back('}');
|
||||
|
||||
system.GetReporter().SaveUnimplementedFunctionReport(ctx, ctx.GetCommand(), function_name,
|
||||
service_name);
|
||||
system.GetReporter().SaveUnimplementedFunctionReport(ctx, ctx.GetCommand(), function_name, service_name);
|
||||
UNIMPLEMENTED_MSG("Unknown / unimplemented {}", fmt::to_string(buf));
|
||||
if (Settings::values.use_auto_stub) {
|
||||
LOG_WARNING(Service, "Using auto stub fallback!");
|
||||
@@ -87,25 +78,20 @@ void ServiceFrameworkBase::ReportUnimplementedFunction(HLERequestContext& ctx,
|
||||
}
|
||||
|
||||
void ServiceFrameworkBase::InvokeRequest(HLERequestContext& ctx) {
|
||||
auto itr = handlers.find(ctx.GetCommand());
|
||||
const FunctionInfoBase* info = itr == handlers.end() ? nullptr : &itr->second;
|
||||
if (info == nullptr || info->handler_callback == nullptr) {
|
||||
auto it = handlers.find(ctx.GetCommand());
|
||||
FunctionInfoBase const* info = it == handlers.end() ? nullptr : &it->second;
|
||||
if (info == nullptr || info->handler_callback == nullptr)
|
||||
return ReportUnimplementedFunction(ctx, info);
|
||||
}
|
||||
|
||||
LOG_TRACE(Service, "{}", MakeFunctionString(info->name, GetServiceName(), ctx.CommandBuffer()));
|
||||
handler_invoker(this, info->handler_callback, ctx);
|
||||
}
|
||||
|
||||
void ServiceFrameworkBase::InvokeRequestTipc(HLERequestContext& ctx) {
|
||||
boost::container::flat_map<u32, FunctionInfoBase>::iterator itr;
|
||||
|
||||
itr = handlers_tipc.find(ctx.GetCommand());
|
||||
|
||||
const FunctionInfoBase* info = itr == handlers_tipc.end() ? nullptr : &itr->second;
|
||||
if (info == nullptr || info->handler_callback == nullptr) {
|
||||
auto it = handlers_tipc.find(ctx.GetCommand());
|
||||
FunctionInfoBase const* info = it == handlers_tipc.end() ? nullptr : &it->second;
|
||||
if (info == nullptr || info->handler_callback == nullptr)
|
||||
return ReportUnimplementedFunction(ctx, info);
|
||||
}
|
||||
|
||||
LOG_TRACE(Service, "{}", MakeFunctionString(info->name, GetServiceName(), ctx.CommandBuffer()));
|
||||
handler_invoker(this, info->handler_callback, ctx);
|
||||
|
||||
@@ -1,3 +1,6 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 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
|
||||
|
||||
@@ -47,25 +50,23 @@ static_assert(ServerSessionCountMax == 0x40,
|
||||
class ServiceFrameworkBase : public SessionRequestHandler {
|
||||
public:
|
||||
/// Returns the string identifier used to connect to the service.
|
||||
std::string GetServiceName() const {
|
||||
[[nodiscard]] std::string_view GetServiceName() const noexcept {
|
||||
return service_name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the maximum number of sessions that can be connected to this service at the same
|
||||
* time.
|
||||
*/
|
||||
u32 GetMaxSessions() const {
|
||||
/// @brief Returns the maximum number of sessions that can be connected to this service at the same
|
||||
/// time.
|
||||
u32 GetMaxSessions() const noexcept {
|
||||
return max_sessions;
|
||||
}
|
||||
|
||||
/// Invokes a service request routine using the HIPC protocol.
|
||||
/// @brief Invokes a service request routine using the HIPC protocol.
|
||||
void InvokeRequest(HLERequestContext& ctx);
|
||||
|
||||
/// Invokes a service request routine using the HIPC protocol.
|
||||
/// @brief Invokes a service request routine using the HIPC protocol.
|
||||
void InvokeRequestTipc(HLERequestContext& ctx);
|
||||
|
||||
/// Handles a synchronization request for the service.
|
||||
/// @brief Handles a synchronization request for the service.
|
||||
Result HandleSyncRequest(Kernel::KServerSession& session, HLERequestContext& context) override;
|
||||
|
||||
protected:
|
||||
@@ -74,7 +75,7 @@ protected:
|
||||
using HandlerFnP = void (Self::*)(HLERequestContext&);
|
||||
|
||||
/// Used to gain exclusive access to the service members, e.g. from CoreTiming thread.
|
||||
[[nodiscard]] virtual std::unique_lock<std::mutex> LockService() {
|
||||
[[nodiscard]] virtual std::unique_lock<std::mutex> LockService() noexcept {
|
||||
return std::unique_lock{lock_service};
|
||||
}
|
||||
|
||||
@@ -105,20 +106,19 @@ private:
|
||||
void RegisterHandlersBaseTipc(const FunctionInfoBase* functions, std::size_t n);
|
||||
void ReportUnimplementedFunction(HLERequestContext& ctx, const FunctionInfoBase* info);
|
||||
|
||||
boost::container::flat_map<u32, FunctionInfoBase> handlers;
|
||||
boost::container::flat_map<u32, FunctionInfoBase> handlers_tipc;
|
||||
/// Used to gain exclusive access to the service members, e.g. from CoreTiming thread.
|
||||
std::mutex lock_service;
|
||||
/// Function used to safely up-cast pointers to the derived class before invoking a handler.
|
||||
InvokerFn* handler_invoker;
|
||||
|
||||
/// Maximum number of concurrent sessions that this service can handle.
|
||||
u32 max_sessions;
|
||||
|
||||
/// Flag to store if a port was already create/installed to detect multiple install attempts,
|
||||
/// which is not supported.
|
||||
bool service_registered = false;
|
||||
|
||||
/// Function used to safely up-cast pointers to the derived class before invoking a handler.
|
||||
InvokerFn* handler_invoker;
|
||||
boost::container::flat_map<u32, FunctionInfoBase> handlers;
|
||||
boost::container::flat_map<u32, FunctionInfoBase> handlers_tipc;
|
||||
|
||||
/// Used to gain exclusive access to the service members, e.g. from CoreTiming thread.
|
||||
std::mutex lock_service;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -142,20 +142,12 @@ protected:
|
||||
// TODO(yuriks): This function could be constexpr, but clang is the only compiler that
|
||||
// doesn't emit an ICE or a wrong diagnostic because of the static_cast.
|
||||
|
||||
/**
|
||||
* Constructs a FunctionInfo for a function.
|
||||
*
|
||||
* @param expected_header_ request header in the command buffer which will trigger dispatch
|
||||
* to this handler
|
||||
* @param handler_callback_ member function in this service which will be called to handle
|
||||
* the request
|
||||
* @param name_ human-friendly name for the request. Used mostly for logging purposes.
|
||||
*/
|
||||
FunctionInfoTyped(u32 expected_header_, HandlerFnP<T> handler_callback_, const char* name_)
|
||||
: FunctionInfoBase{
|
||||
expected_header_,
|
||||
// Type-erase member function pointer by casting it down to the base class.
|
||||
static_cast<HandlerFnP<ServiceFrameworkBase>>(handler_callback_), name_} {}
|
||||
/// @brief Constructs a FunctionInfo for a function.
|
||||
/// @param expected_header_ request header in the command buffer which will trigger dispatch to this handler
|
||||
/// @param handler_callback_ member function in this service which will be called to handle the request
|
||||
/// @param name_ human-friendly name for the request. Used mostly for logging purposes.
|
||||
constexpr FunctionInfoTyped(u32 expected_header_, HandlerFnP<T> handler_callback_, const char* name_)
|
||||
: FunctionInfoBase{expected_header_, HandlerFnP<ServiceFrameworkBase>(handler_callback_), name_} {}
|
||||
};
|
||||
using FunctionInfo = FunctionInfoTyped<Self>;
|
||||
|
||||
|
||||
@@ -16,7 +16,6 @@
|
||||
#include "core/hle/service/btdrv/btdrv.h"
|
||||
#include "core/hle/service/btm/btm.h"
|
||||
#include "core/hle/service/caps/caps.h"
|
||||
#include "core/hle/service/dmnt/dmnt.h"
|
||||
#include "core/hle/service/erpt/erpt.h"
|
||||
#include "core/hle/service/es/es.h"
|
||||
#include "core/hle/service/eupld/eupld.h"
|
||||
@@ -108,7 +107,6 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system
|
||||
{"btdrv", &BtDrv::LoopProcess},
|
||||
{"btm", &BTM::LoopProcess},
|
||||
{"capsrv", &Capture::LoopProcess},
|
||||
{"dmnt", &DMNT::LoopProcess},
|
||||
{"erpt", &ERPT::LoopProcess},
|
||||
{"es", &ES::LoopProcess},
|
||||
{"eupld", &EUPLD::LoopProcess},
|
||||
|
||||
@@ -1082,8 +1082,7 @@ BSD::~BSD() {
|
||||
}
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> BSD::LockService() {
|
||||
// Do not lock socket IClient instances.
|
||||
std::unique_lock<std::mutex> BSD::LockService() noexcept {
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
@@ -188,7 +188,7 @@ private:
|
||||
Network::RoomMember::CallbackHandle<Network::ProxyPacket> proxy_packet_received;
|
||||
|
||||
protected:
|
||||
virtual std::unique_lock<std::mutex> LockService() override;
|
||||
std::unique_lock<std::mutex> LockService() noexcept override;
|
||||
};
|
||||
|
||||
class BSDCFG final : public ServiceFramework<BSDCFG> {
|
||||
|
||||
286
src/core/memory/cheat_engine.cpp
Normal file
286
src/core/memory/cheat_engine.cpp
Normal file
@@ -0,0 +1,286 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 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
|
||||
|
||||
#include <locale>
|
||||
#include "common/hex_util.h"
|
||||
#include "common/swap.h"
|
||||
#include "core/arm/debug.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/kernel/k_page_table.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
#include "core/hle/kernel/k_process_page_table.h"
|
||||
#include "core/hle/kernel/svc_types.h"
|
||||
#include "core/hle/service/hid/hid_server.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
#include "core/memory.h"
|
||||
#include "core/memory/cheat_engine.h"
|
||||
#include "hid_core/resource_manager.h"
|
||||
#include "hid_core/resources/npad/npad.h"
|
||||
|
||||
namespace Core::Memory {
|
||||
namespace {
|
||||
constexpr auto CHEAT_ENGINE_NS = std::chrono::nanoseconds{1000000000 / 12};
|
||||
|
||||
std::string_view ExtractName(std::size_t& out_name_size, std::string_view data,
|
||||
std::size_t start_index, char match) {
|
||||
auto end_index = start_index;
|
||||
while (data[end_index] != match) {
|
||||
++end_index;
|
||||
if (end_index > data.size()) {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
out_name_size = end_index - start_index;
|
||||
|
||||
// Clamp name if it's too big
|
||||
if (out_name_size > sizeof(CheatDefinition::readable_name)) {
|
||||
end_index = start_index + sizeof(CheatDefinition::readable_name);
|
||||
}
|
||||
|
||||
return data.substr(start_index, end_index - start_index);
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
StandardVmCallbacks::StandardVmCallbacks(System& system_, const CheatProcessMetadata& metadata_)
|
||||
: metadata{metadata_}, system{system_} {}
|
||||
|
||||
StandardVmCallbacks::~StandardVmCallbacks() = default;
|
||||
|
||||
void StandardVmCallbacks::MemoryReadUnsafe(VAddr address, void* data, u64 size) {
|
||||
// Return zero on invalid address
|
||||
if (!IsAddressInRange(address) || !system.ApplicationMemory().IsValidVirtualAddress(address)) {
|
||||
std::memset(data, 0, size);
|
||||
return;
|
||||
}
|
||||
|
||||
system.ApplicationMemory().ReadBlock(address, data, size);
|
||||
}
|
||||
|
||||
void StandardVmCallbacks::MemoryWriteUnsafe(VAddr address, const void* data, u64 size) {
|
||||
// Skip invalid memory write address
|
||||
if (!IsAddressInRange(address) || !system.ApplicationMemory().IsValidVirtualAddress(address)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (system.ApplicationMemory().WriteBlock(address, data, size)) {
|
||||
Core::InvalidateInstructionCacheRange(system.ApplicationProcess(), address, size);
|
||||
}
|
||||
}
|
||||
|
||||
u64 StandardVmCallbacks::HidKeysDown() {
|
||||
const auto hid = system.ServiceManager().GetService<Service::HID::IHidServer>("hid");
|
||||
if (hid == nullptr) {
|
||||
LOG_WARNING(CheatEngine, "Attempted to read input state, but hid is not initialized!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto applet_resource = hid->GetResourceManager();
|
||||
if (applet_resource == nullptr || applet_resource->GetNpad() == nullptr) {
|
||||
LOG_WARNING(CheatEngine,
|
||||
"Attempted to read input state, but applet resource is not initialized!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto press_state = applet_resource->GetNpad()->GetAndResetPressState();
|
||||
return static_cast<u64>(press_state & HID::NpadButton::All);
|
||||
}
|
||||
|
||||
void StandardVmCallbacks::PauseProcess() {
|
||||
if (system.ApplicationProcess()->IsSuspended()) {
|
||||
return;
|
||||
}
|
||||
system.ApplicationProcess()->SetActivity(Kernel::Svc::ProcessActivity::Paused);
|
||||
}
|
||||
|
||||
void StandardVmCallbacks::ResumeProcess() {
|
||||
if (!system.ApplicationProcess()->IsSuspended()) {
|
||||
return;
|
||||
}
|
||||
system.ApplicationProcess()->SetActivity(Kernel::Svc::ProcessActivity::Runnable);
|
||||
}
|
||||
|
||||
void StandardVmCallbacks::DebugLog(u8 id, u64 value) {
|
||||
LOG_INFO(CheatEngine, "Cheat triggered DebugLog: ID '{:01X}' Value '{:016X}'", id, value);
|
||||
}
|
||||
|
||||
void StandardVmCallbacks::CommandLog(std::string_view data) {
|
||||
LOG_DEBUG(CheatEngine, "[DmntCheatVm]: {}",
|
||||
data.back() == '\n' ? data.substr(0, data.size() - 1) : data);
|
||||
}
|
||||
|
||||
bool StandardVmCallbacks::IsAddressInRange(VAddr in) const {
|
||||
if ((in < metadata.main_nso_extents.base ||
|
||||
in >= metadata.main_nso_extents.base + metadata.main_nso_extents.size) &&
|
||||
(in < metadata.heap_extents.base ||
|
||||
in >= metadata.heap_extents.base + metadata.heap_extents.size) &&
|
||||
(in < metadata.alias_extents.base ||
|
||||
in >= metadata.alias_extents.base + metadata.alias_extents.size) &&
|
||||
(in < metadata.aslr_extents.base ||
|
||||
in >= metadata.aslr_extents.base + metadata.aslr_extents.size)) {
|
||||
LOG_DEBUG(CheatEngine,
|
||||
"Cheat attempting to access memory at invalid address={:016X}, if this "
|
||||
"persists, "
|
||||
"the cheat may be incorrect. However, this may be normal early in execution if "
|
||||
"the game has not properly set up yet.",
|
||||
in);
|
||||
return false; ///< Invalid addresses will hard crash
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
CheatParser::~CheatParser() = default;
|
||||
|
||||
TextCheatParser::~TextCheatParser() = default;
|
||||
|
||||
std::vector<CheatEntry> TextCheatParser::Parse(std::string_view data) const {
|
||||
std::vector<CheatEntry> out(1);
|
||||
std::optional<u64> current_entry;
|
||||
|
||||
for (std::size_t i = 0; i < data.size(); ++i) {
|
||||
if (::isspace(data[i])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (data[i] == '{') {
|
||||
current_entry = 0;
|
||||
|
||||
if (out[*current_entry].definition.num_opcodes > 0) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::size_t name_size{};
|
||||
const auto name = ExtractName(name_size, data, i + 1, '}');
|
||||
if (name.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::memcpy(out[*current_entry].definition.readable_name.data(), name.data(),
|
||||
std::min<std::size_t>(out[*current_entry].definition.readable_name.size(),
|
||||
name.size()));
|
||||
out[*current_entry]
|
||||
.definition.readable_name[out[*current_entry].definition.readable_name.size() - 1] =
|
||||
'\0';
|
||||
|
||||
i += name_size + 1;
|
||||
} else if (data[i] == '[') {
|
||||
current_entry = out.size();
|
||||
out.emplace_back();
|
||||
|
||||
std::size_t name_size{};
|
||||
const auto name = ExtractName(name_size, data, i + 1, ']');
|
||||
if (name.empty()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
std::memcpy(out[*current_entry].definition.readable_name.data(), name.data(),
|
||||
std::min<std::size_t>(out[*current_entry].definition.readable_name.size(),
|
||||
name.size()));
|
||||
out[*current_entry]
|
||||
.definition.readable_name[out[*current_entry].definition.readable_name.size() - 1] =
|
||||
'\0';
|
||||
|
||||
i += name_size + 1;
|
||||
} else if (::isxdigit(data[i])) {
|
||||
if (!current_entry || out[*current_entry].definition.num_opcodes >=
|
||||
out[*current_entry].definition.opcodes.size()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto hex = std::string(data.substr(i, 8));
|
||||
if (!std::all_of(hex.begin(), hex.end(), ::isxdigit)) {
|
||||
return {};
|
||||
}
|
||||
|
||||
const auto value = static_cast<u32>(std::strtoul(hex.c_str(), nullptr, 0x10));
|
||||
out[*current_entry].definition.opcodes[out[*current_entry].definition.num_opcodes++] =
|
||||
value;
|
||||
|
||||
i += 8;
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
out[0].enabled = out[0].definition.num_opcodes > 0;
|
||||
out[0].cheat_id = 0;
|
||||
|
||||
for (u32 i = 1; i < out.size(); ++i) {
|
||||
out[i].enabled = out[i].definition.num_opcodes > 0;
|
||||
out[i].cheat_id = i;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
CheatEngine::CheatEngine(System& system_, std::vector<CheatEntry> cheats_,
|
||||
const std::array<u8, 0x20>& build_id_)
|
||||
: vm{std::make_unique<StandardVmCallbacks>(system_, metadata)},
|
||||
cheats(std::move(cheats_)), core_timing{system_.CoreTiming()}, system{system_} {
|
||||
metadata.main_nso_build_id = build_id_;
|
||||
}
|
||||
|
||||
CheatEngine::~CheatEngine() {
|
||||
core_timing.UnscheduleEvent(event);
|
||||
}
|
||||
|
||||
void CheatEngine::Initialize() {
|
||||
event = Core::Timing::CreateEvent(
|
||||
"CheatEngine::FrameCallback::" + Common::HexToString(metadata.main_nso_build_id),
|
||||
[this](s64 time,
|
||||
std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> {
|
||||
FrameCallback(ns_late);
|
||||
return std::nullopt;
|
||||
});
|
||||
core_timing.ScheduleLoopingEvent(CHEAT_ENGINE_NS, CHEAT_ENGINE_NS, event);
|
||||
|
||||
metadata.process_id = system.ApplicationProcess()->GetProcessId();
|
||||
metadata.title_id = system.GetApplicationProcessProgramID();
|
||||
|
||||
const auto& page_table = system.ApplicationProcess()->GetPageTable();
|
||||
metadata.heap_extents = {
|
||||
.base = GetInteger(page_table.GetHeapRegionStart()),
|
||||
.size = page_table.GetHeapRegionSize(),
|
||||
};
|
||||
metadata.aslr_extents = {
|
||||
.base = GetInteger(page_table.GetAliasCodeRegionStart()),
|
||||
.size = page_table.GetAliasCodeRegionSize(),
|
||||
};
|
||||
metadata.alias_extents = {
|
||||
.base = GetInteger(page_table.GetAliasRegionStart()),
|
||||
.size = page_table.GetAliasRegionSize(),
|
||||
};
|
||||
|
||||
is_pending_reload.exchange(true);
|
||||
}
|
||||
|
||||
void CheatEngine::SetMainMemoryParameters(VAddr main_region_begin, u64 main_region_size) {
|
||||
metadata.main_nso_extents = {
|
||||
.base = main_region_begin,
|
||||
.size = main_region_size,
|
||||
};
|
||||
}
|
||||
|
||||
void CheatEngine::Reload(std::vector<CheatEntry> reload_cheats) {
|
||||
cheats = std::move(reload_cheats);
|
||||
is_pending_reload.exchange(true);
|
||||
}
|
||||
|
||||
void CheatEngine::FrameCallback(std::chrono::nanoseconds ns_late) {
|
||||
if (is_pending_reload.exchange(false)) {
|
||||
vm.LoadProgram(cheats);
|
||||
}
|
||||
|
||||
if (vm.GetProgramSize() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
vm.Execute(metadata);
|
||||
}
|
||||
|
||||
} // namespace Core::Memory
|
||||
88
src/core/memory/cheat_engine.h
Normal file
88
src/core/memory/cheat_engine.h
Normal file
@@ -0,0 +1,88 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include "common/common_types.h"
|
||||
#include "core/memory/dmnt_cheat_types.h"
|
||||
#include "core/memory/dmnt_cheat_vm.h"
|
||||
|
||||
namespace Core {
|
||||
class System;
|
||||
}
|
||||
|
||||
namespace Core::Timing {
|
||||
class CoreTiming;
|
||||
struct EventType;
|
||||
} // namespace Core::Timing
|
||||
|
||||
namespace Core::Memory {
|
||||
|
||||
class StandardVmCallbacks : public DmntCheatVm::Callbacks {
|
||||
public:
|
||||
StandardVmCallbacks(System& system_, const CheatProcessMetadata& metadata_);
|
||||
~StandardVmCallbacks() override;
|
||||
|
||||
void MemoryReadUnsafe(VAddr address, void* data, u64 size) override;
|
||||
void MemoryWriteUnsafe(VAddr address, const void* data, u64 size) override;
|
||||
u64 HidKeysDown() override;
|
||||
void PauseProcess() override;
|
||||
void ResumeProcess() override;
|
||||
void DebugLog(u8 id, u64 value) override;
|
||||
void CommandLog(std::string_view data) override;
|
||||
|
||||
private:
|
||||
bool IsAddressInRange(VAddr address) const;
|
||||
|
||||
const CheatProcessMetadata& metadata;
|
||||
Core::System& system;
|
||||
};
|
||||
|
||||
// Intermediary class that parses a text file or other disk format for storing cheats into a
|
||||
// CheatList object, that can be used for execution.
|
||||
class CheatParser {
|
||||
public:
|
||||
virtual ~CheatParser();
|
||||
|
||||
[[nodiscard]] virtual std::vector<CheatEntry> Parse(std::string_view data) const = 0;
|
||||
};
|
||||
|
||||
// CheatParser implementation that parses text files
|
||||
class TextCheatParser final : public CheatParser {
|
||||
public:
|
||||
~TextCheatParser() override;
|
||||
|
||||
[[nodiscard]] std::vector<CheatEntry> Parse(std::string_view data) const override;
|
||||
};
|
||||
|
||||
// Class that encapsulates a CheatList and manages its interaction with memory and CoreTiming
|
||||
class CheatEngine final {
|
||||
public:
|
||||
CheatEngine(System& system_, std::vector<CheatEntry> cheats_,
|
||||
const std::array<u8, 0x20>& build_id_);
|
||||
~CheatEngine();
|
||||
|
||||
void Initialize();
|
||||
void SetMainMemoryParameters(VAddr main_region_begin, u64 main_region_size);
|
||||
|
||||
void Reload(std::vector<CheatEntry> reload_cheats);
|
||||
|
||||
private:
|
||||
void FrameCallback(std::chrono::nanoseconds ns_late);
|
||||
|
||||
DmntCheatVm vm;
|
||||
CheatProcessMetadata metadata;
|
||||
|
||||
std::vector<CheatEntry> cheats;
|
||||
std::atomic_bool is_pending_reload{false};
|
||||
|
||||
std::shared_ptr<Core::Timing::EventType> event;
|
||||
Core::Timing::CoreTiming& core_timing;
|
||||
Core::System& system;
|
||||
};
|
||||
|
||||
} // namespace Core::Memory
|
||||
37
src/core/memory/dmnt_cheat_types.h
Normal file
37
src/core/memory/dmnt_cheat_types.h
Normal file
@@ -0,0 +1,37 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Core::Memory {
|
||||
|
||||
struct MemoryRegionExtents {
|
||||
u64 base{};
|
||||
u64 size{};
|
||||
};
|
||||
|
||||
struct CheatProcessMetadata {
|
||||
u64 process_id{};
|
||||
u64 title_id{};
|
||||
MemoryRegionExtents main_nso_extents{};
|
||||
MemoryRegionExtents heap_extents{};
|
||||
MemoryRegionExtents alias_extents{};
|
||||
MemoryRegionExtents aslr_extents{};
|
||||
std::array<u8, 0x20> main_nso_build_id{};
|
||||
};
|
||||
|
||||
struct CheatDefinition {
|
||||
std::array<char, 0x40> readable_name{};
|
||||
u32 num_opcodes{};
|
||||
std::array<u32, 0x100> opcodes{};
|
||||
};
|
||||
|
||||
struct CheatEntry {
|
||||
bool enabled{};
|
||||
u32 cheat_id{};
|
||||
CheatDefinition definition{};
|
||||
};
|
||||
|
||||
} // namespace Core::Memory
|
||||
1268
src/core/memory/dmnt_cheat_vm.cpp
Normal file
1268
src/core/memory/dmnt_cheat_vm.cpp
Normal file
File diff suppressed because it is too large
Load Diff
330
src/core/memory/dmnt_cheat_vm.h
Normal file
330
src/core/memory/dmnt_cheat_vm.h
Normal file
@@ -0,0 +1,330 @@
|
||||
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
|
||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||
|
||||
// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <variant>
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
|
||||
#include <fmt/printf.h>
|
||||
#include "common/common_types.h"
|
||||
#include "core/memory/dmnt_cheat_types.h"
|
||||
|
||||
namespace Core::Memory {
|
||||
|
||||
enum class CheatVmOpcodeType : u32 {
|
||||
StoreStatic = 0,
|
||||
BeginConditionalBlock = 1,
|
||||
EndConditionalBlock = 2,
|
||||
ControlLoop = 3,
|
||||
LoadRegisterStatic = 4,
|
||||
LoadRegisterMemory = 5,
|
||||
StoreStaticToAddress = 6,
|
||||
PerformArithmeticStatic = 7,
|
||||
BeginKeypressConditionalBlock = 8,
|
||||
|
||||
// These are not implemented by Gateway's VM.
|
||||
PerformArithmeticRegister = 9,
|
||||
StoreRegisterToAddress = 10,
|
||||
Reserved11 = 11,
|
||||
|
||||
// This is a meta entry, and not a real opcode.
|
||||
// This is to facilitate multi-nybble instruction decoding.
|
||||
ExtendedWidth = 12,
|
||||
|
||||
// Extended width opcodes.
|
||||
BeginRegisterConditionalBlock = 0xC0,
|
||||
SaveRestoreRegister = 0xC1,
|
||||
SaveRestoreRegisterMask = 0xC2,
|
||||
ReadWriteStaticRegister = 0xC3,
|
||||
|
||||
// This is a meta entry, and not a real opcode.
|
||||
// This is to facilitate multi-nybble instruction decoding.
|
||||
DoubleExtendedWidth = 0xF0,
|
||||
|
||||
// Double-extended width opcodes.
|
||||
PauseProcess = 0xFF0,
|
||||
ResumeProcess = 0xFF1,
|
||||
DebugLog = 0xFFF,
|
||||
};
|
||||
|
||||
enum class MemoryAccessType : u32 {
|
||||
MainNso = 0,
|
||||
Heap = 1,
|
||||
Alias = 2,
|
||||
Aslr = 3,
|
||||
};
|
||||
|
||||
enum class ConditionalComparisonType : u32 {
|
||||
GT = 1,
|
||||
GE = 2,
|
||||
LT = 3,
|
||||
LE = 4,
|
||||
EQ = 5,
|
||||
NE = 6,
|
||||
};
|
||||
|
||||
enum class RegisterArithmeticType : u32 {
|
||||
Addition = 0,
|
||||
Subtraction = 1,
|
||||
Multiplication = 2,
|
||||
LeftShift = 3,
|
||||
RightShift = 4,
|
||||
|
||||
// These are not supported by Gateway's VM.
|
||||
LogicalAnd = 5,
|
||||
LogicalOr = 6,
|
||||
LogicalNot = 7,
|
||||
LogicalXor = 8,
|
||||
|
||||
None = 9,
|
||||
};
|
||||
|
||||
enum class StoreRegisterOffsetType : u32 {
|
||||
None = 0,
|
||||
Reg = 1,
|
||||
Imm = 2,
|
||||
MemReg = 3,
|
||||
MemImm = 4,
|
||||
MemImmReg = 5,
|
||||
};
|
||||
|
||||
enum class CompareRegisterValueType : u32 {
|
||||
MemoryRelAddr = 0,
|
||||
MemoryOfsReg = 1,
|
||||
RegisterRelAddr = 2,
|
||||
RegisterOfsReg = 3,
|
||||
StaticValue = 4,
|
||||
OtherRegister = 5,
|
||||
};
|
||||
|
||||
enum class SaveRestoreRegisterOpType : u32 {
|
||||
Restore = 0,
|
||||
Save = 1,
|
||||
ClearSaved = 2,
|
||||
ClearRegs = 3,
|
||||
};
|
||||
|
||||
enum class DebugLogValueType : u32 {
|
||||
MemoryRelAddr = 0,
|
||||
MemoryOfsReg = 1,
|
||||
RegisterRelAddr = 2,
|
||||
RegisterOfsReg = 3,
|
||||
RegisterValue = 4,
|
||||
};
|
||||
|
||||
union VmInt {
|
||||
u8 bit8;
|
||||
u16 bit16;
|
||||
u32 bit32;
|
||||
u64 bit64;
|
||||
};
|
||||
|
||||
struct StoreStaticOpcode {
|
||||
u32 bit_width{};
|
||||
MemoryAccessType mem_type{};
|
||||
u32 offset_register{};
|
||||
u64 rel_address{};
|
||||
VmInt value{};
|
||||
};
|
||||
|
||||
struct BeginConditionalOpcode {
|
||||
u32 bit_width{};
|
||||
MemoryAccessType mem_type{};
|
||||
ConditionalComparisonType cond_type{};
|
||||
u64 rel_address{};
|
||||
VmInt value{};
|
||||
};
|
||||
|
||||
struct EndConditionalOpcode {
|
||||
bool is_else;
|
||||
};
|
||||
|
||||
struct ControlLoopOpcode {
|
||||
bool start_loop{};
|
||||
u32 reg_index{};
|
||||
u32 num_iters{};
|
||||
};
|
||||
|
||||
struct LoadRegisterStaticOpcode {
|
||||
u32 reg_index{};
|
||||
u64 value{};
|
||||
};
|
||||
|
||||
struct LoadRegisterMemoryOpcode {
|
||||
u32 bit_width{};
|
||||
MemoryAccessType mem_type{};
|
||||
u32 reg_index{};
|
||||
bool load_from_reg{};
|
||||
u64 rel_address{};
|
||||
};
|
||||
|
||||
struct StoreStaticToAddressOpcode {
|
||||
u32 bit_width{};
|
||||
u32 reg_index{};
|
||||
bool increment_reg{};
|
||||
bool add_offset_reg{};
|
||||
u32 offset_reg_index{};
|
||||
u64 value{};
|
||||
};
|
||||
|
||||
struct PerformArithmeticStaticOpcode {
|
||||
u32 bit_width{};
|
||||
u32 reg_index{};
|
||||
RegisterArithmeticType math_type{};
|
||||
u32 value{};
|
||||
};
|
||||
|
||||
struct BeginKeypressConditionalOpcode {
|
||||
u32 key_mask{};
|
||||
};
|
||||
|
||||
struct PerformArithmeticRegisterOpcode {
|
||||
u32 bit_width{};
|
||||
RegisterArithmeticType math_type{};
|
||||
u32 dst_reg_index{};
|
||||
u32 src_reg_1_index{};
|
||||
u32 src_reg_2_index{};
|
||||
bool has_immediate{};
|
||||
VmInt value{};
|
||||
};
|
||||
|
||||
struct StoreRegisterToAddressOpcode {
|
||||
u32 bit_width{};
|
||||
u32 str_reg_index{};
|
||||
u32 addr_reg_index{};
|
||||
bool increment_reg{};
|
||||
StoreRegisterOffsetType ofs_type{};
|
||||
MemoryAccessType mem_type{};
|
||||
u32 ofs_reg_index{};
|
||||
u64 rel_address{};
|
||||
};
|
||||
|
||||
struct BeginRegisterConditionalOpcode {
|
||||
u32 bit_width{};
|
||||
ConditionalComparisonType cond_type{};
|
||||
u32 val_reg_index{};
|
||||
CompareRegisterValueType comp_type{};
|
||||
MemoryAccessType mem_type{};
|
||||
u32 addr_reg_index{};
|
||||
u32 other_reg_index{};
|
||||
u32 ofs_reg_index{};
|
||||
u64 rel_address{};
|
||||
VmInt value{};
|
||||
};
|
||||
|
||||
struct SaveRestoreRegisterOpcode {
|
||||
u32 dst_index{};
|
||||
u32 src_index{};
|
||||
SaveRestoreRegisterOpType op_type{};
|
||||
};
|
||||
|
||||
struct SaveRestoreRegisterMaskOpcode {
|
||||
SaveRestoreRegisterOpType op_type{};
|
||||
std::array<bool, 0x10> should_operate{};
|
||||
};
|
||||
|
||||
struct ReadWriteStaticRegisterOpcode {
|
||||
u32 static_idx{};
|
||||
u32 idx{};
|
||||
};
|
||||
|
||||
struct PauseProcessOpcode {};
|
||||
|
||||
struct ResumeProcessOpcode {};
|
||||
|
||||
struct DebugLogOpcode {
|
||||
u32 bit_width{};
|
||||
u32 log_id{};
|
||||
DebugLogValueType val_type{};
|
||||
MemoryAccessType mem_type{};
|
||||
u32 addr_reg_index{};
|
||||
u32 val_reg_index{};
|
||||
u32 ofs_reg_index{};
|
||||
u64 rel_address{};
|
||||
};
|
||||
|
||||
struct UnrecognizedInstruction {
|
||||
CheatVmOpcodeType opcode{};
|
||||
};
|
||||
|
||||
struct CheatVmOpcode {
|
||||
bool begin_conditional_block{};
|
||||
std::variant<StoreStaticOpcode, BeginConditionalOpcode, EndConditionalOpcode, ControlLoopOpcode,
|
||||
LoadRegisterStaticOpcode, LoadRegisterMemoryOpcode, StoreStaticToAddressOpcode,
|
||||
PerformArithmeticStaticOpcode, BeginKeypressConditionalOpcode,
|
||||
PerformArithmeticRegisterOpcode, StoreRegisterToAddressOpcode,
|
||||
BeginRegisterConditionalOpcode, SaveRestoreRegisterOpcode,
|
||||
SaveRestoreRegisterMaskOpcode, ReadWriteStaticRegisterOpcode, PauseProcessOpcode,
|
||||
ResumeProcessOpcode, DebugLogOpcode, UnrecognizedInstruction>
|
||||
opcode{};
|
||||
};
|
||||
|
||||
class DmntCheatVm {
|
||||
public:
|
||||
/// Helper Type for DmntCheatVm <=> yuzu Interface
|
||||
class Callbacks {
|
||||
public:
|
||||
virtual ~Callbacks();
|
||||
|
||||
virtual void MemoryReadUnsafe(VAddr address, void* data, u64 size) = 0;
|
||||
virtual void MemoryWriteUnsafe(VAddr address, const void* data, u64 size) = 0;
|
||||
|
||||
virtual u64 HidKeysDown() = 0;
|
||||
|
||||
virtual void PauseProcess() = 0;
|
||||
virtual void ResumeProcess() = 0;
|
||||
|
||||
virtual void DebugLog(u8 id, u64 value) = 0;
|
||||
virtual void CommandLog(std::string_view data) = 0;
|
||||
};
|
||||
|
||||
static constexpr std::size_t MaximumProgramOpcodeCount = 0x400;
|
||||
static constexpr std::size_t NumRegisters = 0x10;
|
||||
static constexpr std::size_t NumReadableStaticRegisters = 0x80;
|
||||
static constexpr std::size_t NumWritableStaticRegisters = 0x80;
|
||||
static constexpr std::size_t NumStaticRegisters =
|
||||
NumReadableStaticRegisters + NumWritableStaticRegisters;
|
||||
|
||||
explicit DmntCheatVm(std::unique_ptr<Callbacks> callbacks_);
|
||||
~DmntCheatVm();
|
||||
|
||||
std::size_t GetProgramSize() const {
|
||||
return this->num_opcodes;
|
||||
}
|
||||
|
||||
bool LoadProgram(const std::vector<CheatEntry>& cheats);
|
||||
void Execute(const CheatProcessMetadata& metadata);
|
||||
|
||||
private:
|
||||
std::unique_ptr<Callbacks> callbacks;
|
||||
|
||||
std::size_t num_opcodes = 0;
|
||||
std::size_t instruction_ptr = 0;
|
||||
std::size_t condition_depth = 0;
|
||||
bool decode_success = false;
|
||||
std::array<u32, MaximumProgramOpcodeCount> program{};
|
||||
std::array<u64, NumRegisters> registers{};
|
||||
std::array<u64, NumRegisters> saved_values{};
|
||||
std::array<u64, NumStaticRegisters> static_registers{};
|
||||
std::array<std::size_t, NumRegisters> loop_tops{};
|
||||
|
||||
bool DecodeNextOpcode(CheatVmOpcode& out);
|
||||
void SkipConditionalBlock(bool is_if);
|
||||
void ResetState();
|
||||
|
||||
// For implementing the DebugLog opcode.
|
||||
void DebugLog(u32 log_id, u64 value);
|
||||
|
||||
void LogOpcode(const CheatVmOpcode& opcode);
|
||||
|
||||
static u64 GetVmInt(VmInt value, u32 bit_width);
|
||||
static u64 GetCheatProcessAddress(const CheatProcessMetadata& metadata,
|
||||
MemoryAccessType mem_type, u64 rel_address);
|
||||
};
|
||||
|
||||
}; // namespace Core::Memory
|
||||
@@ -57,7 +57,7 @@ class SigHandler {
|
||||
public:
|
||||
SigHandler() noexcept {
|
||||
signal_stack_size = std::max<size_t>(SIGSTKSZ, 2 * 1024 * 1024);
|
||||
signal_stack_memory = mmap(nullptr, signal_stack_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
||||
signal_stack_memory = std::malloc(signal_stack_size);
|
||||
|
||||
stack_t signal_stack{};
|
||||
signal_stack.ss_sp = signal_stack_memory;
|
||||
@@ -89,7 +89,7 @@ public:
|
||||
}
|
||||
|
||||
~SigHandler() noexcept {
|
||||
munmap(signal_stack_memory, signal_stack_size);
|
||||
std::free(signal_stack_memory);
|
||||
}
|
||||
|
||||
void AddCodeBlock(u64 offset, CodeBlockInfo cbi) noexcept {
|
||||
|
||||
@@ -82,7 +82,8 @@ FP::FPCR A32EmitContext::FPCR(bool fpcr_controlled) const {
|
||||
|
||||
A32EmitX64::A32EmitX64(BlockOfCode& code, A32::UserConfig conf, A32::Jit* jit_interface)
|
||||
: EmitX64(code), conf(std::move(conf)), jit_interface(jit_interface) {
|
||||
GenFastmemFallbacks();
|
||||
if (conf.fastmem_pointer.has_value())
|
||||
GenFastmemFallbacks();
|
||||
GenTerminalHandlers();
|
||||
code.PreludeComplete();
|
||||
ClearFastDispatchTable();
|
||||
|
||||
@@ -56,7 +56,8 @@ FP::FPCR A64EmitContext::FPCR(bool fpcr_controlled) const {
|
||||
A64EmitX64::A64EmitX64(BlockOfCode& code, A64::UserConfig conf, A64::Jit* jit_interface)
|
||||
: EmitX64(code), conf(conf), jit_interface{jit_interface} {
|
||||
GenMemory128Accessors();
|
||||
GenFastmemFallbacks();
|
||||
if (conf.fastmem_pointer.has_value())
|
||||
GenFastmemFallbacks();
|
||||
GenTerminalHandlers();
|
||||
code.PreludeComplete();
|
||||
ClearFastDispatchTable();
|
||||
|
||||
@@ -79,7 +79,9 @@ namespace {
|
||||
#endif
|
||||
if (enable_validation && AreExtensionsSupported(dld, *properties, std::array{VK_EXT_DEBUG_UTILS_EXTENSION_NAME}))
|
||||
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||
|
||||
// VK_EXT_surface_maintenance1 is required for VK_EXT_swapchain_maintenance1
|
||||
if (window_type != Core::Frontend::WindowSystemType::Headless && AreExtensionsSupported(dld, *properties, std::array{VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME}))
|
||||
extensions.push_back(VK_EXT_SURFACE_MAINTENANCE_1_EXTENSION_NAME);
|
||||
}
|
||||
return extensions;
|
||||
}
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <algorithm>
|
||||
#include <functional>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
|
||||
@@ -75,32 +73,10 @@ ConfigurePerGameAddons::~ConfigurePerGameAddons() = default;
|
||||
void ConfigurePerGameAddons::ApplyConfiguration() {
|
||||
std::vector<std::string> disabled_addons;
|
||||
|
||||
// Helper function to recursively collect disabled items
|
||||
std::function<void(QStandardItem*)> collect_disabled = [&](QStandardItem* item) {
|
||||
if (item == nullptr) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check if this item is disabled
|
||||
if (item->isCheckable() && item->checkState() == Qt::Unchecked) {
|
||||
// Use the stored key from UserRole, falling back to text
|
||||
const auto key = item->data(Qt::UserRole).toString();
|
||||
if (!key.isEmpty()) {
|
||||
disabled_addons.push_back(key.toStdString());
|
||||
} else {
|
||||
disabled_addons.push_back(item->text().toStdString());
|
||||
}
|
||||
}
|
||||
|
||||
// Process children (for cheats under mods)
|
||||
for (int row = 0; row < item->rowCount(); ++row) {
|
||||
collect_disabled(item->child(row, 0));
|
||||
}
|
||||
};
|
||||
|
||||
// Process all root items
|
||||
for (int row = 0; row < item_model->rowCount(); ++row) {
|
||||
collect_disabled(item_model->item(row, 0));
|
||||
for (const auto& item : list_items) {
|
||||
const auto disabled = item.front()->checkState() == Qt::Unchecked;
|
||||
if (disabled)
|
||||
disabled_addons.push_back(item.front()->text().toStdString());
|
||||
}
|
||||
|
||||
auto current = Settings::values.disabled_addons[title_id];
|
||||
@@ -147,61 +123,24 @@ void ConfigurePerGameAddons::LoadConfiguration() {
|
||||
FileSys::VirtualFile update_raw;
|
||||
loader->ReadUpdateRaw(update_raw);
|
||||
|
||||
// Get the build ID from the main executable for cheat enumeration
|
||||
const auto build_id = pm.GetBuildID(update_raw);
|
||||
|
||||
const auto& disabled = Settings::values.disabled_addons[title_id];
|
||||
|
||||
// Map to store parent items for mods (for adding cheat children)
|
||||
std::map<std::string, QStandardItem*> mod_items;
|
||||
|
||||
for (const auto& patch : pm.GetPatches(update_raw, build_id)) {
|
||||
for (const auto& patch : pm.GetPatches(update_raw)) {
|
||||
const auto name = QString::fromStdString(patch.name);
|
||||
|
||||
// For cheats, we need to use the full key (parent::name) for storage
|
||||
std::string storage_key;
|
||||
if (patch.type == FileSys::PatchType::Cheat && !patch.parent_name.empty()) {
|
||||
storage_key = patch.parent_name + "::" + patch.name;
|
||||
} else {
|
||||
storage_key = patch.name;
|
||||
}
|
||||
|
||||
auto* const first_item = new QStandardItem;
|
||||
first_item->setText(name);
|
||||
first_item->setCheckable(true);
|
||||
|
||||
// Store the storage key as user data for later retrieval
|
||||
first_item->setData(QString::fromStdString(storage_key), Qt::UserRole);
|
||||
|
||||
const auto patch_disabled =
|
||||
std::find(disabled.begin(), disabled.end(), storage_key) != disabled.end();
|
||||
std::find(disabled.begin(), disabled.end(), name.toStdString()) != disabled.end();
|
||||
|
||||
first_item->setCheckState(patch_disabled ? Qt::Unchecked : Qt::Checked);
|
||||
|
||||
auto* const version_item = new QStandardItem{QString::fromStdString(patch.version)};
|
||||
|
||||
if (patch.type == FileSys::PatchType::Cheat && !patch.parent_name.empty()) {
|
||||
// This is a cheat - add as child of its parent mod
|
||||
auto parent_it = mod_items.find(patch.parent_name);
|
||||
if (parent_it != mod_items.end()) {
|
||||
parent_it->second->appendRow(QList<QStandardItem*>{first_item, version_item});
|
||||
} else {
|
||||
// Parent not found (shouldn't happen), add to root
|
||||
list_items.push_back(QList<QStandardItem*>{first_item, version_item});
|
||||
item_model->appendRow(list_items.back());
|
||||
}
|
||||
} else {
|
||||
// This is a top-level item (Update, Mod, DLC)
|
||||
list_items.push_back(QList<QStandardItem*>{first_item, version_item});
|
||||
item_model->appendRow(list_items.back());
|
||||
|
||||
// Store mod items for later cheat attachment
|
||||
if (patch.type == FileSys::PatchType::Mod) {
|
||||
mod_items[patch.name] = first_item;
|
||||
}
|
||||
}
|
||||
list_items.push_back(QList<QStandardItem*>{
|
||||
first_item, new QStandardItem{QString::fromStdString(patch.version)}});
|
||||
item_model->appendRow(list_items.back());
|
||||
}
|
||||
|
||||
tree_view->expandAll();
|
||||
tree_view->resizeColumnToContents(1);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user