Core: Improve support for ROM patch cheats, supporting disabling overlapping patches

This commit is contained in:
Vicki Pfau 2020-12-23 18:35:42 -08:00
parent a59ffbc9a6
commit 5781566717
9 changed files with 190 additions and 183 deletions

View File

@ -92,6 +92,7 @@ Misc:
- Core: Add savedataUpdated callback - Core: Add savedataUpdated callback
- Core: Add shutdown callback - Core: Add shutdown callback
- Core: Rework thread state synchronization - Core: Rework thread state synchronization
- Core: Improve support for ROM patch cheats, supporting disabling overlapping patches
- GB: Allow pausing event loop while CPU is blocked - GB: Allow pausing event loop while CPU is blocked
- GB: Add support for sleep and shutdown callbacks - GB: Add support for sleep and shutdown callbacks
- GB I/O: Implement preliminary support for PCM12/PCM34 (closes mgba.io/i/1468) - GB I/O: Implement preliminary support for PCM12/PCM34 (closes mgba.io/i/1468)

View File

@ -12,6 +12,7 @@ CXX_GUARD_START
#include <mgba/core/cpu.h> #include <mgba/core/cpu.h>
#include <mgba/core/log.h> #include <mgba/core/log.h>
#include <mgba-util/table.h>
#include <mgba-util/vector.h> #include <mgba-util/vector.h>
enum mCheatType { enum mCheatType {
@ -44,9 +45,20 @@ struct mCheat {
int32_t operandOffset; int32_t operandOffset;
}; };
struct mCheatPatch {
uint32_t address;
int segment;
uint32_t value;
int width;
bool applied;
uint32_t checkValue;
bool check;
};
mLOG_DECLARE_CATEGORY(CHEATS); mLOG_DECLARE_CATEGORY(CHEATS);
DECLARE_VECTOR(mCheatList, struct mCheat); DECLARE_VECTOR(mCheatList, struct mCheat);
DECLARE_VECTOR(mCheatPatchList, struct mCheatPatch);
struct mCheatDevice; struct mCheatDevice;
struct mCheatSet { struct mCheatSet {
@ -66,6 +78,7 @@ struct mCheatSet {
char* name; char* name;
bool enabled; bool enabled;
struct mCheatPatchList romPatches;
struct StringList lines; struct StringList lines;
}; };
@ -78,6 +91,7 @@ struct mCheatDevice {
struct mCheatSet* (*createSet)(struct mCheatDevice*, const char* name); struct mCheatSet* (*createSet)(struct mCheatDevice*, const char* name);
struct mCheatSets cheats; struct mCheatSets cheats;
struct Table unpatchedMemory;
bool autosave; bool autosave;
bool buttonDown; bool buttonDown;
}; };

View File

@ -11,7 +11,6 @@
CXX_GUARD_START CXX_GUARD_START
#include <mgba/core/cheats.h> #include <mgba/core/cheats.h>
#include <mgba-util/vector.h>
enum GBCheatType { enum GBCheatType {
GB_CHEAT_AUTODETECT, GB_CHEAT_AUTODETECT,
@ -20,22 +19,6 @@ enum GBCheatType {
GB_CHEAT_VBA GB_CHEAT_VBA
}; };
struct GBCheatPatch {
uint16_t address;
int8_t newValue;
int8_t oldValue;
int segment;
bool applied;
bool checkByte;
};
DECLARE_VECTOR(GBCheatPatchList, struct GBCheatPatch);
struct GBCheatSet {
struct mCheatSet d;
struct GBCheatPatchList romPatches;
};
struct mCheatDevice* GBCheatDeviceCreate(void); struct mCheatDevice* GBCheatDeviceCreate(void);
CXX_GUARD_END CXX_GUARD_END

View File

@ -134,23 +134,14 @@ struct GBACheatHook {
size_t reentries; size_t reentries;
}; };
struct GBACheatPatch {
uint32_t address;
int16_t newValue;
int16_t oldValue;
bool applied;
};
DECLARE_VECTOR(GBACheatPatchList, struct GBACheatPatch); DECLARE_VECTOR(GBACheatPatchList, struct GBACheatPatch);
struct GBACheatSet { struct GBACheatSet {
struct mCheatSet d; struct mCheatSet d;
struct GBACheatHook* hook; struct GBACheatHook* hook;
struct GBACheatPatchList romPatches;
size_t incompleteCheat; size_t incompleteCheat;
struct GBACheatPatch* incompletePatch; struct mCheatPatch* incompletePatch;
size_t currentBlock; size_t currentBlock;
int gsaVersion; int gsaVersion;

View File

@ -18,6 +18,33 @@ mLOG_DEFINE_CATEGORY(CHEATS, "Cheats", "core.cheats");
DEFINE_VECTOR(mCheatList, struct mCheat); DEFINE_VECTOR(mCheatList, struct mCheat);
DEFINE_VECTOR(mCheatSets, struct mCheatSet*); DEFINE_VECTOR(mCheatSets, struct mCheatSet*);
DEFINE_VECTOR(mCheatPatchList, struct mCheatPatch);
struct mCheatPatchedMem {
uint32_t originalValue;
int refs;
bool dirty;
};
static uint32_t _patchMakeKey(struct mCheatPatch* patch) {
// NB: This assumes patches have only one valid size per platform
uint32_t patchKey = patch->address;
switch (patch->width) {
case 2:
patchKey >>= 1;
break;
case 4:
patchKey >>= 2;
break;
default:
break;
}
// TODO: More than one segment
if (patch->segment > 0) {
patchKey |= patch->segment << 16;
}
return patchKey;
}
static int32_t _readMem(struct mCore* core, uint32_t address, int width) { static int32_t _readMem(struct mCore* core, uint32_t address, int width) {
switch (width) { switch (width) {
@ -31,6 +58,18 @@ static int32_t _readMem(struct mCore* core, uint32_t address, int width) {
return 0; return 0;
} }
static int32_t _readMemSegment(struct mCore* core, uint32_t address, int segment, int width) {
switch (width) {
case 1:
return core->rawRead8(core, address, segment);
case 2:
return core->rawRead16(core, address, segment);
case 4:
return core->rawRead32(core, address, segment);
}
return 0;
}
static void _writeMem(struct mCore* core, uint32_t address, int width, int32_t value) { static void _writeMem(struct mCore* core, uint32_t address, int width, int32_t value) {
switch (width) { switch (width) {
case 1: case 1:
@ -45,6 +84,83 @@ static void _writeMem(struct mCore* core, uint32_t address, int width, int32_t v
} }
} }
static void _patchMem(struct mCore* core, uint32_t address, int segment, int width, int32_t value) {
switch (width) {
case 1:
core->rawWrite8(core, address, segment, value);
break;
case 2:
core->rawWrite16(core, address, segment, value);
break;
case 4:
core->rawWrite32(core, address, segment, value);
break;
}
}
static void _patchROM(struct mCheatDevice* device, struct mCheatSet* cheats) {
if (!device->p) {
return;
}
size_t i;
for (i = 0; i < mCheatPatchListSize(&cheats->romPatches); ++i) {
struct mCheatPatch* patch = mCheatPatchListGetPointer(&cheats->romPatches, i);
int segment = -1;
if (patch->check && patch->segment < 0) {
int maxSegment = 0;
for (segment = 0; segment < maxSegment; ++segment) {
uint32_t value = _readMemSegment(device->p, patch->address, segment, patch->width);
if (value == patch->checkValue) {
break;
}
}
if (segment == maxSegment) {
continue;
}
}
patch->segment = segment;
uint32_t patchKey = _patchMakeKey(patch);
struct mCheatPatchedMem* patchData = TableLookup(&device->unpatchedMemory, patchKey);
if (!patchData) {
patchData = malloc(sizeof(*patchData));
patchData->originalValue = _readMemSegment(device->p, patch->address, segment, patch->width);
patchData->refs = 1;
patchData->dirty = false;
TableInsert(&device->unpatchedMemory, patchKey, patchData);
} else if (!patch->applied) {
++patchData->refs;
patchData->dirty = true;
} else if (!patchData->dirty) {
continue;
}
_patchMem(device->p, patch->address, segment, patch->width, patch->value);
patch->applied = true;
}
}
static void _unpatchROM(struct mCheatDevice* device, struct mCheatSet* cheats) {
if (!device->p) {
return;
}
size_t i;
for (i = 0; i < mCheatPatchListSize(&cheats->romPatches); ++i) {
struct mCheatPatch* patch = mCheatPatchListGetPointer(&cheats->romPatches, i);
if (!patch->applied) {
continue;
}
uint32_t patchKey = _patchMakeKey(patch);
struct mCheatPatchedMem* patchData = TableLookup(&device->unpatchedMemory, patchKey);
--patchData->refs;
patchData->dirty = true;
if (patchData->refs <= 0) {
_patchMem(device->p, patch->address, patch->segment, patch->width, patchData->originalValue);
TableRemove(&device->unpatchedMemory, patchKey);
}
patch->applied = false;
}
}
static void mCheatDeviceInit(void*, struct mCPUComponent*); static void mCheatDeviceInit(void*, struct mCPUComponent*);
static void mCheatDeviceDeinit(struct mCPUComponent*); static void mCheatDeviceDeinit(struct mCPUComponent*);
@ -55,11 +171,13 @@ void mCheatDeviceCreate(struct mCheatDevice* device) {
device->autosave = false; device->autosave = false;
device->buttonDown = false; device->buttonDown = false;
mCheatSetsInit(&device->cheats, 4); mCheatSetsInit(&device->cheats, 4);
TableInit(&device->unpatchedMemory, 4, free);
} }
void mCheatDeviceDestroy(struct mCheatDevice* device) { void mCheatDeviceDestroy(struct mCheatDevice* device) {
mCheatDeviceClear(device); mCheatDeviceClear(device);
mCheatSetsDeinit(&device->cheats); mCheatSetsDeinit(&device->cheats);
TableDeinit(&device->unpatchedMemory);
free(device); free(device);
} }
@ -75,6 +193,7 @@ void mCheatDeviceClear(struct mCheatDevice* device) {
void mCheatSetInit(struct mCheatSet* set, const char* name) { void mCheatSetInit(struct mCheatSet* set, const char* name) {
mCheatListInit(&set->list, 4); mCheatListInit(&set->list, 4);
StringListInit(&set->lines, 4); StringListInit(&set->lines, 4);
mCheatPatchListInit(&set->romPatches, 4);
if (name) { if (name) {
set->name = strdup(name); set->name = strdup(name);
} else { } else {
@ -93,7 +212,10 @@ void mCheatSetDeinit(struct mCheatSet* set) {
free(set->name); free(set->name);
} }
StringListDeinit(&set->lines); StringListDeinit(&set->lines);
mCheatPatchListDeinit(&set->romPatches);
if (set->deinit) {
set->deinit(set); set->deinit(set);
}
free(set); free(set);
} }
@ -117,7 +239,9 @@ bool mCheatAddLine(struct mCheatSet* set, const char* line, int type) {
void mCheatAddSet(struct mCheatDevice* device, struct mCheatSet* cheats) { void mCheatAddSet(struct mCheatDevice* device, struct mCheatSet* cheats) {
*mCheatSetsAppend(&device->cheats) = cheats; *mCheatSetsAppend(&device->cheats) = cheats;
if (cheats->add) {
cheats->add(cheats, device); cheats->add(cheats, device);
}
} }
void mCheatRemoveSet(struct mCheatDevice* device, struct mCheatSet* cheats) { void mCheatRemoveSet(struct mCheatDevice* device, struct mCheatSet* cheats) {
@ -131,7 +255,9 @@ void mCheatRemoveSet(struct mCheatDevice* device, struct mCheatSet* cheats) {
return; return;
} }
mCheatSetsShift(&device->cheats, i, 1); mCheatSetsShift(&device->cheats, i, 1);
if (cheats->remove) {
cheats->remove(cheats, device); cheats->remove(cheats, device);
}
} }
bool mCheatParseFile(struct mCheatDevice* device, struct VFile* vf) { bool mCheatParseFile(struct mCheatDevice* device, struct VFile* vf) {
@ -503,8 +629,14 @@ void mCheatAutosave(struct mCheatDevice* device) {
#endif #endif
void mCheatRefresh(struct mCheatDevice* device, struct mCheatSet* cheats) { void mCheatRefresh(struct mCheatDevice* device, struct mCheatSet* cheats) {
if (cheats->enabled) {
_patchROM(device, cheats);
}
if (cheats->refresh) {
cheats->refresh(cheats, device); cheats->refresh(cheats, device);
}
if (!cheats->enabled) { if (!cheats->enabled) {
_unpatchROM(device, cheats);
return; return;
} }

View File

@ -10,58 +10,6 @@
#include <mgba/internal/gb/memory.h> #include <mgba/internal/gb/memory.h>
#include <mgba-util/string.h> #include <mgba-util/string.h>
DEFINE_VECTOR(GBCheatPatchList, struct GBCheatPatch);
static void _patchROM(struct mCheatDevice* device, struct GBCheatSet* cheats) {
if (!device->p) {
return;
}
size_t i;
for (i = 0; i < GBCheatPatchListSize(&cheats->romPatches); ++i) {
struct GBCheatPatch* patch = GBCheatPatchListGetPointer(&cheats->romPatches, i);
if (patch->applied) {
continue;
}
int segment = 0;
if (patch->checkByte) {
struct GB* gb = device->p->board;
int maxSegment = (gb->memory.romSize + GB_SIZE_CART_BANK0 - 1) / GB_SIZE_CART_BANK0;
for (; segment < maxSegment; ++segment) {
int8_t value = GBView8(device->p->cpu, patch->address, segment);
if (value == patch->oldValue) {
break;
}
}
if (segment == maxSegment) {
continue;
}
}
// TODO: More than one segment
GBPatch8(device->p->cpu, patch->address, patch->newValue, &patch->oldValue, segment);
patch->applied = true;
patch->segment = segment;
}
}
static void _unpatchROM(struct mCheatDevice* device, struct GBCheatSet* cheats) {
if (!device->p) {
return;
}
size_t i;
for (i = 0; i < GBCheatPatchListSize(&cheats->romPatches); ++i) {
struct GBCheatPatch* patch = GBCheatPatchListGetPointer(&cheats->romPatches, i);
if (!patch->applied) {
continue;
}
GBPatch8(device->p->cpu, patch->address, patch->oldValue, &patch->newValue, patch->segment);
patch->applied = false;
}
}
static void GBCheatSetDeinit(struct mCheatSet* set);
static void GBCheatAddSet(struct mCheatSet* cheats, struct mCheatDevice* device);
static void GBCheatRemoveSet(struct mCheatSet* cheats, struct mCheatDevice* device);
static void GBCheatRefresh(struct mCheatSet* cheats, struct mCheatDevice* device);
static void GBCheatSetCopyProperties(struct mCheatSet* set, struct mCheatSet* oldSet); static void GBCheatSetCopyProperties(struct mCheatSet* set, struct mCheatSet* oldSet);
static void GBCheatParseDirectives(struct mCheatSet* set, const struct StringList* directives); static void GBCheatParseDirectives(struct mCheatSet* set, const struct StringList* directives);
static void GBCheatDumpDirectives(struct mCheatSet* set, struct StringList* directives); static void GBCheatDumpDirectives(struct mCheatSet* set, struct StringList* directives);
@ -69,23 +17,21 @@ static bool GBCheatAddLine(struct mCheatSet*, const char* line, int type);
static struct mCheatSet* GBCheatSetCreate(struct mCheatDevice* device, const char* name) { static struct mCheatSet* GBCheatSetCreate(struct mCheatDevice* device, const char* name) {
UNUSED(device); UNUSED(device);
struct GBCheatSet* set = malloc(sizeof(*set)); struct mCheatSet* set = malloc(sizeof(*set));
mCheatSetInit(&set->d, name); mCheatSetInit(set, name);
GBCheatPatchListInit(&set->romPatches, 0); set->deinit = NULL;
set->add = NULL;
set->remove = NULL;
set->d.deinit = GBCheatSetDeinit; set->addLine = GBCheatAddLine;
set->d.add = GBCheatAddSet; set->copyProperties = GBCheatSetCopyProperties;
set->d.remove = GBCheatRemoveSet;
set->d.addLine = GBCheatAddLine; set->parseDirectives = GBCheatParseDirectives;
set->d.copyProperties = GBCheatSetCopyProperties; set->dumpDirectives = GBCheatDumpDirectives;
set->d.parseDirectives = GBCheatParseDirectives; set->refresh = NULL;
set->d.dumpDirectives = GBCheatDumpDirectives; return set;
set->d.refresh = GBCheatRefresh;
return &set->d;
} }
struct mCheatDevice* GBCheatDeviceCreate(void) { struct mCheatDevice* GBCheatDeviceCreate(void) {
@ -95,23 +41,8 @@ struct mCheatDevice* GBCheatDeviceCreate(void) {
return device; return device;
} }
static void GBCheatSetDeinit(struct mCheatSet* set) { static bool GBCheatAddCodebreaker(struct mCheatSet* cheats, uint16_t address, uint8_t data) {
struct GBCheatSet* gbset = (struct GBCheatSet*) set; struct mCheat* cheat = mCheatListAppend(&cheats->list);
GBCheatPatchListDeinit(&gbset->romPatches);
}
static void GBCheatAddSet(struct mCheatSet* cheats, struct mCheatDevice* device) {
struct GBCheatSet* gbset = (struct GBCheatSet*) cheats;
_patchROM(device, gbset);
}
static void GBCheatRemoveSet(struct mCheatSet* cheats, struct mCheatDevice* device) {
struct GBCheatSet* gbset = (struct GBCheatSet*) cheats;
_unpatchROM(device, gbset);
}
static bool GBCheatAddCodebreaker(struct GBCheatSet* cheats, uint16_t address, uint8_t data) {
struct mCheat* cheat = mCheatListAppend(&cheats->d.list);
cheat->type = CHEAT_ASSIGN; cheat->type = CHEAT_ASSIGN;
cheat->width = 1; cheat->width = 1;
cheat->address = address; cheat->address = address;
@ -121,11 +52,11 @@ static bool GBCheatAddCodebreaker(struct GBCheatSet* cheats, uint16_t address, u
return true; return true;
} }
static bool GBCheatAddGameShark(struct GBCheatSet* cheats, uint32_t op) { static bool GBCheatAddGameShark(struct mCheatSet* cheats, uint32_t op) {
return GBCheatAddCodebreaker(cheats, ((op & 0xFF) << 8) | ((op >> 8) & 0xFF), (op >> 16) & 0xFF); return GBCheatAddCodebreaker(cheats, ((op & 0xFF) << 8) | ((op >> 8) & 0xFF), (op >> 16) & 0xFF);
} }
static bool GBCheatAddGameSharkLine(struct GBCheatSet* cheats, const char* line) { static bool GBCheatAddGameSharkLine(struct mCheatSet* cheats, const char* line) {
uint32_t op; uint32_t op;
if (!hex32(line, &op)) { if (!hex32(line, &op)) {
return false; return false;
@ -133,7 +64,7 @@ static bool GBCheatAddGameSharkLine(struct GBCheatSet* cheats, const char* line)
return GBCheatAddGameShark(cheats, op); return GBCheatAddGameShark(cheats, op);
} }
static bool GBCheatAddGameGenieLine(struct GBCheatSet* cheats, const char* line) { static bool GBCheatAddGameGenieLine(struct mCheatSet* cheats, const char* line) {
uint16_t op1; uint16_t op1;
uint16_t op2; uint16_t op2;
uint16_t op3 = 0x1000; uint16_t op3 = 0x1000;
@ -156,24 +87,26 @@ static bool GBCheatAddGameGenieLine(struct GBCheatSet* cheats, const char* line)
uint16_t address = (op1 & 0xF) << 8; uint16_t address = (op1 & 0xF) << 8;
address |= (op2 >> 4) & 0xFF; address |= (op2 >> 4) & 0xFF;
address |= ((op2 & 0xF) ^ 0xF) << 12; address |= ((op2 & 0xF) ^ 0xF) << 12;
struct GBCheatPatch* patch = GBCheatPatchListAppend(&cheats->romPatches); struct mCheatPatch* patch = mCheatPatchListAppend(&cheats->romPatches);
patch->address = address; patch->address = address;
patch->newValue = op1 >> 4; patch->value = op1 >> 4;
patch->applied = false; patch->applied = false;
patch->width = 1;
patch->segment = -1;
if (op3 < 0x1000) { if (op3 < 0x1000) {
uint32_t value = ((op3 & 0xF00) << 20) | (op3 & 0xF); uint32_t value = ((op3 & 0xF00) << 20) | (op3 & 0xF);
value = ROR(value, 2); value = ROR(value, 2);
value |= value >> 24; value |= value >> 24;
value ^= 0xBA; value ^= 0xBA;
patch->oldValue = value; patch->checkValue = value;
patch->checkByte = true; patch->check = true;
} else { } else {
patch->checkByte = false; patch->check = false;
} }
return true; return true;
} }
static bool GBCheatAddVBALine(struct GBCheatSet* cheats, const char* line) { static bool GBCheatAddVBALine(struct mCheatSet* cheats, const char* line) {
uint16_t address; uint16_t address;
uint8_t value; uint8_t value;
const char* lineNext = hex16(line, &address); const char* lineNext = hex16(line, &address);
@ -183,7 +116,7 @@ static bool GBCheatAddVBALine(struct GBCheatSet* cheats, const char* line) {
if (!hex8(line, &value)) { if (!hex8(line, &value)) {
return false; return false;
} }
struct mCheat* cheat = mCheatListAppend(&cheats->d.list); struct mCheat* cheat = mCheatListAppend(&cheats->list);
cheat->type = CHEAT_ASSIGN; cheat->type = CHEAT_ASSIGN;
cheat->width = 1; cheat->width = 1;
cheat->address = address; cheat->address = address;
@ -193,8 +126,7 @@ static bool GBCheatAddVBALine(struct GBCheatSet* cheats, const char* line) {
return true; return true;
} }
bool GBCheatAddLine(struct mCheatSet* set, const char* line, int type) { bool GBCheatAddLine(struct mCheatSet* cheats, const char* line, int type) {
struct GBCheatSet* cheats = (struct GBCheatSet*) set;
switch (type) { switch (type) {
case GB_CHEAT_AUTODETECT: case GB_CHEAT_AUTODETECT:
break; break;
@ -242,15 +174,6 @@ bool GBCheatAddLine(struct mCheatSet* set, const char* line, int type) {
} }
} }
static void GBCheatRefresh(struct mCheatSet* cheats, struct mCheatDevice* device) {
struct GBCheatSet* gbset = (struct GBCheatSet*) cheats;
if (cheats->enabled) {
_patchROM(device, gbset);
} else {
_unpatchROM(device, gbset);
}
}
static void GBCheatSetCopyProperties(struct mCheatSet* set, struct mCheatSet* oldSet) { static void GBCheatSetCopyProperties(struct mCheatSet* set, struct mCheatSet* oldSet) {
UNUSED(set); UNUSED(set);
UNUSED(oldSet); UNUSED(oldSet);

View File

@ -13,8 +13,6 @@
#define MAX_LINE_LENGTH 128 #define MAX_LINE_LENGTH 128
DEFINE_VECTOR(GBACheatPatchList, struct GBACheatPatch);
static void _addBreakpoint(struct mCheatDevice* device, struct GBACheatSet* cheats) { static void _addBreakpoint(struct mCheatDevice* device, struct GBACheatSet* cheats) {
if (!device->p || !cheats->hook) { if (!device->p || !cheats->hook) {
return; return;
@ -37,36 +35,6 @@ static void _removeBreakpoint(struct mCheatDevice* device, struct GBACheatSet* c
GBAClearBreakpoint(device->p->board, cheats->hook->address, cheats->hook->mode, cheats->hook->patchedOpcode); GBAClearBreakpoint(device->p->board, cheats->hook->address, cheats->hook->mode, cheats->hook->patchedOpcode);
} }
static void _patchROM(struct mCheatDevice* device, struct GBACheatSet* cheats) {
if (!device->p) {
return;
}
size_t i;
for (i = 0; i < GBACheatPatchListSize(&cheats->romPatches); ++i) {
struct GBACheatPatch* patch = GBACheatPatchListGetPointer(&cheats->romPatches, i);
if (patch->applied) {
continue;
}
GBAPatch16(device->p->cpu, patch->address, patch->newValue, &patch->oldValue);
patch->applied = true;
}
}
static void _unpatchROM(struct mCheatDevice* device, struct GBACheatSet* cheats) {
if (!device->p) {
return;
}
size_t i;
for (i = 0; i < GBACheatPatchListSize(&cheats->romPatches); ++i) {
struct GBACheatPatch* patch = GBACheatPatchListGetPointer(&cheats->romPatches, i);
if (!patch->applied) {
continue;
}
GBAPatch16(device->p->cpu, patch->address, patch->oldValue, NULL);
patch->applied = false;
}
}
static void GBACheatSetDeinit(struct mCheatSet* set); static void GBACheatSetDeinit(struct mCheatSet* set);
static void GBACheatAddSet(struct mCheatSet* cheats, struct mCheatDevice* device); static void GBACheatAddSet(struct mCheatSet* cheats, struct mCheatDevice* device);
static void GBACheatRemoveSet(struct mCheatSet* cheats, struct mCheatDevice* device); static void GBACheatRemoveSet(struct mCheatSet* cheats, struct mCheatDevice* device);
@ -101,7 +69,6 @@ static struct mCheatSet* GBACheatSetCreate(struct mCheatDevice* device, const ch
set->d.refresh = GBACheatRefresh; set->d.refresh = GBACheatRefresh;
GBACheatPatchListInit(&set->romPatches, 4);
return &set->d; return &set->d;
} }
@ -120,18 +87,15 @@ static void GBACheatSetDeinit(struct mCheatSet* set) {
free(gbaset->hook); free(gbaset->hook);
} }
} }
GBACheatPatchListDeinit(&gbaset->romPatches);
} }
static void GBACheatAddSet(struct mCheatSet* cheats, struct mCheatDevice* device) { static void GBACheatAddSet(struct mCheatSet* cheats, struct mCheatDevice* device) {
struct GBACheatSet* gbaset = (struct GBACheatSet*) cheats; struct GBACheatSet* gbaset = (struct GBACheatSet*) cheats;
_addBreakpoint(device, gbaset); _addBreakpoint(device, gbaset);
_patchROM(device, gbaset);
} }
static void GBACheatRemoveSet(struct mCheatSet* cheats, struct mCheatDevice* device) { static void GBACheatRemoveSet(struct mCheatSet* cheats, struct mCheatDevice* device) {
struct GBACheatSet* gbaset = (struct GBACheatSet*) cheats; struct GBACheatSet* gbaset = (struct GBACheatSet*) cheats;
_unpatchROM(device, gbaset);
_removeBreakpoint(device, gbaset); _removeBreakpoint(device, gbaset);
} }
@ -276,14 +240,9 @@ bool GBACheatAddLine(struct mCheatSet* set, const char* line, int type) {
static void GBACheatRefresh(struct mCheatSet* cheats, struct mCheatDevice* device) { static void GBACheatRefresh(struct mCheatSet* cheats, struct mCheatDevice* device) {
struct GBACheatSet* gbaset = (struct GBACheatSet*) cheats; struct GBACheatSet* gbaset = (struct GBACheatSet*) cheats;
if (cheats->enabled) { if (cheats->enabled && gbaset->hook && !gbaset->hook->reentries) {
_patchROM(device, gbaset);
if (gbaset->hook && !gbaset->hook->reentries) {
_addBreakpoint(device, gbaset); _addBreakpoint(device, gbaset);
} }
} else {
_unpatchROM(device, gbaset);
}
} }
static void GBACheatSetCopyProperties(struct mCheatSet* set, struct mCheatSet* oldSet) { static void GBACheatSetCopyProperties(struct mCheatSet* set, struct mCheatSet* oldSet) {

View File

@ -93,7 +93,7 @@ void GBACheatSetGameSharkVersion(struct GBACheatSet* cheats, enum GBACheatGameSh
bool GBACheatAddGameSharkRaw(struct GBACheatSet* cheats, uint32_t op1, uint32_t op2) { bool GBACheatAddGameSharkRaw(struct GBACheatSet* cheats, uint32_t op1, uint32_t op2) {
enum GBAGameSharkType type = op1 >> 28; enum GBAGameSharkType type = op1 >> 28;
struct mCheat* cheat = 0; struct mCheat* cheat = 0;
struct GBACheatPatch* romPatch; struct mCheatPatch* romPatch;
if (cheats->incompleteCheat != COMPLETE) { if (cheats->incompleteCheat != COMPLETE) {
struct mCheat* incompleteCheat = mCheatListGetPointer(&cheats->d.list, cheats->incompleteCheat); struct mCheat* incompleteCheat = mCheatListGetPointer(&cheats->d.list, cheats->incompleteCheat);
@ -149,10 +149,12 @@ bool GBACheatAddGameSharkRaw(struct GBACheatSet* cheats, uint32_t op1, uint32_t
cheats->incompleteCheat = mCheatListIndex(&cheats->d.list, cheat); cheats->incompleteCheat = mCheatListIndex(&cheats->d.list, cheat);
break; break;
case GSA_PATCH: case GSA_PATCH:
romPatch = GBACheatPatchListAppend(&cheats->romPatches); romPatch = mCheatPatchListAppend(&cheats->d.romPatches);
romPatch->address = BASE_CART0 | ((op1 & 0xFFFFFF) << 1); romPatch->address = BASE_CART0 | ((op1 & 0xFFFFFF) << 1);
romPatch->newValue = op2; romPatch->value = op2;
romPatch->applied = false; romPatch->applied = false;
romPatch->width = 2;
romPatch->check = false;
return true; return true;
case GSA_BUTTON: case GSA_BUTTON:
switch (op1 & 0x00F00000) { switch (op1 & 0x00F00000) {

View File

@ -230,9 +230,11 @@ static bool _addPAR3Special(struct GBACheatSet* cheats, uint32_t op2) {
break; break;
} }
if (romPatch >= 0) { if (romPatch >= 0) {
struct GBACheatPatch* patch = GBACheatPatchListAppend(&cheats->romPatches); struct mCheatPatch* patch = mCheatPatchListAppend(&cheats->d.romPatches);
patch->address = BASE_CART0 | ((op2 & 0xFFFFFF) << 1); patch->address = BASE_CART0 | ((op2 & 0xFFFFFF) << 1);
patch->applied = false; patch->applied = false;
patch->check = false;
patch->width = 2;
cheats->incompletePatch = patch; cheats->incompletePatch = patch;
} }
return true; return true;
@ -240,8 +242,8 @@ static bool _addPAR3Special(struct GBACheatSet* cheats, uint32_t op2) {
bool GBACheatAddProActionReplayRaw(struct GBACheatSet* cheats, uint32_t op1, uint32_t op2) { bool GBACheatAddProActionReplayRaw(struct GBACheatSet* cheats, uint32_t op1, uint32_t op2) {
if (cheats->incompletePatch) { if (cheats->incompletePatch) {
cheats->incompletePatch->newValue = op1; cheats->incompletePatch->value = op1;
cheats->incompletePatch = 0; cheats->incompletePatch = NULL;
return true; return true;
} }
if (cheats->incompleteCheat != COMPLETE) { if (cheats->incompleteCheat != COMPLETE) {