CheatGeneration.cpp 2.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778
  1. // Copyright 2021 Dolphin Emulator Project
  2. // SPDX-License-Identifier: GPL-2.0-or-later
  3. #include "Core/CheatGeneration.h"
  4. #include <vector>
  5. #include <fmt/format.h>
  6. #include "Common/Align.h"
  7. #include "Common/CommonTypes.h"
  8. #include "Common/Result.h"
  9. #include "Common/Swap.h"
  10. #include "Core/ActionReplay.h"
  11. #include "Core/CheatSearch.h"
  12. constexpr int AR_SET_BYTE_CMD = 0x00;
  13. constexpr int AR_SET_SHORT_CMD = 0x02;
  14. constexpr int AR_SET_INT_CMD = 0x04;
  15. static std::vector<ActionReplay::AREntry> ResultToAREntries(u32 addr, const Cheats::SearchValue& sv)
  16. {
  17. std::vector<ActionReplay::AREntry> codes;
  18. std::vector<u8> data = Cheats::GetValueAsByteVector(sv);
  19. for (size_t i = 0; i < data.size(); ++i)
  20. {
  21. const u32 address = (addr + i) & 0x01ff'ffffu;
  22. if (Common::AlignUp(address, 4) == address && i + 3 < data.size())
  23. {
  24. const u8 cmd = AR_SET_INT_CMD;
  25. const u32 val = Common::swap32(&data[i]);
  26. codes.emplace_back((cmd << 24) | address, val);
  27. i += 3;
  28. }
  29. else if (Common::AlignUp(address, 2) == address && i + 1 < data.size())
  30. {
  31. const u8 cmd = AR_SET_SHORT_CMD;
  32. const u32 val = Common::swap16(&data[i]);
  33. codes.emplace_back((cmd << 24) | address, val);
  34. ++i;
  35. }
  36. else
  37. {
  38. const u8 cmd = AR_SET_BYTE_CMD;
  39. const u32 val = data[i];
  40. codes.emplace_back((cmd << 24) | address, val);
  41. }
  42. }
  43. return codes;
  44. }
  45. Common::Result<Cheats::GenerateActionReplayCodeErrorCode, ActionReplay::ARCode>
  46. Cheats::GenerateActionReplayCode(const Cheats::CheatSearchSessionBase& session, size_t index)
  47. {
  48. if (index >= session.GetResultCount())
  49. return Cheats::GenerateActionReplayCodeErrorCode::IndexOutOfRange;
  50. if (session.GetResultValueState(index) != Cheats::SearchResultValueState::ValueFromVirtualMemory)
  51. return Cheats::GenerateActionReplayCodeErrorCode::NotVirtualMemory;
  52. u32 address = session.GetResultAddress(index);
  53. // check if the address is actually addressable by the ActionReplay system
  54. if (((address & 0x01ff'ffffu) | 0x8000'0000u) != address)
  55. return Cheats::GenerateActionReplayCodeErrorCode::InvalidAddress;
  56. ActionReplay::ARCode ar_code;
  57. ar_code.enabled = true;
  58. ar_code.user_defined = true;
  59. ar_code.name = fmt::format("Generated by Cheat Search (Address 0x{:08x})", address);
  60. ar_code.ops = ResultToAREntries(address, session.GetResultValueAsSearchValue(index));
  61. return ar_code;
  62. }