2 Commits

Author SHA1 Message Date
55e2306156 cheat interface 2024-02-24 21:10:22 -06:00
68b4f65390 cheat mgr 2024-02-24 15:35:35 -06:00
13 changed files with 147 additions and 85 deletions

View File

@ -588,8 +588,6 @@ add_library(core STATIC
hle/service/caps/caps_types.h hle/service/caps/caps_types.h
hle/service/caps/caps_u.cpp hle/service/caps/caps_u.cpp
hle/service/caps/caps_u.h 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.cpp
hle/service/dmnt/cheat_interface.h hle/service/dmnt/cheat_interface.h
hle/service/dmnt/cheat_parser.cpp hle/service/dmnt/cheat_parser.cpp
@ -602,6 +600,8 @@ add_library(core STATIC
hle/service/dmnt/dmnt.h hle/service/dmnt/dmnt.h
hle/service/dmnt/dmnt_results.h hle/service/dmnt/dmnt_results.h
hle/service/dmnt/dmnt_types.h hle/service/dmnt/dmnt_types.h
hle/service/cmif_serialization.h
hle/service/cmif_types.h
hle/service/erpt/erpt.cpp hle/service/erpt/erpt.cpp
hle/service/erpt/erpt.h hle/service/erpt/erpt.h
hle/service/es/es.cpp hle/service/es/es.cpp

View File

@ -362,7 +362,7 @@ struct System::Impl {
kernel.AppendNewProcess(main_process); kernel.AppendNewProcess(main_process);
kernel.MakeApplicationProcess(main_process); kernel.MakeApplicationProcess(main_process);
if (!cheat_manager) { if (cheat_manager == nullptr) {
cheat_manager = std::make_unique<Service::DMNT::CheatProcessManager>(system); cheat_manager = std::make_unique<Service::DMNT::CheatProcessManager>(system);
} }
@ -1049,7 +1049,6 @@ Service::DMNT::CheatProcessManager& System::GetCheatManager() {
const Service::DMNT::CheatProcessManager& System::GetCheatManager() const { const Service::DMNT::CheatProcessManager& System::GetCheatManager() const {
return *impl->cheat_manager; return *impl->cheat_manager;
} }
Network::RoomNetwork& System::GetRoomNetwork() { Network::RoomNetwork& System::GetRoomNetwork() {
return impl->room_network; return impl->room_network;
} }

View File

@ -66,7 +66,7 @@ class Controller;
namespace DMNT { namespace DMNT {
struct CheatEntry; struct CheatEntry;
class CheatProcessManager; class CheatProcessManager;
} // namespace DMNT }
namespace FileSystem { namespace FileSystem {
class FileSystemController; class FileSystemController;

View File

@ -24,13 +24,13 @@
#include "core/file_sys/vfs/vfs_cached.h" #include "core/file_sys/vfs/vfs_cached.h"
#include "core/file_sys/vfs/vfs_layered.h" #include "core/file_sys/vfs/vfs_layered.h"
#include "core/file_sys/vfs/vfs_vector.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/filesystem/filesystem.h"
#include "core/hle/service/ns/language.h" #include "core/hle/service/ns/language.h"
#include "core/hle/service/set/settings_server.h" #include "core/hle/service/set/settings_server.h"
#include "core/loader/loader.h" #include "core/loader/loader.h"
#include "core/loader/nso.h" #include "core/loader/nso.h"
#include "core/hle/service/dmnt/cheat_parser.h"
#include "core/hle/service/dmnt/dmnt_types.h"
namespace FileSys { namespace FileSys {
namespace { namespace {
@ -512,6 +512,7 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const {
const auto mod_dir = fs_controller.GetModificationLoadRoot(title_id); const auto mod_dir = fs_controller.GetModificationLoadRoot(title_id);
if (mod_dir != nullptr) { if (mod_dir != nullptr) {
for (const auto& mod : mod_dir->GetSubdirectories()) { for (const auto& mod : mod_dir->GetSubdirectories()) {
std::vector<CheatPatch> cheats;
std::string types; std::string types;
const auto exefs_dir = FindSubdirectoryCaseless(mod, "exefs"); const auto exefs_dir = FindSubdirectoryCaseless(mod, "exefs");
@ -540,20 +541,32 @@ std::vector<Patch> PatchManager::GetPatches(VirtualFile update_raw) const {
} }
if (IsDirValidAndNonEmpty(FindSubdirectoryCaseless(mod, "romfs"))) if (IsDirValidAndNonEmpty(FindSubdirectoryCaseless(mod, "romfs")))
AppendCommaIfNotEmpty(types, "LayeredFS"); AppendCommaIfNotEmpty(types, "LayeredFS");
if (IsDirValidAndNonEmpty(FindSubdirectoryCaseless(mod, "cheats"))) if (IsDirValidAndNonEmpty(FindSubdirectoryCaseless(mod, "cheats"))) {
AppendCommaIfNotEmpty(types, "Cheats"); AppendCommaIfNotEmpty(types, "Cheats");
cheats.push_back({
.enabled = true,
.name = "1. Pointed Unit Refill HP/Gas/Ammo (ZL+B)",
});
cheats.push_back({
.enabled = true,
.name = "2. Pointed Unit Can Move Again (ZL+B)",
});
}
if (types.empty()) if (types.empty())
continue; continue;
const auto mod_disabled = const auto mod_disabled =
std::find(disabled.begin(), disabled.end(), mod->GetName()) != disabled.end(); std::find(disabled.begin(), disabled.end(), mod->GetName()) != disabled.end();
out.push_back({.enabled = !mod_disabled, out.push_back({
.name = mod->GetName(), .enabled = !mod_disabled,
.version = types, .name = mod->GetName(),
.type = PatchType::Mod, .version = types,
.program_id = title_id, .type = PatchType::Mod,
.title_id = title_id}); .program_id = title_id,
.title_id = title_id,
.cheats = cheats,
});
} }
} }

View File

@ -32,6 +32,11 @@ class NACP;
enum class PatchType { Update, DLC, Mod }; enum class PatchType { Update, DLC, Mod };
struct CheatPatch {
bool enabled;
std::string name;
};
struct Patch { struct Patch {
bool enabled; bool enabled;
std::string name; std::string name;
@ -39,6 +44,7 @@ struct Patch {
PatchType type; PatchType type;
u64 program_id; u64 program_id;
u64 title_id; u64 title_id;
std::vector<CheatPatch> cheats;
}; };
// A centralized class to manage patches to games. // A centralized class to manage patches to games.

View File

@ -60,9 +60,9 @@ Result ICheatInterface::GetCheatProcessEvent(OutCopyHandle<Kernel::KReadableEven
R_SUCCEED(); R_SUCCEED();
} }
Result ICheatInterface::GetCheatProcessMetadata(Out<CheatProcessMetadata> out_metadata) { Result ICheatInterface::GetCheatProcessMetadata(CheatProcessMetadata out_metadata) {
LOG_INFO(CheatEngine, "called"); LOG_INFO(CheatEngine, "called");
R_RETURN(cheat_process_manager.GetCheatProcessMetadata(*out_metadata)); R_RETURN(cheat_process_manager.GetCheatProcessMetadata(out_metadata));
} }
Result ICheatInterface::ForceOpenCheatProcess() { Result ICheatInterface::ForceOpenCheatProcess() {
@ -82,33 +82,33 @@ Result ICheatInterface::ResumeCheatProcess() {
} }
Result ICheatInterface::ForceCloseCheatProcess() { Result ICheatInterface::ForceCloseCheatProcess() {
LOG_WARNING(CheatEngine, "(STUBBED) called"); LOG_INFO(CheatEngine, "called");
R_RETURN(cheat_process_manager.ForceCloseCheatProcess()); R_RETURN(cheat_process_manager.ForceCloseCheatProcess());
} }
Result ICheatInterface::GetCheatProcessMappingCount(Out<u64> out_count) { Result ICheatInterface::GetCheatProcessMappingCount(Out<u64> out_count) {
LOG_WARNING(CheatEngine, "(STUBBED) called"); LOG_INFO(CheatEngine, "called");
R_RETURN(cheat_process_manager.GetCheatProcessMappingCount(*out_count)); R_RETURN(cheat_process_manager.GetCheatProcessMappingCount(*out_count));
} }
Result ICheatInterface::GetCheatProcessMappings( Result ICheatInterface::GetCheatProcessMappings(
Out<u64> out_count, u64 offset, Out<u64> out_count, u64 offset,
OutArray<Kernel::Svc::MemoryInfo, BufferAttr_HipcMapAlias> out_mappings) { OutArray<Kernel::Svc::MemoryInfo, BufferAttr_HipcMapAlias> out_mappings) {
LOG_INFO(CheatEngine, "called, offset={}", offset); LOG_INFO(CheatEngine, "called");
R_UNLESS(!out_mappings.empty(), ResultCheatNullBuffer); R_UNLESS(!out_mappings.empty(), ResultCheatNullBuffer);
R_RETURN(cheat_process_manager.GetCheatProcessMappings(*out_count, offset, out_mappings)); R_RETURN(cheat_process_manager.GetCheatProcessMappings(*out_count, offset, out_mappings));
} }
Result ICheatInterface::ReadCheatProcessMemory(u64 address, u64 size, Result ICheatInterface::ReadCheatProcessMemory(u64 address, u64 size,
OutBuffer<BufferAttr_HipcMapAlias> out_buffer) { OutBuffer<BufferAttr_HipcMapAlias> out_buffer) {
LOG_DEBUG(CheatEngine, "called, address={}, size={}", address, size); LOG_INFO(CheatEngine, "called");
R_UNLESS(!out_buffer.empty(), ResultCheatNullBuffer); R_UNLESS(!out_buffer.empty(), ResultCheatNullBuffer);
R_RETURN(cheat_process_manager.ReadCheatProcessMemory(address, size, out_buffer)); R_RETURN(cheat_process_manager.ReadCheatProcessMemory(address, size, out_buffer));
} }
Result ICheatInterface::WriteCheatProcessMemory(u64 address, u64 size, Result ICheatInterface::WriteCheatProcessMemory(u64 address, u64 size,
InBuffer<BufferAttr_HipcMapAlias> buffer) { InBuffer<BufferAttr_HipcMapAlias> buffer) {
LOG_DEBUG(CheatEngine, "called, address={}, size={}", address, size); LOG_INFO(CheatEngine, "called, address={}, size={}", address, size);
R_UNLESS(!buffer.empty(), ResultCheatNullBuffer); R_UNLESS(!buffer.empty(), ResultCheatNullBuffer);
R_RETURN(cheat_process_manager.WriteCheatProcessMemory(address, size, buffer)); R_RETURN(cheat_process_manager.WriteCheatProcessMemory(address, size, buffer));
} }
@ -155,12 +155,12 @@ Result ICheatInterface::RemoveCheat(u32 cheat_id) {
} }
Result ICheatInterface::ReadStaticRegister(Out<u64> out_value, u8 register_index) { Result ICheatInterface::ReadStaticRegister(Out<u64> out_value, u8 register_index) {
LOG_DEBUG(CheatEngine, "called, register_index={}", register_index); LOG_INFO(CheatEngine, "called, register_index={}", register_index);
R_RETURN(cheat_process_manager.ReadStaticRegister(*out_value, register_index)); R_RETURN(cheat_process_manager.ReadStaticRegister(*out_value, register_index));
} }
Result ICheatInterface::WriteStaticRegister(u8 register_index, u64 value) { Result ICheatInterface::WriteStaticRegister(u64 register_index, u64 value) {
LOG_DEBUG(CheatEngine, "called, register_index={, value={}", register_index, value); LOG_INFO(CheatEngine, "called, register_index={, value={}", register_index, value);
R_RETURN(cheat_process_manager.WriteStaticRegister(register_index, value)); R_RETURN(cheat_process_manager.WriteStaticRegister(register_index, value));
} }
@ -191,12 +191,12 @@ Result ICheatInterface::GetFrozenAddresses(
Result ICheatInterface::GetFrozenAddress(Out<FrozenAddressEntry> out_frozen_address_entry, Result ICheatInterface::GetFrozenAddress(Out<FrozenAddressEntry> out_frozen_address_entry,
u64 address) { u64 address) {
LOG_INFO(CheatEngine, "called, address={}", address); LOG_INFO(CheatEngine, "called, adress={}", address);
R_RETURN(cheat_process_manager.GetFrozenAddress(*out_frozen_address_entry, address)); R_RETURN(cheat_process_manager.GetFrozenAddress(*out_frozen_address_entry, address));
} }
Result ICheatInterface::EnableFrozenAddress(Out<u64> out_value, u64 address, u64 width) { Result ICheatInterface::EnableFrozenAddress(Out<u64> out_value, u64 address, u64 width) {
LOG_INFO(CheatEngine, "called, address={}, width={}", address, width); LOG_INFO(CheatEngine, "called, adress={}, witdh={}", address, width);
R_UNLESS(width > 0, ResultFrozenAddressInvalidWidth); R_UNLESS(width > 0, ResultFrozenAddressInvalidWidth);
R_UNLESS(width <= sizeof(u64), ResultFrozenAddressInvalidWidth); R_UNLESS(width <= sizeof(u64), ResultFrozenAddressInvalidWidth);
R_UNLESS((width & (width - 1)) == 0, ResultFrozenAddressInvalidWidth); R_UNLESS((width & (width - 1)) == 0, ResultFrozenAddressInvalidWidth);
@ -204,7 +204,7 @@ Result ICheatInterface::EnableFrozenAddress(Out<u64> out_value, u64 address, u64
} }
Result ICheatInterface::DisableFrozenAddress(u64 address) { Result ICheatInterface::DisableFrozenAddress(u64 address) {
LOG_INFO(CheatEngine, "called, address={}", address); LOG_INFO(CheatEngine, "called, adress={}", address);
R_RETURN(cheat_process_manager.DisableFrozenAddress(address)); R_RETURN(cheat_process_manager.DisableFrozenAddress(address));
} }
@ -214,13 +214,13 @@ void ICheatInterface::InitializeCheatManager() {
Result ICheatInterface::ReadCheatProcessMemoryUnsafe(u64 process_addr, std::span<u8> out_data, Result ICheatInterface::ReadCheatProcessMemoryUnsafe(u64 process_addr, std::span<u8> out_data,
size_t size) { size_t size) {
LOG_DEBUG(CheatEngine, "called, process_addr={}, size={}", process_addr, size); LOG_INFO(CheatEngine, "called");
R_RETURN(cheat_process_manager.ReadCheatProcessMemoryUnsafe(process_addr, &out_data, size)); R_RETURN(cheat_process_manager.ReadCheatProcessMemoryUnsafe(process_addr, &out_data, size));
} }
Result ICheatInterface::WriteCheatProcessMemoryUnsafe(u64 process_addr, std::span<const u8> data, Result ICheatInterface::WriteCheatProcessMemoryUnsafe(u64 process_addr, std::span<const u8> data,
size_t size) { size_t size) {
LOG_DEBUG(CheatEngine, "called, process_addr={}, size={}", process_addr, size); LOG_INFO(CheatEngine, "called");
R_RETURN(cheat_process_manager.WriteCheatProcessMemoryUnsafe(process_addr, &data, size)); R_RETURN(cheat_process_manager.WriteCheatProcessMemoryUnsafe(process_addr, &data, size));
} }

View File

@ -35,7 +35,7 @@ public:
private: private:
Result HasCheatProcess(Out<bool> out_has_cheat); Result HasCheatProcess(Out<bool> out_has_cheat);
Result GetCheatProcessEvent(OutCopyHandle<Kernel::KReadableEvent> out_event); Result GetCheatProcessEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
Result GetCheatProcessMetadata(Out<CheatProcessMetadata> out_metadata); Result GetCheatProcessMetadata(CheatProcessMetadata out_metadata);
Result ForceOpenCheatProcess(); Result ForceOpenCheatProcess();
Result PauseCheatProcess(); Result PauseCheatProcess();
Result ResumeCheatProcess(); Result ResumeCheatProcess();
@ -60,7 +60,7 @@ private:
InLargeData<CheatDefinition, BufferAttr_HipcMapAlias> cheat_definition); InLargeData<CheatDefinition, BufferAttr_HipcMapAlias> cheat_definition);
Result RemoveCheat(u32 cheat_id); Result RemoveCheat(u32 cheat_id);
Result ReadStaticRegister(Out<u64> out_value, u8 register_index); Result ReadStaticRegister(Out<u64> out_value, u8 register_index);
Result WriteStaticRegister(u8 register_index, u64 value); Result WriteStaticRegister(u64 register_index, u64 value);
Result ResetStaticRegisters(); Result ResetStaticRegisters();
Result SetMasterCheat(InLargeData<CheatDefinition, BufferAttr_HipcMapAlias> cheat_definition); Result SetMasterCheat(InLargeData<CheatDefinition, BufferAttr_HipcMapAlias> cheat_definition);
Result GetFrozenAddressCount(Out<u64> out_count); Result GetFrozenAddressCount(Out<u64> out_count);

View File

@ -1,10 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // SPDX-License-Identifier: GPL-3.0-or-later
#include <algorithm>
#include <cctype>
#include <optional>
#include "core/hle/service/dmnt/cheat_parser.h" #include "core/hle/service/dmnt/cheat_parser.h"
#include "core/hle/service/dmnt/dmnt_types.h" #include "core/hle/service/dmnt/dmnt_types.h"
@ -19,7 +15,7 @@ std::vector<CheatEntry> CheatParser::Parse(std::string_view data) const {
std::optional<u64> current_entry; std::optional<u64> current_entry;
for (std::size_t i = 0; i < data.size(); ++i) { for (std::size_t i = 0; i < data.size(); ++i) {
if (std::isspace(data[i])) { if (::isspace(data[i])) {
continue; continue;
} }
@ -62,7 +58,7 @@ std::vector<CheatEntry> CheatParser::Parse(std::string_view data) const {
'\0'; '\0';
i += name_size + 1; i += name_size + 1;
} else if (std::isxdigit(data[i])) { } else if (::isxdigit(data[i])) {
if (!current_entry || out[*current_entry].definition.num_opcodes >= if (!current_entry || out[*current_entry].definition.num_opcodes >=
out[*current_entry].definition.opcodes.size()) { out[*current_entry].definition.opcodes.size()) {
return {}; return {};

View File

@ -44,7 +44,7 @@ void CheatProcessManager::SetVirtualMachine(std::unique_ptr<CheatVirtualMachine>
} }
bool CheatProcessManager::HasActiveCheatProcess() { bool CheatProcessManager::HasActiveCheatProcess() {
// Note: This function *MUST* be called only with the cheat lock held. /* Note: This function *MUST* be called only with the cheat lock held. */
bool has_cheat_process = bool has_cheat_process =
cheat_process_debug_handle != InvalidHandle && cheat_process_debug_handle != InvalidHandle &&
system.ApplicationProcess()->GetProcessId() == cheat_process_metadata.process_id; system.ApplicationProcess()->GetProcessId() == cheat_process_metadata.process_id;
@ -58,27 +58,28 @@ bool CheatProcessManager::HasActiveCheatProcess() {
void CheatProcessManager::CloseActiveCheatProcess() { void CheatProcessManager::CloseActiveCheatProcess() {
if (cheat_process_debug_handle != InvalidHandle) { if (cheat_process_debug_handle != InvalidHandle) {
// We don't need to do any unsafe breaking. /* We don't need to do any unsafe breaking. */
broken_unsafe = false; broken_unsafe = false;
unsafe_break_event->Signal(); unsafe_break_event->Signal();
core_timing.UnscheduleEvent(update_event); core_timing.UnscheduleEvent(update_event);
// Close resources. /* Close resources. */
// R_ABORT_UNLESS(svc::CloseHandle(cheat_process_debug_handle));
cheat_process_debug_handle = InvalidHandle; cheat_process_debug_handle = InvalidHandle;
// Save cheat toggles. /* Save cheat toggles. */
if (always_save_cheat_toggles || should_save_cheat_toggles) { if (always_save_cheat_toggles || should_save_cheat_toggles) {
// TODO: save cheat toggles // SaveCheatToggles(cheat_process_metadata.program_id);
should_save_cheat_toggles = false; should_save_cheat_toggles = false;
} }
// Clear metadata. /* Clear metadata. */
cheat_process_metadata = {}; cheat_process_metadata = {};
// Clear cheat list. /* Clear cheat list. */
ResetAllCheatEntries(); ResetAllCheatEntries();
// Clear frozen addresses. /* Clear frozen addresses. */
{ {
auto it = frozen_addresses_map.begin(); auto it = frozen_addresses_map.begin();
while (it != frozen_addresses_map.end()) { while (it != frozen_addresses_map.end()) {
@ -86,7 +87,7 @@ void CheatProcessManager::CloseActiveCheatProcess() {
} }
} }
// Signal to our fans. /* Signal to our fans. */
cheat_process_event->Signal(); cheat_process_event->Signal();
} }
} }
@ -119,18 +120,18 @@ void CheatProcessManager::ResetAllCheatEntries() {
CheatEntry* CheatProcessManager::GetCheatEntryById(size_t i) { CheatEntry* CheatProcessManager::GetCheatEntryById(size_t i) {
if (i < MaxCheatCount) { if (i < MaxCheatCount) {
return cheat_entries.data() + i; return cheat_entries + i;
} }
return nullptr; return nullptr;
} }
CheatEntry* CheatProcessManager::GetCheatEntryByReadableName(const char* readable_name) { CheatEntry* CheatProcessManager::GetCheatEntryByReadableName(const char* readable_name) {
// Check all non-master cheats for match. /* Check all non-master cheats for match. */
for (size_t i = 1; i < MaxCheatCount; i++) { for (size_t i = 1; i < MaxCheatCount; i++) {
if (std::strncmp(cheat_entries[i].definition.readable_name.data(), readable_name, if (std::strncmp(cheat_entries[i].definition.readable_name.data(), readable_name,
sizeof(cheat_entries[i].definition.readable_name)) == 0) { sizeof(cheat_entries[i].definition.readable_name)) == 0) {
return cheat_entries.data() + i; return cheat_entries + i;
} }
} }
@ -138,10 +139,10 @@ CheatEntry* CheatProcessManager::GetCheatEntryByReadableName(const char* readabl
} }
CheatEntry* CheatProcessManager::GetFreeCheatEntry() { CheatEntry* CheatProcessManager::GetFreeCheatEntry() {
// Check all non-master cheats for availability. /* Check all non-master cheats for availability. */
for (size_t i = 1; i < MaxCheatCount; i++) { for (size_t i = 1; i < MaxCheatCount; i++) {
if (cheat_entries[i].definition.num_opcodes == 0) { if (cheat_entries[i].definition.num_opcodes == 0) {
return cheat_entries.data() + i; return cheat_entries + i;
} }
} }
@ -162,18 +163,18 @@ Result CheatProcessManager::AttachToApplicationProcess(const std::array<u8, 0x20
u64 main_region_size) { u64 main_region_size) {
std::scoped_lock lk(cheat_lock); std::scoped_lock lk(cheat_lock);
// Close the active process, if needed. /* Close the active process, if needed. */
{ {
if (this->HasActiveCheatProcess()) { if (this->HasActiveCheatProcess()) {
// When forcing attach, we're done. /* When forcing attach, we're done. */
this->CloseActiveCheatProcess(); this->CloseActiveCheatProcess();
} }
} }
// Get the application process's ID. /* Get the application process's ID. */
cheat_process_metadata.process_id = system.ApplicationProcess()->GetProcessId(); cheat_process_metadata.process_id = system.ApplicationProcess()->GetProcessId();
// Get process handle, use it to learn memory extents. /* Get process handle, use it to learn memory extents. */
{ {
const auto& page_table = system.ApplicationProcess()->GetPageTable(); const auto& page_table = system.ApplicationProcess()->GetPageTable();
cheat_process_metadata.program_id = system.GetApplicationProcessProgramID(); cheat_process_metadata.program_id = system.GetApplicationProcessProgramID();
@ -191,7 +192,7 @@ Result CheatProcessManager::AttachToApplicationProcess(const std::array<u8, 0x20
}; };
} }
// Get module information from loader. /* Get module information from loader. */
{ {
cheat_process_metadata.main_nso_extents = { cheat_process_metadata.main_nso_extents = {
.base = main_region_begin, .base = main_region_begin,
@ -200,17 +201,17 @@ Result CheatProcessManager::AttachToApplicationProcess(const std::array<u8, 0x20
cheat_process_metadata.main_nso_build_id = build_id; cheat_process_metadata.main_nso_build_id = build_id;
} }
// Set our debug handle. /* Set our debug handle. */
cheat_process_debug_handle = cheat_process_metadata.process_id; cheat_process_debug_handle = cheat_process_metadata.process_id;
// Reset broken state. /* Reset broken state. */
broken_unsafe = false; broken_unsafe = false;
unsafe_break_event->Signal(); unsafe_break_event->Signal();
// start the process. /*start the process. */
core_timing.ScheduleLoopingEvent(CHEAT_ENGINE_NS, CHEAT_ENGINE_NS, update_event); core_timing.ScheduleLoopingEvent(CHEAT_ENGINE_NS, CHEAT_ENGINE_NS, update_event);
// Signal to our fans. /* Signal to our fans. */
cheat_process_event->Signal(); cheat_process_event->Signal();
R_SUCCEED(); R_SUCCEED();
@ -271,7 +272,22 @@ Result CheatProcessManager::GetCheatProcessMappingCount(u64& out_count) {
std::scoped_lock lk(cheat_lock); std::scoped_lock lk(cheat_lock);
R_TRY(this->EnsureCheatProcess()); R_TRY(this->EnsureCheatProcess());
// TODO: Call svc::QueryDebugProcessMemory // svc::MemoryInfo mem_info;
// svc::PageInfo page_info;
// u64 address = 0, count = 0;
// do {
// if (R_FAILED(svc::QueryDebugProcessMemory(std::addressof(mem_info),
// std::addressof(page_info),
// this->GetCheatProcessHandle(), address))) {
// break;
// }
// if (mem_info.permission != svc::MemoryPermission_None) {
// count++;
// }
// address = mem_info.base_address + mem_info.size;
//} while (address != 0);
out_count = 0; out_count = 0;
R_SUCCEED(); R_SUCCEED();
@ -282,7 +298,25 @@ Result CheatProcessManager::GetCheatProcessMappings(
std::scoped_lock lk(cheat_lock); std::scoped_lock lk(cheat_lock);
R_TRY(this->EnsureCheatProcess()); R_TRY(this->EnsureCheatProcess());
// TODO: Call svc::QueryDebugProcessMemory // svc::MemoryInfo mem_info;
// svc::PageInfo page_info;
// u64 address = 0, total_count = 0, written_count = 0;
// do {
// if (R_FAILED(svc::QueryDebugProcessMemory(std::addressof(mem_info),
// std::addressof(page_info),
// this->GetCheatProcessHandle(), address))) {
// break;
// }
// if (mem_info.permission != svc::MemoryPermission_None) {
// if (offset <= total_count && written_count < max_count) {
// mappings[written_count++] = mem_info;
// }
// total_count++;
// }
// address = mem_info.base_address + mem_info.size;
//} while (address != 0 && written_count < max_count);
out_count = 0; out_count = 0;
R_SUCCEED(); R_SUCCEED();
@ -343,8 +377,14 @@ Result CheatProcessManager::GetCheatCount(u64& out_count) {
std::scoped_lock lk(cheat_lock); std::scoped_lock lk(cheat_lock);
R_TRY(EnsureCheatProcess()); R_TRY(EnsureCheatProcess());
out_count = std::count_if(cheat_entries.begin(), cheat_entries.end(), size_t count = 0;
[](const auto& entry) { return entry.definition.num_opcodes != 0; }); for (size_t i = 0; i < MaxCheatCount; i++) {
if (cheat_entries[i].definition.num_opcodes) {
count++;
}
}
out_count = count;
R_SUCCEED(); R_SUCCEED();
} }
@ -391,7 +431,7 @@ Result CheatProcessManager::ToggleCheat(u32 cheat_id) {
entry->enabled = !entry->enabled; entry->enabled = !entry->enabled;
// Trigger a VM reload. /* Trigger a VM reload. */
SetNeedsReloadVm(true); SetNeedsReloadVm(true);
R_SUCCEED(); R_SUCCEED();
@ -411,10 +451,10 @@ Result CheatProcessManager::AddCheat(u32& out_cheat_id, bool enabled,
new_entry->enabled = enabled; new_entry->enabled = enabled;
new_entry->definition = cheat_definition; new_entry->definition = cheat_definition;
// Trigger a VM reload. /* Trigger a VM reload. */
SetNeedsReloadVm(true); SetNeedsReloadVm(true);
// Set output id. /* Set output id. */
out_cheat_id = new_entry->cheat_id; out_cheat_id = new_entry->cheat_id;
R_SUCCEED(); R_SUCCEED();
@ -430,7 +470,7 @@ Result CheatProcessManager::RemoveCheat(u32 cheat_id) {
R_SUCCEED(); R_SUCCEED();
} }
Result CheatProcessManager::ReadStaticRegister(u64& out_value, u64 register_index) { Result CheatProcessManager::ReadStaticRegister(u64& out_value, u8 register_index) {
std::scoped_lock lk(cheat_lock); std::scoped_lock lk(cheat_lock);
R_TRY(EnsureCheatProcess()); R_TRY(EnsureCheatProcess());
R_UNLESS(register_index < CheatVirtualMachine::NumStaticRegisters, ResultCheatInvalid); R_UNLESS(register_index < CheatVirtualMachine::NumStaticRegisters, ResultCheatInvalid);
@ -463,12 +503,12 @@ Result CheatProcessManager::SetMasterCheat(const CheatDefinition& cheat_definiti
R_UNLESS(cheat_definition.num_opcodes != 0, ResultCheatInvalid); R_UNLESS(cheat_definition.num_opcodes != 0, ResultCheatInvalid);
R_UNLESS(cheat_definition.num_opcodes <= cheat_definition.opcodes.size(), ResultCheatInvalid); R_UNLESS(cheat_definition.num_opcodes <= cheat_definition.opcodes.size(), ResultCheatInvalid);
cheat_entries[0] = { CheatEntry* master_entry = cheat_entries + 0;
.enabled = true,
.definition = cheat_definition,
};
// Trigger a VM reload. master_entry->enabled = true;
master_entry->definition = cheat_definition;
/* Trigger a VM reload. */
SetNeedsReloadVm(true); SetNeedsReloadVm(true);
R_SUCCEED(); R_SUCCEED();

View File

@ -67,7 +67,7 @@ public:
Result AddCheat(u32& out_cheat_id, bool enabled, const CheatDefinition& cheat_definition); Result AddCheat(u32& out_cheat_id, bool enabled, const CheatDefinition& cheat_definition);
Result RemoveCheat(u32 cheat_id); Result RemoveCheat(u32 cheat_id);
Result ReadStaticRegister(u64& out_value, u64 register_index); Result ReadStaticRegister(u64& out_value, u8 register_index);
Result WriteStaticRegister(u64 register_index, u64 value); Result WriteStaticRegister(u64 register_index, u64 value);
Result ResetStaticRegisters(); Result ResetStaticRegisters();
Result SetMasterCheat(const CheatDefinition& cheat_definition); Result SetMasterCheat(const CheatDefinition& cheat_definition);
@ -111,7 +111,7 @@ private:
bool enable_cheats_by_default = true; bool enable_cheats_by_default = true;
bool always_save_cheat_toggles = false; bool always_save_cheat_toggles = false;
bool should_save_cheat_toggles = false; bool should_save_cheat_toggles = false;
std::array<CheatEntry, MaxCheatCount> cheat_entries = {}; CheatEntry cheat_entries[MaxCheatCount] = {};
// TODO: Replace with IntrusiveRedBlackTree // TODO: Replace with IntrusiveRedBlackTree
std::map<u64, FrozenAddressValue> frozen_addresses_map = {}; std::map<u64, FrozenAddressValue> frozen_addresses_map = {};

View File

@ -1,7 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project // SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later // 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_interface.h"
#include "core/hle/service/dmnt/cheat_process_manager.h" #include "core/hle/service/dmnt/cheat_process_manager.h"
#include "core/hle/service/dmnt/cheat_virtual_machine.h" #include "core/hle/service/dmnt/cheat_virtual_machine.h"

View File

@ -25,19 +25,18 @@ struct CheatProcessMetadata {
static_assert(sizeof(CheatProcessMetadata) == 0x70, "CheatProcessMetadata is an invalid size"); static_assert(sizeof(CheatProcessMetadata) == 0x70, "CheatProcessMetadata is an invalid size");
struct CheatDefinition { struct CheatDefinition {
std::array<char, 0x40> readable_name; std::array<char, 0x40> readable_name{};
u32 num_opcodes; u32 num_opcodes{};
std::array<u32, 0x100> opcodes; std::array<u32, 0x100> opcodes{};
}; };
static_assert(sizeof(CheatDefinition) == 0x444, "CheatDefinition is an invalid size"); static_assert(sizeof(CheatDefinition) == 0x444, "CheatDefinition is an invalid size");
struct CheatEntry { struct CheatEntry {
bool enabled; bool enabled{};
u32 cheat_id; u32 cheat_id{};
CheatDefinition definition; CheatDefinition definition{};
}; };
static_assert(sizeof(CheatEntry) == 0x44C, "CheatEntry is an invalid size"); 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 { struct FrozenAddressValue {
u64 value; u64 value;

View File

@ -59,8 +59,6 @@ ConfigurePerGameAddons::ConfigurePerGameAddons(Core::System& system_, QWidget* p
ui->scrollArea->setLayout(layout); ui->scrollArea->setLayout(layout);
ui->scrollArea->setEnabled(!system.IsPoweredOn());
connect(item_model, &QStandardItemModel::itemChanged, connect(item_model, &QStandardItemModel::itemChanged,
[] { UISettings::values.is_game_list_reload_pending.exchange(true); }); [] { UISettings::values.is_game_list_reload_pending.exchange(true); });
} }
@ -128,12 +126,24 @@ void ConfigurePerGameAddons::LoadConfiguration() {
auto* const first_item = new QStandardItem; auto* const first_item = new QStandardItem;
first_item->setText(name); first_item->setText(name);
first_item->setCheckable(true); first_item->setCheckable(true);
first_item->setEnabled(!system.IsPoweredOn());
const auto patch_disabled = const auto patch_disabled =
std::find(disabled.begin(), disabled.end(), name.toStdString()) != disabled.end(); std::find(disabled.begin(), disabled.end(), name.toStdString()) != disabled.end();
first_item->setCheckState(patch_disabled ? Qt::Unchecked : Qt::Checked); first_item->setCheckState(patch_disabled ? Qt::Unchecked : Qt::Checked);
for (const auto& cheat : patch.cheats) {
auto* const sub_item = new QStandardItem;
const auto cheat_name = QString::fromStdString(cheat.name);
sub_item->setText(cheat_name);
sub_item->setCheckable(true);
sub_item->setCheckState(cheat.enabled ? Qt::Checked : Qt::Unchecked);
first_item->appendRow(sub_item);
first_item->setEnabled(true);
}
list_items.push_back(QList<QStandardItem*>{ list_items.push_back(QList<QStandardItem*>{
first_item, new QStandardItem{QString::fromStdString(patch.version)}}); first_item, new QStandardItem{QString::fromStdString(patch.version)}});
item_model->appendRow(list_items.back()); item_model->appendRow(list_items.back());