From ecea158f503d89a40c79d28ab7f6381c2e1949b5 Mon Sep 17 00:00:00 2001 From: Souryo Date: Sun, 28 Aug 2016 18:58:22 -0400 Subject: [PATCH] Cheats: Apply all cheats at once (fixes game crashes that could occur because the game could run a full frame between each cheat) --- Core/CheatManager.cpp | 41 +++++++++++++++++--------- Core/CheatManager.h | 29 ++++++++++++++++--- GUI.NET/Config/CheatInfo.cs | 54 ++++++++++++++++------------------- GUI.NET/Forms/frmMain.cs | 6 ++-- GUI.NET/InteropEmu.cs | 21 +++++++++++--- InteropDLL/ConsoleWrapper.cpp | 5 +--- 6 files changed, 99 insertions(+), 57 deletions(-) diff --git a/Core/CheatManager.cpp b/Core/CheatManager.cpp index e0a4aa31..535ded8f 100644 --- a/Core/CheatManager.cpp +++ b/Core/CheatManager.cpp @@ -84,7 +84,6 @@ CodeInfo CheatManager::GetPARCodeInfo(uint32_t parCode) void CheatManager::AddCode(CodeInfo &code) { - Console::Pause(); if(code.IsRelativeAddress) { if(_relativeCheatCodes[code.Address] == nullptr) { _relativeCheatCodes[code.Address].reset(new vector()); @@ -94,19 +93,18 @@ void CheatManager::AddCode(CodeInfo &code) _absoluteCheatCodes.push_back(code); } MessageManager::SendNotification(ConsoleNotificationType::CheatAdded); - Console::Resume(); } void CheatManager::AddGameGenieCode(string code) { - CodeInfo info = Instance->GetGGCodeInfo(code); - Instance->AddCode(info); + CodeInfo info = GetGGCodeInfo(code); + AddCode(info); } void CheatManager::AddProActionRockyCode(uint32_t code) { - CodeInfo info = Instance->GetPARCodeInfo(code); - Instance->AddCode(info); + CodeInfo info = GetPARCodeInfo(code); + AddCode(info); } void CheatManager::AddCustomCode(uint32_t address, uint8_t value, int32_t compareValue, bool isRelativeAddress) @@ -117,29 +115,26 @@ void CheatManager::AddCustomCode(uint32_t address, uint8_t value, int32_t compar code.CompareValue = compareValue; code.IsRelativeAddress = isRelativeAddress; - Instance->AddCode(code); + AddCode(code); } void CheatManager::ClearCodes() { bool cheatRemoved = false; - Console::Pause(); for(int i = 0; i <= 0xFFFF; i++) { - if(!Instance->_relativeCheatCodes[i]) { + if(!_relativeCheatCodes[i]) { cheatRemoved = true; } - Instance->_relativeCheatCodes[i] = nullptr; + _relativeCheatCodes[i].reset(); } - cheatRemoved |= Instance->_absoluteCheatCodes.size() > 0; - Instance->_absoluteCheatCodes.clear(); + cheatRemoved |= _absoluteCheatCodes.size() > 0; + _absoluteCheatCodes.clear(); if(cheatRemoved) { MessageManager::SendNotification(ConsoleNotificationType::CheatRemoved); } - - Console::Resume(); } void CheatManager::ApplyRamCodes(uint16_t addr, uint8_t &value) @@ -182,6 +177,24 @@ vector CheatManager::GetCheats() return cheats; } +void CheatManager::SetCheats(CheatInfo cheats[], uint32_t length) +{ + Console::Pause(); + + Instance->ClearCodes(); + + for(uint32_t i = 0; i < length; i++) { + CheatInfo &cheat = cheats[i]; + switch(cheat.CheatType) { + case CheatType::Custom: Instance->AddCustomCode(cheat.Address, cheat.Value, cheat.UseCompareValue ? cheat.CompareValue : -1, cheat.IsRelativeAddress); break; + case CheatType::GameGenie: Instance->AddGameGenieCode(cheat.GameGenieCode); break; + case CheatType::ProActionRocky: Instance->AddProActionRockyCode(cheat.ProActionRockyCode); break; + } + } + + Console::Resume(); +} + void CheatManager::SetCheats(vector &cheats) { //Used by NetPlay diff --git a/Core/CheatManager.h b/Core/CheatManager.h index 492d4a41..190c200b 100644 --- a/Core/CheatManager.h +++ b/Core/CheatManager.h @@ -10,6 +10,25 @@ struct CodeInfo bool IsRelativeAddress; }; +enum class CheatType +{ + GameGenie = 0, + ProActionRocky = 1, + Custom = 2 +}; + +struct CheatInfo +{ + CheatType CheatType; + uint32_t ProActionRockyCode; + uint32_t Address; + char GameGenieCode[9]; + uint8_t Value; + uint8_t CompareValue; + bool UseCompareValue; + bool IsRelativeAddress; +}; + class CheatManager { private: @@ -21,16 +40,18 @@ private: CodeInfo GetGGCodeInfo(string ggCode); CodeInfo GetPARCodeInfo(uint32_t parCode); void AddCode(CodeInfo &code); + + void AddGameGenieCode(string code); + void AddProActionRockyCode(uint32_t code); + void AddCustomCode(uint32_t address, uint8_t value, int32_t compareValue = -1, bool isRelativeAddress = true); + void ClearCodes(); public: CheatManager(); - static void AddGameGenieCode(string code); - static void AddProActionRockyCode(uint32_t code); - static void AddCustomCode(uint32_t address, uint8_t value, int32_t compareValue = -1, bool isRelativeAddress = true); - static void ClearCodes(); static vector GetCheats(); static void SetCheats(vector &cheats); + static void SetCheats(CheatInfo cheats[], uint32_t length); static void ApplyRamCodes(uint16_t addr, uint8_t &value); static void ApplyPrgCodes(uint8_t *prgRam, uint32_t prgSize); diff --git a/GUI.NET/Config/CheatInfo.cs b/GUI.NET/Config/CheatInfo.cs index 98da9279..2561b049 100644 --- a/GUI.NET/Config/CheatInfo.cs +++ b/GUI.NET/Config/CheatInfo.cs @@ -41,45 +41,41 @@ namespace Mesen.GUI.Config return string.Empty; } - public void ApplyCheat() - { - switch(CheatType) { - case CheatType.Custom: - InteropEmu.CheatAddCustom(Address, Value, UseCompareValue ? CompareValue : -1, IsRelativeAddress); - break; - - case Config.CheatType.GameGenie: - InteropEmu.CheatAddGameGenie(GameGenieCode); - break; - - case Config.CheatType.ProActionRocky: - InteropEmu.CheatAddProActionRocky(ProActionRockyCode); - break; - } - } - public static void ClearCheats() { - InteropEmu.CheatClear(); + InteropEmu.SetCheats(new InteropCheatInfo[] { }, 0); + } + + private InteropCheatInfo ToInterop() + { + byte[] ggCode = Encoding.UTF8.GetBytes(GameGenieCode ?? ""); + Array.Resize(ref ggCode, 9); + + return new InteropCheatInfo() { + CheatType = CheatType, + GameGenieCode = ggCode, + ProActionRockyCode = ProActionRockyCode, + Address = Address, + Value = Value, + CompareValue = CompareValue, + UseCompareValue = UseCompareValue, + IsRelativeAddress = IsRelativeAddress + }; } public static void ApplyCheats() { - InteropEmu.CheatClear(); - if(!ConfigManager.Config.DisableAllCheats) { string crc = InteropEmu.GetRomInfo().GetPrgCrcString(); - int cheatCount = 0; - foreach(CheatInfo cheat in ConfigManager.Config.Cheats.Where(c => c.GameCrc == crc)) { - if(cheat.Enabled) { - cheat.ApplyCheat(); - cheatCount++; - } - } - if(cheatCount > 0) { - InteropEmu.DisplayMessage("Cheats", cheatCount > 1 ? "CheatsApplied" : "CheatApplied", cheatCount.ToString()); + InteropCheatInfo[] cheats = ConfigManager.Config.Cheats.Where(c => c.GameCrc == crc).Select(cheat => cheat.ToInterop()).ToArray(); + InteropEmu.SetCheats(cheats, (UInt32)cheats.Length); + + if(cheats.Length > 0) { + InteropEmu.DisplayMessage("Cheats", cheats.Length > 1 ? "CheatsApplied" : "CheatApplied", cheats.Length.ToString()); } + } else { + ClearCheats(); } } } diff --git a/GUI.NET/Forms/frmMain.cs b/GUI.NET/Forms/frmMain.cs index b2adcb92..b19b1c5c 100644 --- a/GUI.NET/Forms/frmMain.cs +++ b/GUI.NET/Forms/frmMain.cs @@ -1048,8 +1048,10 @@ namespace Mesen.GUI.Forms _cheatListWindow = new frmCheatList(); _cheatListWindow.Show(sender, this); _cheatListWindow.FormClosed += (s, evt) => { - _cheatListWindow = null; - CheatInfo.ApplyCheats(); + if(_cheatListWindow.DialogResult == DialogResult.OK) { + CheatInfo.ApplyCheats(); + } + _cheatListWindow = null; }; } else { _cheatListWindow.Focus(); diff --git a/GUI.NET/InteropEmu.cs b/GUI.NET/InteropEmu.cs index a407e8fd..02d55dd7 100644 --- a/GUI.NET/InteropEmu.cs +++ b/GUI.NET/InteropEmu.cs @@ -7,6 +7,7 @@ using System.Runtime.InteropServices; using System.Text; using System.Threading.Tasks; using System.Windows.Forms; +using Mesen.GUI.Config; using Mesen.GUI.Forms; namespace Mesen.GUI @@ -119,10 +120,7 @@ namespace Mesen.GUI [DllImport(DLLPath)] public static extern void VsInsertCoin(UInt32 port); [DllImport(DLLPath)] public static extern void VsSetGameConfig(PpuModel model, VsInputType inputType, byte dipSwitches); - [DllImport(DLLPath)] public static extern void CheatAddCustom(UInt32 address, Byte value, Int32 compareValue, [MarshalAs(UnmanagedType.I1)]bool isRelativeAddress); - [DllImport(DLLPath)] public static extern void CheatAddGameGenie([MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef=typeof(UTF8Marshaler))]string code); - [DllImport(DLLPath)] public static extern void CheatAddProActionRocky(UInt32 code); - [DllImport(DLLPath)] public static extern void CheatClear(); + [DllImport(DLLPath)] public static extern void SetCheats([MarshalAs(UnmanagedType.LPArray, SizeParamIndex=1)]InteropCheatInfo[] cheats, UInt32 length); [DllImport(DLLPath)] private static extern void SetFlags(EmulationFlags flags); [DllImport(DLLPath)] private static extern void ClearFlags(EmulationFlags flags); @@ -701,6 +699,21 @@ namespace Mesen.GUI } }; + public struct InteropCheatInfo + { + public CheatType CheatType; + public UInt32 ProActionRockyCode; + public UInt32 Address; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 9)] + public byte[] GameGenieCode; + public byte Value; + public byte CompareValue; + [MarshalAs(UnmanagedType.I1)] + public bool UseCompareValue; + [MarshalAs(UnmanagedType.I1)] + public bool IsRelativeAddress; + } + public struct InteropBreakpoint { public BreakpointType Type; diff --git a/InteropDLL/ConsoleWrapper.cpp b/InteropDLL/ConsoleWrapper.cpp index 7f10a5a1..b15659e0 100644 --- a/InteropDLL/ConsoleWrapper.cpp +++ b/InteropDLL/ConsoleWrapper.cpp @@ -317,10 +317,7 @@ namespace InteropEmu { DllExport bool __stdcall RomTestRecording() { return _autoRomTest != nullptr; } - DllExport void __stdcall CheatAddCustom(uint32_t address, uint8_t value, int32_t compareValue, bool isRelativeAddress) { CheatManager::AddCustomCode(address, value, compareValue, isRelativeAddress); } - DllExport void __stdcall CheatAddGameGenie(char* code) { CheatManager::AddGameGenieCode(code); } - DllExport void __stdcall CheatAddProActionRocky(uint32_t code) { CheatManager::AddProActionRockyCode(code); } - DllExport void __stdcall CheatClear() { CheatManager::ClearCodes(); } + DllExport void __stdcall SetCheats(CheatInfo cheats[], uint32_t length) { CheatManager::SetCheats(cheats, length); } DllExport void __stdcall SetFlags(EmulationFlags flags) { EmulationSettings::SetFlags(flags); } DllExport void __stdcall ClearFlags(EmulationFlags flags) { EmulationSettings::ClearFlags(flags); }