// Copyright 2021 Dolphin Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #include "Core/CheatGeneration.h" #include #include #include "Common/Align.h" #include "Common/CommonTypes.h" #include "Common/Result.h" #include "Common/Swap.h" #include "Core/ActionReplay.h" #include "Core/CheatSearch.h" constexpr int AR_SET_BYTE_CMD = 0x00; constexpr int AR_SET_SHORT_CMD = 0x02; constexpr int AR_SET_INT_CMD = 0x04; static std::vector ResultToAREntries(u32 addr, const Cheats::SearchValue& sv) { std::vector codes; std::vector data = Cheats::GetValueAsByteVector(sv); for (size_t i = 0; i < data.size(); ++i) { const u32 address = (addr + i) & 0x01ff'ffffu; if (Common::AlignUp(address, 4) == address && i + 3 < data.size()) { const u8 cmd = AR_SET_INT_CMD; const u32 val = Common::swap32(&data[i]); codes.emplace_back((cmd << 24) | address, val); i += 3; } else if (Common::AlignUp(address, 2) == address && i + 1 < data.size()) { const u8 cmd = AR_SET_SHORT_CMD; const u32 val = Common::swap16(&data[i]); codes.emplace_back((cmd << 24) | address, val); ++i; } else { const u8 cmd = AR_SET_BYTE_CMD; const u32 val = data[i]; codes.emplace_back((cmd << 24) | address, val); } } return codes; } Common::Result Cheats::GenerateActionReplayCode(const Cheats::CheatSearchSessionBase& session, size_t index) { if (index >= session.GetResultCount()) return Cheats::GenerateActionReplayCodeErrorCode::IndexOutOfRange; if (session.GetResultValueState(index) != Cheats::SearchResultValueState::ValueFromVirtualMemory) return Cheats::GenerateActionReplayCodeErrorCode::NotVirtualMemory; u32 address = session.GetResultAddress(index); // check if the address is actually addressable by the ActionReplay system if (((address & 0x01ff'ffffu) | 0x8000'0000u) != address) return Cheats::GenerateActionReplayCodeErrorCode::InvalidAddress; ActionReplay::ARCode ar_code; ar_code.enabled = true; ar_code.user_defined = true; ar_code.name = fmt::format("Generated by Cheat Search (Address 0x{:08x})", address); ar_code.ops = ResultToAREntries(address, session.GetResultValueAsSearchValue(index)); return ar_code; }