cheats.h (8704B)
1 // SPDX-FileCopyrightText: 2019-2024 Connor McLaughlin <stenzek@gmail.com> and contributors. 2 // SPDX-License-Identifier: (GPL-3.0 OR CC-BY-NC-ND-4.0) 3 4 #pragma once 5 6 #include "common/bitfield.h" 7 8 #include "types.h" 9 10 #include <optional> 11 #include <string> 12 #include <vector> 13 14 struct CheatCode 15 { 16 enum class Type : u8 17 { 18 Gameshark, 19 Count 20 }; 21 22 enum class Activation : u8 23 { 24 Manual, 25 EndFrame, 26 Count, 27 }; 28 29 enum class InstructionCode : u8 30 { 31 Nop = 0x00, 32 ConstantWrite8 = 0x30, 33 ConstantWrite16 = 0x80, 34 ScratchpadWrite16 = 0x1F, 35 Increment16 = 0x10, 36 Decrement16 = 0x11, 37 Increment8 = 0x20, 38 Decrement8 = 0x21, 39 DelayActivation = 0xC1, 40 SkipIfNotEqual16 = 0xC0, 41 SkipIfButtonsNotEqual = 0xD5, 42 SkipIfButtonsEqual = 0xD6, 43 CompareButtons = 0xD4, 44 CompareEqual16 = 0xD0, 45 CompareNotEqual16 = 0xD1, 46 CompareLess16 = 0xD2, 47 CompareGreater16 = 0xD3, 48 CompareEqual8 = 0xE0, 49 CompareNotEqual8 = 0xE1, 50 CompareLess8 = 0xE2, 51 CompareGreater8 = 0xE3, 52 Slide = 0x50, 53 MemoryCopy = 0xC2, 54 ExtImprovedSlide = 0x53, 55 56 // Extension opcodes, not present on original GameShark. 57 ExtConstantWrite32 = 0x90, 58 ExtScratchpadWrite32 = 0xA5, 59 ExtCompareEqual32 = 0xA0, 60 ExtCompareNotEqual32 = 0xA1, 61 ExtCompareLess32 = 0xA2, 62 ExtCompareGreater32 = 0xA3, 63 ExtSkipIfNotEqual32 = 0xA4, 64 ExtIncrement32 = 0x60, 65 ExtDecrement32 = 0x61, 66 ExtConstantWriteIfMatch16 = 0xA6, 67 ExtConstantWriteIfMatchWithRestore16 = 0xA7, 68 ExtConstantForceRange8 = 0xF0, 69 ExtConstantForceRangeLimits16 = 0xF1, 70 ExtConstantForceRangeRollRound16 = 0xF2, 71 ExtConstantForceRange16 = 0xF3, 72 ExtFindAndReplace = 0xF4, 73 ExtConstantSwap16 = 0xF5, 74 75 ExtConstantBitSet8 = 0x31, 76 ExtConstantBitClear8 = 0x32, 77 ExtConstantBitSet16 = 0x81, 78 ExtConstantBitClear16 = 0x82, 79 ExtConstantBitSet32 = 0x91, 80 ExtConstantBitClear32 = 0x92, 81 82 ExtBitCompareButtons = 0xD7, 83 ExtSkipIfNotLess8 = 0xC3, 84 ExtSkipIfNotGreater8 = 0xC4, 85 ExtSkipIfNotLess16 = 0xC5, 86 ExtSkipIfNotGreater16 = 0xC6, 87 ExtMultiConditionals = 0xF6, 88 89 ExtCheatRegisters = 0x51, 90 ExtCheatRegistersCompare = 0x52, 91 92 ExtCompareBitsSet8 = 0xE4, //Only used inside ExtMultiConditionals 93 ExtCompareBitsClear8 = 0xE5, //Only used inside ExtMultiConditionals 94 }; 95 96 union Instruction 97 { 98 u64 bits; 99 100 struct 101 { 102 u32 second; 103 u32 first; 104 }; 105 106 BitField<u64, InstructionCode, 32 + 24, 8> code; 107 BitField<u64, u32, 32, 24> address; 108 BitField<u64, u32, 0, 32> value32; 109 BitField<u64, u16, 0, 16> value16; 110 BitField<u64, u8, 0, 8> value8; 111 }; 112 113 std::string group; 114 std::string description; 115 std::vector<Instruction> instructions; 116 std::string comments; 117 Type type = Type::Gameshark; 118 Activation activation = Activation::EndFrame; 119 bool enabled = false; 120 121 ALWAYS_INLINE bool Valid() const { return !instructions.empty() && !description.empty(); } 122 ALWAYS_INLINE bool IsManuallyActivated() const { return (activation == Activation::Manual); } 123 124 std::string GetInstructionsAsString() const; 125 bool SetInstructionsFromString(const std::string& str); 126 127 u32 GetNextNonConditionalInstruction(u32 index) const; 128 129 void Apply() const; 130 void ApplyOnDisable() const; 131 132 static const char* GetTypeName(Type type); 133 static const char* GetTypeDisplayName(Type type); 134 static std::optional<Type> ParseTypeName(const char* str); 135 136 static const char* GetActivationName(Activation activation); 137 static const char* GetActivationDisplayName(Activation activation); 138 static std::optional<Activation> ParseActivationName(const char* str); 139 }; 140 141 class CheatList final 142 { 143 public: 144 enum class Format 145 { 146 Autodetect, 147 PCSXR, 148 Libretro, 149 EPSXe, 150 Count 151 }; 152 153 CheatList(); 154 ~CheatList(); 155 156 ALWAYS_INLINE const CheatCode& GetCode(u32 i) const { return m_codes[i]; } 157 ALWAYS_INLINE CheatCode& GetCode(u32 i) { return m_codes[i]; } 158 ALWAYS_INLINE u32 GetCodeCount() const { return static_cast<u32>(m_codes.size()); } 159 ALWAYS_INLINE bool IsCodeEnabled(u32 index) const { return m_codes[index].enabled; } 160 161 ALWAYS_INLINE bool GetMasterEnable() const { return m_master_enable; } 162 ALWAYS_INLINE void SetMasterEnable(bool enable) { m_master_enable = enable; } 163 164 const CheatCode* FindCode(const char* name) const; 165 const CheatCode* FindCode(const char* group, const char* name) const; 166 167 void AddCode(CheatCode cc); 168 void SetCode(u32 index, CheatCode cc); 169 void RemoveCode(u32 i); 170 171 u32 GetEnabledCodeCount() const; 172 std::vector<std::string> GetCodeGroups() const; 173 void EnableCode(u32 index); 174 void DisableCode(u32 index); 175 void SetCodeEnabled(u32 index, bool state); 176 177 static std::optional<Format> DetectFileFormat(const char* filename); 178 static Format DetectFileFormat(const std::string& str); 179 static bool ParseLibretroCheat(CheatCode* cc, const char* line); 180 181 bool LoadFromFile(const char* filename, Format format); 182 bool LoadFromPCSXRFile(const char* filename); 183 bool LoadFromLibretroFile(const char* filename); 184 185 bool LoadFromString(const std::string& str, Format format); 186 bool LoadFromPCSXRString(const std::string& str); 187 bool LoadFromLibretroString(const std::string& str); 188 bool LoadFromEPSXeString(const std::string& str); 189 190 bool SaveToPCSXRFile(const char* filename); 191 192 bool LoadFromPackage(const std::string& serial); 193 194 void Apply(); 195 196 void ApplyCode(u32 index); 197 198 void MergeList(const CheatList& cl); 199 200 private: 201 std::vector<CheatCode> m_codes; 202 bool m_master_enable = true; 203 }; 204 205 class MemoryScan 206 { 207 public: 208 enum class Operator 209 { 210 Any, 211 LessThanLast, 212 LessEqualLast, 213 GreaterThanLast, 214 GreaterEqualLast, 215 NotEqualLast, 216 EqualLast, 217 DecreasedBy, 218 IncreasedBy, 219 ChangedBy, 220 Equal, 221 NotEqual, 222 LessThan, 223 LessEqual, 224 GreaterThan, 225 GreaterEqual 226 }; 227 228 struct Result 229 { 230 PhysicalMemoryAddress address; 231 u32 value; 232 u32 last_value; 233 bool value_changed; 234 235 bool Filter(Operator op, u32 comp_value, bool is_signed) const; 236 void UpdateValue(MemoryAccessSize size, bool is_signed); 237 }; 238 239 using ResultVector = std::vector<Result>; 240 241 MemoryScan(); 242 ~MemoryScan(); 243 244 u32 GetValue() const { return m_value; } 245 bool GetValueSigned() const { return m_signed; } 246 MemoryAccessSize GetSize() const { return m_size; } 247 Operator GetOperator() const { return m_operator; } 248 PhysicalMemoryAddress GetStartAddress() const { return m_start_address; } 249 PhysicalMemoryAddress GetEndAddress() const { return m_end_address; } 250 const ResultVector& GetResults() const { return m_results; } 251 const Result& GetResult(u32 index) const { return m_results[index]; } 252 u32 GetResultCount() const { return static_cast<u32>(m_results.size()); } 253 254 void SetValue(u32 value) { m_value = value; } 255 void SetValueSigned(bool s) { m_signed = s; } 256 void SetSize(MemoryAccessSize size) { m_size = size; } 257 void SetOperator(Operator op) { m_operator = op; } 258 void SetStartAddress(PhysicalMemoryAddress addr) { m_start_address = addr; } 259 void SetEndAddress(PhysicalMemoryAddress addr) { m_end_address = addr; } 260 261 void ResetSearch(); 262 void Search(); 263 void SearchAgain(); 264 void UpdateResultsValues(); 265 266 void SetResultValue(u32 index, u32 value); 267 268 private: 269 void SearchBytes(); 270 void SearchHalfwords(); 271 void SearchWords(); 272 273 u32 m_value = 0; 274 MemoryAccessSize m_size = MemoryAccessSize::HalfWord; 275 Operator m_operator = Operator::Equal; 276 PhysicalMemoryAddress m_start_address = 0; 277 PhysicalMemoryAddress m_end_address = 0x200000; 278 ResultVector m_results; 279 bool m_signed = false; 280 }; 281 282 class MemoryWatchList 283 { 284 public: 285 MemoryWatchList(); 286 ~MemoryWatchList(); 287 288 struct Entry 289 { 290 std::string description; 291 u32 address; 292 u32 value; 293 MemoryAccessSize size; 294 bool is_signed; 295 bool freeze; 296 bool changed; 297 }; 298 299 using EntryVector = std::vector<Entry>; 300 301 const Entry* GetEntryByAddress(u32 address) const; 302 const EntryVector& GetEntries() const { return m_entries; } 303 const Entry& GetEntry(u32 index) const { return m_entries[index]; } 304 u32 GetEntryCount() const { return static_cast<u32>(m_entries.size()); } 305 306 bool AddEntry(std::string description, u32 address, MemoryAccessSize size, bool is_signed, bool freeze); 307 void RemoveEntry(u32 index); 308 bool RemoveEntryByDescription(const char* description); 309 bool RemoveEntryByAddress(u32 address); 310 311 void SetEntryDescription(u32 index, std::string description); 312 void SetEntryFreeze(u32 index, bool freeze); 313 void SetEntryValue(u32 index, u32 value); 314 315 void UpdateValues(); 316 317 private: 318 static void SetEntryValue(Entry* entry, u32 value); 319 static void UpdateEntryValue(Entry* entry); 320 321 EntryVector m_entries; 322 };