Dump and load cheats

This commit is contained in:
Lior Halphon 2020-04-11 19:15:40 +03:00
parent 5df45417fa
commit 0abd3b2c46
5 changed files with 88 additions and 1 deletions

View File

@ -3,6 +3,8 @@
#include "GBImageView.h" #include "GBImageView.h"
#include "GBSplitView.h" #include "GBSplitView.h"
@class GBCheatWindowController;
@interface Document : NSDocument <NSWindowDelegate, GBImageViewDelegate, NSTableViewDataSource, NSTableViewDelegate, NSSplitViewDelegate> @interface Document : NSDocument <NSWindowDelegate, GBImageViewDelegate, NSTableViewDataSource, NSTableViewDelegate, NSSplitViewDelegate>
@property (strong) IBOutlet GBView *view; @property (strong) IBOutlet GBView *view;
@property (strong) IBOutlet NSTextView *consoleOutput; @property (strong) IBOutlet NSTextView *consoleOutput;
@ -34,6 +36,7 @@
@property (strong) IBOutlet GBSplitView *debuggerSplitView; @property (strong) IBOutlet GBSplitView *debuggerSplitView;
@property (strong) IBOutlet NSBox *debuggerVerticalLine; @property (strong) IBOutlet NSBox *debuggerVerticalLine;
@property (strong) IBOutlet NSPanel *cheatsWindow; @property (strong) IBOutlet NSPanel *cheatsWindow;
@property (strong) IBOutlet GBCheatWindowController *cheatWindowController;
-(uint8_t) readMemory:(uint16_t) addr; -(uint8_t) readMemory:(uint16_t) addr;
-(void) writeMemory:(uint16_t) addr value:(uint8_t)value; -(void) writeMemory:(uint16_t) addr value:(uint8_t)value;

View File

@ -7,6 +7,7 @@
#include "HexFiend/HexFiend.h" #include "HexFiend/HexFiend.h"
#include "GBMemoryByteArray.h" #include "GBMemoryByteArray.h"
#include "GBWarningPopover.h" #include "GBWarningPopover.h"
#include "GBCheatWindowController.h"
/* Todo: The general Objective-C coding style conflicts with SameBoy's. This file needs a cleanup. */ /* Todo: The general Objective-C coding style conflicts with SameBoy's. This file needs a cleanup. */
/* Todo: Split into category files! This is so messy!!! */ /* Todo: Split into category files! This is so messy!!! */
@ -359,6 +360,7 @@ static void audioCallback(GB_gameboy_t *gb, GB_sample_t *sample)
self.audioClient = nil; self.audioClient = nil;
self.view.mouseHidingEnabled = NO; self.view.mouseHidingEnabled = NO;
GB_save_battery(&gb, [[[self.fileName stringByDeletingPathExtension] stringByAppendingPathExtension:@"sav"] UTF8String]); GB_save_battery(&gb, [[[self.fileName stringByDeletingPathExtension] stringByAppendingPathExtension:@"sav"] UTF8String]);
GB_save_cheats(&gb, [[[self.fileName stringByDeletingPathExtension] stringByAppendingPathExtension:@"cht"] UTF8String]);
stopping = false; stopping = false;
} }
@ -643,6 +645,8 @@ static void audioCallback(GB_gameboy_t *gb, GB_sample_t *sample)
NSString *rom_warnings = [self captureOutputForBlock:^{ NSString *rom_warnings = [self captureOutputForBlock:^{
GB_load_rom(&gb, [self.fileName UTF8String]); GB_load_rom(&gb, [self.fileName UTF8String]);
GB_load_battery(&gb, [[[self.fileName stringByDeletingPathExtension] stringByAppendingPathExtension:@"sav"] UTF8String]); GB_load_battery(&gb, [[[self.fileName stringByDeletingPathExtension] stringByAppendingPathExtension:@"sav"] UTF8String]);
GB_load_cheats(&gb, [[[self.fileName stringByDeletingPathExtension] stringByAppendingPathExtension:@"cht"] UTF8String]);
[self.cheatWindowController.cheatsTable reloadData];
GB_debugger_clear_symbols(&gb); GB_debugger_clear_symbols(&gb);
GB_debugger_load_symbol_file(&gb, [[[NSBundle mainBundle] pathForResource:@"registers" ofType:@"sym"] UTF8String]); GB_debugger_load_symbol_file(&gb, [[[NSBundle mainBundle] pathForResource:@"registers" ofType:@"sym"] UTF8String]);
GB_debugger_load_symbol_file(&gb, [[[self.fileName stringByDeletingPathExtension] stringByAppendingPathExtension:@"sym"] UTF8String]); GB_debugger_load_symbol_file(&gb, [[[self.fileName stringByDeletingPathExtension] stringByAppendingPathExtension:@"sym"] UTF8String]);

View File

@ -9,6 +9,8 @@
<customObject id="-2" userLabel="File's Owner" customClass="Document"> <customObject id="-2" userLabel="File's Owner" customClass="Document">
<connections> <connections>
<outlet property="TilemapSetButton" destination="k4c-Vg-MBu" id="Ak1-6d-B1N"/> <outlet property="TilemapSetButton" destination="k4c-Vg-MBu" id="Ak1-6d-B1N"/>
<outlet property="cheatController" destination="v7q-gT-jHT" id="yg2-23-kOX"/>
<outlet property="cheatWindowController" destination="v7q-gT-jHT" id="UNn-g4-2kP"/>
<outlet property="cheatsWindow" destination="4Yb-Np-JrF" id="YCZ-cj-gn5"/> <outlet property="cheatsWindow" destination="4Yb-Np-JrF" id="YCZ-cj-gn5"/>
<outlet property="consoleInput" destination="l22-S8-uji" id="Heu-am-YgB"/> <outlet property="consoleInput" destination="l22-S8-uji" id="Heu-am-YgB"/>
<outlet property="consoleOutput" destination="doS-dM-hnl" id="Gn5-ju-Wb0"/> <outlet property="consoleOutput" destination="doS-dM-hnl" id="Gn5-ju-Wb0"/>
@ -1056,7 +1058,7 @@
<customObject id="v7q-gT-jHT" customClass="GBCheatWindowController"> <customObject id="v7q-gT-jHT" customClass="GBCheatWindowController">
<connections> <connections>
<outlet property="addressField" destination="qHx-1z-daR" id="FWo-4u-Qse"/> <outlet property="addressField" destination="qHx-1z-daR" id="FWo-4u-Qse"/>
<outlet property="cheatsTable" destination="tA3-8T-bxb" id="n7v-rn-TOg"/> <outlet property="cheatsTable" destination="tA3-8T-bxb" id="Z2r-AQ-5th"/>
<outlet property="descriptionField" destination="C6E-oI-hDC" id="tc0-gI-FBa"/> <outlet property="descriptionField" destination="C6E-oI-hDC" id="tc0-gI-FBa"/>
<outlet property="document" destination="-2" id="5NX-N4-5Rt"/> <outlet property="document" destination="-2" id="5NX-N4-5Rt"/>
<outlet property="importCodeField" destination="X7K-nJ-alF" id="ni0-zH-XDU"/> <outlet property="importCodeField" destination="X7K-nJ-alF" id="ni0-zH-XDU"/>

View File

@ -2,6 +2,7 @@
#include "cheats.h" #include "cheats.h"
#include <stdio.h> #include <stdio.h>
#include <assert.h> #include <assert.h>
#include <errno.h>
static inline uint8_t hash_addr(uint16_t addr) static inline uint8_t hash_addr(uint16_t addr)
{ {
@ -238,3 +239,78 @@ void GB_update_cheat(GB_gameboy_t *gb, const GB_cheat_t *_cheat, const char *des
cheat->description[sizeof(cheat->description) - 1] = 0; cheat->description[sizeof(cheat->description) - 1] = 0;
} }
} }
#define CHEAT_MAGIC 'SBCh'
void GB_load_cheats(GB_gameboy_t *gb, const char *path)
{
FILE *f = fopen(path, "rb");
if (!f) {
return;
}
uint32_t magic = 0;
uint32_t struct_size = 0;
fread(&magic, sizeof(magic), 1, f);
fread(&struct_size, sizeof(struct_size), 1, f);
if (magic != CHEAT_MAGIC && magic != __builtin_bswap32(CHEAT_MAGIC)) {
GB_log(gb, "The file is not a SameBoy cheat database");
return;
}
if (struct_size != sizeof(GB_cheat_t)) {
GB_log(gb, "This cheat database is not compatible with this version of SameBoy");
return;
}
// Remove all cheats first
while (gb->cheats) {
GB_remove_cheat(gb, gb->cheats[0]);
}
GB_cheat_t cheat;
while (fread(&cheat, sizeof(cheat), 1, f)) {
if (magic == __builtin_bswap32(CHEAT_MAGIC)) {
cheat.address = __builtin_bswap16(cheat.address);
cheat.bank = __builtin_bswap16(cheat.bank);
}
cheat.description[sizeof(cheat.description) - 1] = 0;
GB_add_cheat(gb, cheat.description, cheat.address, cheat.bank, cheat.value, cheat.old_value, cheat.use_old_value, cheat.enabled);
}
return;
}
int GB_save_cheats(GB_gameboy_t *gb, const char *path)
{
if (!gb->cheat_count) return 0; // Nothing to save.
FILE *f = fopen(path, "wb");
if (!f) {
GB_log(gb, "Could not dump cheat database: %s.\n", strerror(errno));
return errno;
}
uint32_t magic = CHEAT_MAGIC;
uint32_t struct_size = sizeof(GB_cheat_t);
if (fwrite(&magic, sizeof(magic), 1, f) != 1) {
fclose(f);
return EIO;
}
if (fwrite(&struct_size, sizeof(struct_size), 1, f) != 1) {
fclose(f);
return EIO;
}
for (size_t i = 0; i <gb->cheat_count; i++) {
if (fwrite(gb->cheats[i], sizeof(*gb->cheats[i]), 1, f) != 1) {
fclose(f);
return EIO;
}
}
errno = 0;
fclose(f);
return errno;
}

View File

@ -13,6 +13,8 @@ const GB_cheat_t *const *GB_get_cheats(GB_gameboy_t *gb, size_t *size);
void GB_remove_cheat(GB_gameboy_t *gb, const GB_cheat_t *cheat); void GB_remove_cheat(GB_gameboy_t *gb, const GB_cheat_t *cheat);
bool GB_cheats_enabled(GB_gameboy_t *gb); bool GB_cheats_enabled(GB_gameboy_t *gb);
void GB_set_cheats_enabled(GB_gameboy_t *gb, bool enabled); void GB_set_cheats_enabled(GB_gameboy_t *gb, bool enabled);
void GB_load_cheats(GB_gameboy_t *gb, const char *path);
int GB_save_cheats(GB_gameboy_t *gb, const char *path);
#ifdef GB_INTERNAL #ifdef GB_INTERNAL
void GB_apply_cheat(GB_gameboy_t *gb, uint16_t address, uint8_t *value); void GB_apply_cheat(GB_gameboy_t *gb, uint16_t address, uint8_t *value);