mirror of https://github.com/mgba-emu/mgba.git
Core: Improve support for ROM patch cheats, supporting disabling overlapping patches
This commit is contained in:
parent
a59ffbc9a6
commit
5781566717
1
CHANGES
1
CHANGES
|
@ -92,6 +92,7 @@ Misc:
|
|||
- Core: Add savedataUpdated callback
|
||||
- Core: Add shutdown callback
|
||||
- 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: Add support for sleep and shutdown callbacks
|
||||
- GB I/O: Implement preliminary support for PCM12/PCM34 (closes mgba.io/i/1468)
|
||||
|
|
|
@ -12,6 +12,7 @@ CXX_GUARD_START
|
|||
|
||||
#include <mgba/core/cpu.h>
|
||||
#include <mgba/core/log.h>
|
||||
#include <mgba-util/table.h>
|
||||
#include <mgba-util/vector.h>
|
||||
|
||||
enum mCheatType {
|
||||
|
@ -44,9 +45,20 @@ struct mCheat {
|
|||
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);
|
||||
|
||||
DECLARE_VECTOR(mCheatList, struct mCheat);
|
||||
DECLARE_VECTOR(mCheatPatchList, struct mCheatPatch);
|
||||
|
||||
struct mCheatDevice;
|
||||
struct mCheatSet {
|
||||
|
@ -66,6 +78,7 @@ struct mCheatSet {
|
|||
|
||||
char* name;
|
||||
bool enabled;
|
||||
struct mCheatPatchList romPatches;
|
||||
struct StringList lines;
|
||||
};
|
||||
|
||||
|
@ -78,6 +91,7 @@ struct mCheatDevice {
|
|||
struct mCheatSet* (*createSet)(struct mCheatDevice*, const char* name);
|
||||
|
||||
struct mCheatSets cheats;
|
||||
struct Table unpatchedMemory;
|
||||
bool autosave;
|
||||
bool buttonDown;
|
||||
};
|
||||
|
|
|
@ -11,7 +11,6 @@
|
|||
CXX_GUARD_START
|
||||
|
||||
#include <mgba/core/cheats.h>
|
||||
#include <mgba-util/vector.h>
|
||||
|
||||
enum GBCheatType {
|
||||
GB_CHEAT_AUTODETECT,
|
||||
|
@ -20,22 +19,6 @@ enum GBCheatType {
|
|||
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);
|
||||
|
||||
CXX_GUARD_END
|
||||
|
|
|
@ -134,23 +134,14 @@ struct GBACheatHook {
|
|||
size_t reentries;
|
||||
};
|
||||
|
||||
struct GBACheatPatch {
|
||||
uint32_t address;
|
||||
int16_t newValue;
|
||||
int16_t oldValue;
|
||||
bool applied;
|
||||
};
|
||||
|
||||
DECLARE_VECTOR(GBACheatPatchList, struct GBACheatPatch);
|
||||
|
||||
struct GBACheatSet {
|
||||
struct mCheatSet d;
|
||||
struct GBACheatHook* hook;
|
||||
|
||||
struct GBACheatPatchList romPatches;
|
||||
|
||||
size_t incompleteCheat;
|
||||
struct GBACheatPatch* incompletePatch;
|
||||
struct mCheatPatch* incompletePatch;
|
||||
size_t currentBlock;
|
||||
|
||||
int gsaVersion;
|
||||
|
|
|
@ -18,6 +18,33 @@ mLOG_DEFINE_CATEGORY(CHEATS, "Cheats", "core.cheats");
|
|||
|
||||
DEFINE_VECTOR(mCheatList, struct mCheat);
|
||||
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) {
|
||||
switch (width) {
|
||||
|
@ -31,6 +58,18 @@ static int32_t _readMem(struct mCore* core, uint32_t address, int width) {
|
|||
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) {
|
||||
switch (width) {
|
||||
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 mCheatDeviceDeinit(struct mCPUComponent*);
|
||||
|
||||
|
@ -55,11 +171,13 @@ void mCheatDeviceCreate(struct mCheatDevice* device) {
|
|||
device->autosave = false;
|
||||
device->buttonDown = false;
|
||||
mCheatSetsInit(&device->cheats, 4);
|
||||
TableInit(&device->unpatchedMemory, 4, free);
|
||||
}
|
||||
|
||||
void mCheatDeviceDestroy(struct mCheatDevice* device) {
|
||||
mCheatDeviceClear(device);
|
||||
mCheatSetsDeinit(&device->cheats);
|
||||
TableDeinit(&device->unpatchedMemory);
|
||||
free(device);
|
||||
}
|
||||
|
||||
|
@ -75,6 +193,7 @@ void mCheatDeviceClear(struct mCheatDevice* device) {
|
|||
void mCheatSetInit(struct mCheatSet* set, const char* name) {
|
||||
mCheatListInit(&set->list, 4);
|
||||
StringListInit(&set->lines, 4);
|
||||
mCheatPatchListInit(&set->romPatches, 4);
|
||||
if (name) {
|
||||
set->name = strdup(name);
|
||||
} else {
|
||||
|
@ -93,7 +212,10 @@ void mCheatSetDeinit(struct mCheatSet* set) {
|
|||
free(set->name);
|
||||
}
|
||||
StringListDeinit(&set->lines);
|
||||
set->deinit(set);
|
||||
mCheatPatchListDeinit(&set->romPatches);
|
||||
if (set->deinit) {
|
||||
set->deinit(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) {
|
||||
*mCheatSetsAppend(&device->cheats) = cheats;
|
||||
cheats->add(cheats, device);
|
||||
if (cheats->add) {
|
||||
cheats->add(cheats, device);
|
||||
}
|
||||
}
|
||||
|
||||
void mCheatRemoveSet(struct mCheatDevice* device, struct mCheatSet* cheats) {
|
||||
|
@ -131,7 +255,9 @@ void mCheatRemoveSet(struct mCheatDevice* device, struct mCheatSet* cheats) {
|
|||
return;
|
||||
}
|
||||
mCheatSetsShift(&device->cheats, i, 1);
|
||||
cheats->remove(cheats, device);
|
||||
if (cheats->remove) {
|
||||
cheats->remove(cheats, device);
|
||||
}
|
||||
}
|
||||
|
||||
bool mCheatParseFile(struct mCheatDevice* device, struct VFile* vf) {
|
||||
|
@ -503,8 +629,14 @@ void mCheatAutosave(struct mCheatDevice* device) {
|
|||
#endif
|
||||
|
||||
void mCheatRefresh(struct mCheatDevice* device, struct mCheatSet* cheats) {
|
||||
cheats->refresh(cheats, device);
|
||||
if (cheats->enabled) {
|
||||
_patchROM(device, cheats);
|
||||
}
|
||||
if (cheats->refresh) {
|
||||
cheats->refresh(cheats, device);
|
||||
}
|
||||
if (!cheats->enabled) {
|
||||
_unpatchROM(device, cheats);
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
129
src/gb/cheats.c
129
src/gb/cheats.c
|
@ -10,58 +10,6 @@
|
|||
#include <mgba/internal/gb/memory.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 GBCheatParseDirectives(struct mCheatSet* set, const 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) {
|
||||
UNUSED(device);
|
||||
struct GBCheatSet* set = malloc(sizeof(*set));
|
||||
mCheatSetInit(&set->d, name);
|
||||
struct mCheatSet* set = malloc(sizeof(*set));
|
||||
mCheatSetInit(set, name);
|
||||
|
||||
GBCheatPatchListInit(&set->romPatches, 0);
|
||||
set->deinit = NULL;
|
||||
set->add = NULL;
|
||||
set->remove = NULL;
|
||||
|
||||
set->d.deinit = GBCheatSetDeinit;
|
||||
set->d.add = GBCheatAddSet;
|
||||
set->d.remove = GBCheatRemoveSet;
|
||||
set->addLine = GBCheatAddLine;
|
||||
set->copyProperties = GBCheatSetCopyProperties;
|
||||
|
||||
set->d.addLine = GBCheatAddLine;
|
||||
set->d.copyProperties = GBCheatSetCopyProperties;
|
||||
set->parseDirectives = GBCheatParseDirectives;
|
||||
set->dumpDirectives = GBCheatDumpDirectives;
|
||||
|
||||
set->d.parseDirectives = GBCheatParseDirectives;
|
||||
set->d.dumpDirectives = GBCheatDumpDirectives;
|
||||
|
||||
set->d.refresh = GBCheatRefresh;
|
||||
return &set->d;
|
||||
set->refresh = NULL;
|
||||
return set;
|
||||
}
|
||||
|
||||
struct mCheatDevice* GBCheatDeviceCreate(void) {
|
||||
|
@ -95,23 +41,8 @@ struct mCheatDevice* GBCheatDeviceCreate(void) {
|
|||
return device;
|
||||
}
|
||||
|
||||
static void GBCheatSetDeinit(struct mCheatSet* set) {
|
||||
struct GBCheatSet* gbset = (struct GBCheatSet*) set;
|
||||
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);
|
||||
static bool GBCheatAddCodebreaker(struct mCheatSet* cheats, uint16_t address, uint8_t data) {
|
||||
struct mCheat* cheat = mCheatListAppend(&cheats->list);
|
||||
cheat->type = CHEAT_ASSIGN;
|
||||
cheat->width = 1;
|
||||
cheat->address = address;
|
||||
|
@ -121,11 +52,11 @@ static bool GBCheatAddCodebreaker(struct GBCheatSet* cheats, uint16_t address, u
|
|||
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);
|
||||
}
|
||||
|
||||
static bool GBCheatAddGameSharkLine(struct GBCheatSet* cheats, const char* line) {
|
||||
static bool GBCheatAddGameSharkLine(struct mCheatSet* cheats, const char* line) {
|
||||
uint32_t op;
|
||||
if (!hex32(line, &op)) {
|
||||
return false;
|
||||
|
@ -133,7 +64,7 @@ static bool GBCheatAddGameSharkLine(struct GBCheatSet* cheats, const char* line)
|
|||
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 op2;
|
||||
uint16_t op3 = 0x1000;
|
||||
|
@ -156,24 +87,26 @@ static bool GBCheatAddGameGenieLine(struct GBCheatSet* cheats, const char* line)
|
|||
uint16_t address = (op1 & 0xF) << 8;
|
||||
address |= (op2 >> 4) & 0xFF;
|
||||
address |= ((op2 & 0xF) ^ 0xF) << 12;
|
||||
struct GBCheatPatch* patch = GBCheatPatchListAppend(&cheats->romPatches);
|
||||
struct mCheatPatch* patch = mCheatPatchListAppend(&cheats->romPatches);
|
||||
patch->address = address;
|
||||
patch->newValue = op1 >> 4;
|
||||
patch->value = op1 >> 4;
|
||||
patch->applied = false;
|
||||
patch->width = 1;
|
||||
patch->segment = -1;
|
||||
if (op3 < 0x1000) {
|
||||
uint32_t value = ((op3 & 0xF00) << 20) | (op3 & 0xF);
|
||||
value = ROR(value, 2);
|
||||
value |= value >> 24;
|
||||
value ^= 0xBA;
|
||||
patch->oldValue = value;
|
||||
patch->checkByte = true;
|
||||
patch->checkValue = value;
|
||||
patch->check = true;
|
||||
} else {
|
||||
patch->checkByte = false;
|
||||
patch->check = false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool GBCheatAddVBALine(struct GBCheatSet* cheats, const char* line) {
|
||||
static bool GBCheatAddVBALine(struct mCheatSet* cheats, const char* line) {
|
||||
uint16_t address;
|
||||
uint8_t value;
|
||||
const char* lineNext = hex16(line, &address);
|
||||
|
@ -183,7 +116,7 @@ static bool GBCheatAddVBALine(struct GBCheatSet* cheats, const char* line) {
|
|||
if (!hex8(line, &value)) {
|
||||
return false;
|
||||
}
|
||||
struct mCheat* cheat = mCheatListAppend(&cheats->d.list);
|
||||
struct mCheat* cheat = mCheatListAppend(&cheats->list);
|
||||
cheat->type = CHEAT_ASSIGN;
|
||||
cheat->width = 1;
|
||||
cheat->address = address;
|
||||
|
@ -193,8 +126,7 @@ static bool GBCheatAddVBALine(struct GBCheatSet* cheats, const char* line) {
|
|||
return true;
|
||||
}
|
||||
|
||||
bool GBCheatAddLine(struct mCheatSet* set, const char* line, int type) {
|
||||
struct GBCheatSet* cheats = (struct GBCheatSet*) set;
|
||||
bool GBCheatAddLine(struct mCheatSet* cheats, const char* line, int type) {
|
||||
switch (type) {
|
||||
case GB_CHEAT_AUTODETECT:
|
||||
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) {
|
||||
UNUSED(set);
|
||||
UNUSED(oldSet);
|
||||
|
|
|
@ -13,8 +13,6 @@
|
|||
|
||||
#define MAX_LINE_LENGTH 128
|
||||
|
||||
DEFINE_VECTOR(GBACheatPatchList, struct GBACheatPatch);
|
||||
|
||||
static void _addBreakpoint(struct mCheatDevice* device, struct GBACheatSet* cheats) {
|
||||
if (!device->p || !cheats->hook) {
|
||||
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);
|
||||
}
|
||||
|
||||
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 GBACheatAddSet(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;
|
||||
|
||||
GBACheatPatchListInit(&set->romPatches, 4);
|
||||
return &set->d;
|
||||
}
|
||||
|
||||
|
@ -120,18 +87,15 @@ static void GBACheatSetDeinit(struct mCheatSet* set) {
|
|||
free(gbaset->hook);
|
||||
}
|
||||
}
|
||||
GBACheatPatchListDeinit(&gbaset->romPatches);
|
||||
}
|
||||
|
||||
static void GBACheatAddSet(struct mCheatSet* cheats, struct mCheatDevice* device) {
|
||||
struct GBACheatSet* gbaset = (struct GBACheatSet*) cheats;
|
||||
_addBreakpoint(device, gbaset);
|
||||
_patchROM(device, gbaset);
|
||||
}
|
||||
|
||||
static void GBACheatRemoveSet(struct mCheatSet* cheats, struct mCheatDevice* device) {
|
||||
struct GBACheatSet* gbaset = (struct GBACheatSet*) cheats;
|
||||
_unpatchROM(device, gbaset);
|
||||
_removeBreakpoint(device, gbaset);
|
||||
}
|
||||
|
||||
|
@ -276,13 +240,8 @@ bool GBACheatAddLine(struct mCheatSet* set, const char* line, int type) {
|
|||
|
||||
static void GBACheatRefresh(struct mCheatSet* cheats, struct mCheatDevice* device) {
|
||||
struct GBACheatSet* gbaset = (struct GBACheatSet*) cheats;
|
||||
if (cheats->enabled) {
|
||||
_patchROM(device, gbaset);
|
||||
if (gbaset->hook && !gbaset->hook->reentries) {
|
||||
_addBreakpoint(device, gbaset);
|
||||
}
|
||||
} else {
|
||||
_unpatchROM(device, gbaset);
|
||||
if (cheats->enabled && gbaset->hook && !gbaset->hook->reentries) {
|
||||
_addBreakpoint(device, gbaset);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -93,7 +93,7 @@ void GBACheatSetGameSharkVersion(struct GBACheatSet* cheats, enum GBACheatGameSh
|
|||
bool GBACheatAddGameSharkRaw(struct GBACheatSet* cheats, uint32_t op1, uint32_t op2) {
|
||||
enum GBAGameSharkType type = op1 >> 28;
|
||||
struct mCheat* cheat = 0;
|
||||
struct GBACheatPatch* romPatch;
|
||||
struct mCheatPatch* romPatch;
|
||||
|
||||
if (cheats->incompleteCheat != COMPLETE) {
|
||||
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);
|
||||
break;
|
||||
case GSA_PATCH:
|
||||
romPatch = GBACheatPatchListAppend(&cheats->romPatches);
|
||||
romPatch = mCheatPatchListAppend(&cheats->d.romPatches);
|
||||
romPatch->address = BASE_CART0 | ((op1 & 0xFFFFFF) << 1);
|
||||
romPatch->newValue = op2;
|
||||
romPatch->value = op2;
|
||||
romPatch->applied = false;
|
||||
romPatch->width = 2;
|
||||
romPatch->check = false;
|
||||
return true;
|
||||
case GSA_BUTTON:
|
||||
switch (op1 & 0x00F00000) {
|
||||
|
|
|
@ -230,9 +230,11 @@ static bool _addPAR3Special(struct GBACheatSet* cheats, uint32_t op2) {
|
|||
break;
|
||||
}
|
||||
if (romPatch >= 0) {
|
||||
struct GBACheatPatch* patch = GBACheatPatchListAppend(&cheats->romPatches);
|
||||
struct mCheatPatch* patch = mCheatPatchListAppend(&cheats->d.romPatches);
|
||||
patch->address = BASE_CART0 | ((op2 & 0xFFFFFF) << 1);
|
||||
patch->applied = false;
|
||||
patch->check = false;
|
||||
patch->width = 2;
|
||||
cheats->incompletePatch = patch;
|
||||
}
|
||||
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) {
|
||||
if (cheats->incompletePatch) {
|
||||
cheats->incompletePatch->newValue = op1;
|
||||
cheats->incompletePatch = 0;
|
||||
cheats->incompletePatch->value = op1;
|
||||
cheats->incompletePatch = NULL;
|
||||
return true;
|
||||
}
|
||||
if (cheats->incompleteCheat != COMPLETE) {
|
||||
|
|
Loading…
Reference in New Issue