Cheats: Apply all cheats at once (fixes game crashes that could occur because the game could run a full frame between each cheat)

This commit is contained in:
Souryo 2016-08-28 18:58:22 -04:00
parent 94dd9683d1
commit ecea158f50
6 changed files with 99 additions and 57 deletions

View File

@ -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<CodeInfo>());
@ -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<CodeInfo> 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<CodeInfo> &cheats)
{
//Used by NetPlay

View File

@ -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<CodeInfo> GetCheats();
static void SetCheats(vector<CodeInfo> &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);

View File

@ -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();
}
}
}

View File

@ -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();

View File

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

View File

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