Dump and load cheats
This commit is contained in:
parent
5df45417fa
commit
0abd3b2c46
@ -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;
|
||||||
|
@ -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]);
|
||||||
|
@ -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"/>
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
|
@ -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);
|
||||||
|
Loading…
Reference in New Issue
Block a user