Add Cartridge Instances – allow multiple saves without multiple ROM copies
This commit is contained in:
parent
641f26e13e
commit
2c635c7a87
155
Cocoa/Document.m
155
Cocoa/Document.m
@ -14,6 +14,30 @@
|
||||
#import "GBObjectView.h"
|
||||
#import "GBPaletteView.h"
|
||||
|
||||
@implementation NSString (relativePath)
|
||||
|
||||
- (NSString *)pathRelativeToDirectory:(NSString *)directory
|
||||
{
|
||||
NSMutableArray<NSString *> *baseComponents = [[directory pathComponents] mutableCopy];
|
||||
NSMutableArray<NSString *> *selfComponents = [[self pathComponents] mutableCopy];
|
||||
|
||||
while (baseComponents.count) {
|
||||
if (![baseComponents.firstObject isEqualToString:selfComponents.firstObject]) {
|
||||
break;
|
||||
}
|
||||
|
||||
[baseComponents removeObjectAtIndex:0];
|
||||
[selfComponents removeObjectAtIndex:0];
|
||||
}
|
||||
while (baseComponents.count) {
|
||||
[baseComponents removeObjectAtIndex:0];
|
||||
[selfComponents insertObject:@".." atIndex:0];
|
||||
}
|
||||
return [selfComponents componentsJoinedByString:@"/"];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#define GB_MODEL_PAL_BIT_OLD 0x1000
|
||||
|
||||
/* Todo: The general Objective-C coding style conflicts with SameBoy's. This file needs a cleanup. */
|
||||
@ -499,8 +523,8 @@ static unsigned *multiplication_table_for_frequency(unsigned frequency)
|
||||
[_audioClient stop];
|
||||
_audioClient = nil;
|
||||
self.view.mouseHidingEnabled = false;
|
||||
GB_save_battery(&gb, [[[self.fileURL URLByDeletingPathExtension] URLByAppendingPathExtension:@"sav"].path UTF8String]);
|
||||
GB_save_cheats(&gb, [[[self.fileURL URLByDeletingPathExtension] URLByAppendingPathExtension:@"cht"].path UTF8String]);
|
||||
GB_save_battery(&gb, self.savPath.UTF8String);
|
||||
GB_save_cheats(&gb, self.chtPath.UTF8String);
|
||||
unsigned time_to_alarm = GB_time_to_alarm(&gb);
|
||||
|
||||
if (time_to_alarm) {
|
||||
@ -943,28 +967,107 @@ static unsigned *multiplication_table_for_frequency(unsigned frequency)
|
||||
}
|
||||
}
|
||||
|
||||
- (bool)isCartContainer
|
||||
{
|
||||
return [self.fileName.pathExtension.lowercaseString isEqualToString:@"gbcart"];
|
||||
}
|
||||
|
||||
- (NSString *)savPath
|
||||
{
|
||||
if (self.isCartContainer) {
|
||||
return [self.fileName stringByAppendingPathComponent:@"battery.sav"];
|
||||
}
|
||||
|
||||
return [[self.fileURL URLByDeletingPathExtension] URLByAppendingPathExtension:@"sav"].path;
|
||||
}
|
||||
|
||||
- (NSString *)chtPath
|
||||
{
|
||||
if (self.isCartContainer) {
|
||||
return [self.fileName stringByAppendingPathComponent:@"cheats.cht"];
|
||||
}
|
||||
|
||||
return [[self.fileURL URLByDeletingPathExtension] URLByAppendingPathExtension:@"cht"].path;
|
||||
}
|
||||
|
||||
- (NSString *)saveStatePath:(unsigned)index
|
||||
{
|
||||
if (self.isCartContainer) {
|
||||
return [self.fileName stringByAppendingPathComponent:[NSString stringWithFormat:@"state.s%u", index]];
|
||||
}
|
||||
return [[self.fileURL URLByDeletingPathExtension] URLByAppendingPathExtension:[NSString stringWithFormat:@"s%u", index]].path;
|
||||
}
|
||||
|
||||
- (NSString *)romPath
|
||||
{
|
||||
NSString *fileName = self.fileName;
|
||||
if (self.isCartContainer) {
|
||||
NSArray *paths = [[NSString stringWithContentsOfFile:[fileName stringByAppendingPathComponent:@"rom.gbl"]
|
||||
encoding:NSUTF8StringEncoding
|
||||
error:nil] componentsSeparatedByString:@"\n"];
|
||||
fileName = nil;
|
||||
bool needsRebuild = false;
|
||||
for (NSString *path in paths) {
|
||||
NSURL *url = [NSURL URLWithString:path relativeToURL:self.fileURL];
|
||||
if ([[NSFileManager defaultManager] fileExistsAtPath:url.path]) {
|
||||
if (fileName && ![fileName isEqualToString:url.path]) {
|
||||
needsRebuild = true;
|
||||
break;
|
||||
}
|
||||
fileName = url.path;
|
||||
}
|
||||
else {
|
||||
needsRebuild = true;
|
||||
}
|
||||
}
|
||||
if (fileName && needsRebuild) {
|
||||
[[NSString stringWithFormat:@"%@\n%@\n%@",
|
||||
[fileName pathRelativeToDirectory:self.fileName],
|
||||
fileName,
|
||||
[[NSURL fileURLWithPath:fileName].fileReferenceURL.absoluteString substringFromIndex:strlen("file://")]]
|
||||
writeToFile:[self.fileName stringByAppendingPathComponent:@"rom.gbl"]
|
||||
atomically:false
|
||||
encoding:NSUTF8StringEncoding
|
||||
error:nil];
|
||||
}
|
||||
}
|
||||
|
||||
return fileName;
|
||||
}
|
||||
|
||||
- (int) loadROM
|
||||
{
|
||||
__block int ret = 0;
|
||||
NSString *fileName = self.romPath;
|
||||
if (!fileName) {
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
[alert setMessageText:@"Could not locate the ROM referenced by this Game Boy Cartridge"];
|
||||
[alert setAlertStyle:NSAlertStyleCritical];
|
||||
[alert runModal];
|
||||
return 1;
|
||||
}
|
||||
|
||||
NSString *rom_warnings = [self captureOutputForBlock:^{
|
||||
GB_debugger_clear_symbols(&gb);
|
||||
if ([[[self.fileType pathExtension] lowercaseString] isEqualToString:@"isx"]) {
|
||||
ret = GB_load_isx(&gb, self.fileURL.path.UTF8String);
|
||||
if ([[[fileName pathExtension] lowercaseString] isEqualToString:@"isx"]) {
|
||||
ret = GB_load_isx(&gb, fileName.UTF8String);
|
||||
if (!self.isCartContainer) {
|
||||
GB_load_battery(&gb, [[self.fileURL URLByDeletingPathExtension] URLByAppendingPathExtension:@"ram"].path.UTF8String);
|
||||
}
|
||||
else if ([[[self.fileType pathExtension] lowercaseString] isEqualToString:@"gbs"]) {
|
||||
}
|
||||
else if ([[[fileName pathExtension] lowercaseString] isEqualToString:@"gbs"]) {
|
||||
__block GB_gbs_info_t info;
|
||||
ret = GB_load_gbs(&gb, self.fileURL.path.UTF8String, &info);
|
||||
ret = GB_load_gbs(&gb, fileName.UTF8String, &info);
|
||||
[self prepareGBSInterface:&info];
|
||||
}
|
||||
else {
|
||||
ret = GB_load_rom(&gb, [self.fileURL.path UTF8String]);
|
||||
ret = GB_load_rom(&gb, [fileName UTF8String]);
|
||||
}
|
||||
GB_load_battery(&gb, [[self.fileURL URLByDeletingPathExtension] URLByAppendingPathExtension:@"sav"].path.UTF8String);
|
||||
GB_load_cheats(&gb, [[self.fileURL URLByDeletingPathExtension] URLByAppendingPathExtension:@"cht"].path.UTF8String);
|
||||
GB_load_battery(&gb, self.savPath.UTF8String);
|
||||
GB_load_cheats(&gb, self.chtPath.UTF8String);
|
||||
[self.cheatWindowController cheatsUpdated];
|
||||
GB_debugger_load_symbol_file(&gb, [[[NSBundle mainBundle] pathForResource:@"registers" ofType:@"sym"] UTF8String]);
|
||||
GB_debugger_load_symbol_file(&gb, [[self.fileURL URLByDeletingPathExtension] URLByAppendingPathExtension:@"sym"].path.UTF8String);
|
||||
GB_debugger_load_symbol_file(&gb, [[fileName stringByDeletingPathExtension] stringByAppendingPathExtension:@"sym"].UTF8String);
|
||||
}];
|
||||
if (ret) {
|
||||
NSAlert *alert = [[NSAlert alloc] init];
|
||||
@ -1295,7 +1398,7 @@ static unsigned *multiplication_table_for_frequency(unsigned frequency)
|
||||
{
|
||||
bool __block success = false;
|
||||
[self performAtomicBlock:^{
|
||||
success = GB_save_state(&gb, [[self.fileURL URLByDeletingPathExtension] URLByAppendingPathExtension:[NSString stringWithFormat:@"s%ld", (long)[sender tag] ]].path.UTF8String) == 0;
|
||||
success = GB_save_state(&gb, [self saveStatePath:[sender tag]].UTF8String) == 0;
|
||||
}];
|
||||
|
||||
if (!success) {
|
||||
@ -1333,8 +1436,8 @@ static unsigned *multiplication_table_for_frequency(unsigned frequency)
|
||||
|
||||
- (IBAction)loadState:(id)sender
|
||||
{
|
||||
int ret = [self loadStateFile:[[self.fileURL URLByDeletingPathExtension] URLByAppendingPathExtension:[NSString stringWithFormat:@"s%ld", (long)[sender tag]]].path.UTF8String noErrorOnNotFound:true];
|
||||
if (ret == ENOENT) {
|
||||
int ret = [self loadStateFile:[self saveStatePath:[sender tag]].UTF8String noErrorOnNotFound:true];
|
||||
if (ret == ENOENT && !self.isCartContainer) {
|
||||
[self loadStateFile:[[self.fileURL URLByDeletingPathExtension] URLByAppendingPathExtension:[NSString stringWithFormat:@"sn%ld", (long)[sender tag]]].path.UTF8String noErrorOnNotFound:false];
|
||||
}
|
||||
}
|
||||
@ -2260,4 +2363,30 @@ static unsigned *multiplication_table_for_frequency(unsigned frequency)
|
||||
GB_set_object_rendering_disabled(&gb, !GB_is_object_rendering_disabled(&gb));
|
||||
}
|
||||
|
||||
- (IBAction)newCartridgeInstance:(id)sender
|
||||
{
|
||||
bool shouldResume = running;
|
||||
[self stop];
|
||||
NSSavePanel *savePanel = [NSSavePanel savePanel];
|
||||
[savePanel setAllowedFileTypes:@[@"gbcart"]];
|
||||
[savePanel beginSheetModalForWindow:self.mainWindow completionHandler:^(NSInteger result) {
|
||||
if (result == NSModalResponseOK) {
|
||||
[savePanel orderOut:self];
|
||||
NSString *romPath = self.romPath;
|
||||
[[NSFileManager defaultManager] trashItemAtURL:savePanel.URL resultingItemURL:nil error:nil];
|
||||
[[NSFileManager defaultManager] createDirectoryAtURL:savePanel.URL withIntermediateDirectories:false attributes:nil error:nil];
|
||||
[[NSString stringWithFormat:@"%@\n%@\n%@",
|
||||
[romPath pathRelativeToDirectory:savePanel.URL.path],
|
||||
romPath,
|
||||
[[NSURL fileURLWithPath:romPath].fileReferenceURL.absoluteString substringFromIndex:strlen("file://")]
|
||||
] writeToURL:[savePanel.URL URLByAppendingPathComponent:@"rom.gbl"] atomically:false encoding:NSUTF8StringEncoding error:nil];
|
||||
[[NSDocumentController sharedDocumentController] openDocumentWithContentsOfURL:savePanel.URL display:true completionHandler:nil];
|
||||
}
|
||||
if (shouldResume) {
|
||||
[self start];
|
||||
}
|
||||
}];
|
||||
}
|
||||
|
||||
|
||||
@end
|
||||
|
@ -88,6 +88,24 @@
|
||||
<key>NSDocumentClass</key>
|
||||
<string>Document</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>CFBundleTypeExtensions</key>
|
||||
<array>
|
||||
<string>gbcart</string>
|
||||
</array>
|
||||
<key>CFBundleTypeIconFile</key>
|
||||
<string>ColorCartridge</string>
|
||||
<key>CFBundleTypeName</key>
|
||||
<string>Game Boy Cartridge</string>
|
||||
<key>CFBundleTypeRole</key>
|
||||
<string>Viewer</string>
|
||||
<key>LSItemContentTypes</key>
|
||||
<array/>
|
||||
<key>LSTypeIsPackage</key>
|
||||
<integer>1</integer>
|
||||
<key>NSDocumentClass</key>
|
||||
<string>Document</string>
|
||||
</dict>
|
||||
</array>
|
||||
<key>CFBundleExecutable</key>
|
||||
<string>SameBoy</string>
|
||||
|
@ -91,6 +91,12 @@
|
||||
</menu>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="m54-Is-iLE"/>
|
||||
<menuItem title="New Cartridge Instance…" keyEquivalent="n" id="Vld-be-NZu">
|
||||
<connections>
|
||||
<action selector="newCartridgeInstance:" target="-1" id="GJc-xU-ZEr"/>
|
||||
</connections>
|
||||
</menuItem>
|
||||
<menuItem isSeparatorItem="YES" id="vQH-Yd-TH4"/>
|
||||
<menuItem title="Close" keyEquivalent="w" id="DVo-aG-piG">
|
||||
<connections>
|
||||
<action selector="performClose:" target="-1" id="HmO-Ls-i7Q"/>
|
||||
|
Loading…
Reference in New Issue
Block a user