duckstation

duckstation, but archived from the revision just before upstream changed it to a proprietary software project, this version is the libre one
git clone https://git.neptards.moe/u3shit/duckstation.git
Log | Files | Refs | README | LICENSE

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 };