diff --git a/Delta.xcodeproj/project.pbxproj b/Delta.xcodeproj/project.pbxproj index dbcbb81..2ba383d 100644 --- a/Delta.xcodeproj/project.pbxproj +++ b/Delta.xcodeproj/project.pbxproj @@ -125,6 +125,7 @@ BFCEA67E1D56FF640061A534 /* UIViewControllerContextTransitioning+Conveniences.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFCEA67D1D56FF640061A534 /* UIViewControllerContextTransitioning+Conveniences.swift */; }; BFD097211D3A01B8005A44C2 /* SaveStatesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF3540041C5DA70400C1184C /* SaveStatesViewController.swift */; }; BFD1EF402336BD8800D197CF /* UIDevice+Processor.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFD1EF3F2336BD8800D197CF /* UIDevice+Processor.swift */; }; + BFDB0FEC24464758001C727C /* DS.png in Resources */ = {isa = PBXBuildFile; fileRef = BFDB0FEB24464757001C727C /* DS.png */; }; BFDB3418219E4B1700595A62 /* SyncStatusViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFDB3417219E4B1700595A62 /* SyncStatusViewController.swift */; }; BFDCA1E6244EBAA900B8FBDB /* liblibDeSmuME.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BFDCA1E5244EBAA900B8FBDB /* liblibDeSmuME.a */; }; BFDD04F11D5E2C27002D450E /* GameCollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFDD04F01D5E2C27002D450E /* GameCollectionViewController.swift */; }; @@ -281,6 +282,7 @@ BFC9B7381CEFCD34008629BB /* CheatsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CheatsViewController.swift; sourceTree = ""; }; BFCEA67D1D56FF640061A534 /* UIViewControllerContextTransitioning+Conveniences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIViewControllerContextTransitioning+Conveniences.swift"; sourceTree = ""; }; BFD1EF3F2336BD8800D197CF /* UIDevice+Processor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIDevice+Processor.swift"; sourceTree = ""; }; + BFDB0FEB24464757001C727C /* DS.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = DS.png; sourceTree = ""; }; BFDB3417219E4B1700595A62 /* SyncStatusViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SyncStatusViewController.swift; sourceTree = ""; }; BFDCA1E5244EBAA900B8FBDB /* liblibDeSmuME.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = liblibDeSmuME.a; sourceTree = BUILT_PRODUCTS_DIR; }; BFDD04F01D5E2C27002D450E /* GameCollectionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GameCollectionViewController.swift; sourceTree = ""; }; @@ -721,6 +723,7 @@ isa = PBXGroup; children = ( BF6BB2451BB73FE800CCF94A /* Assets.xcassets */, + BFDB0FEB24464757001C727C /* DS.png */, BF02D5D91DDEBB3000A5E131 /* openvgdb.sqlite */, ); path = Resources; @@ -920,6 +923,7 @@ BF6BF3211EB82362008E83CD /* GamesDatabase.storyboard in Resources */, BFAB9F88219A4B670080EC7D /* GoogleService-Info.plist in Resources */, BF3540001C5DA3C500C1184C /* PausePresentationControllerContentView.xib in Resources */, + BFDB0FEC24464758001C727C /* DS.png in Resources */, BF5E7F461B9A652600AE44F8 /* Settings.storyboard in Resources */, BF02D5DA1DDEBB3000A5E131 /* openvgdb.sqlite in Resources */, BF71CF8A1FE904B1001F1613 /* GameTableViewCell.xib in Resources */, diff --git a/Delta/Database/DatabaseManager.swift b/Delta/Database/DatabaseManager.swift index e79c49d..1358e29 100644 --- a/Delta/Database/DatabaseManager.swift +++ b/Delta/Database/DatabaseManager.swift @@ -14,6 +14,7 @@ import DeltaCore import Harmony import Roxas import ZIPFoundation +import MelonDSDeltaCore extension DatabaseManager { @@ -74,6 +75,66 @@ extension DatabaseManager } } } + + func prepare(_ core: DeltaCoreProtocol, in context: NSManagedObjectContext) + { + guard let system = System(gameType: core.gameType) else { return } + + if let skin = ControllerSkin(system: system, context: context) + { + print("Updated default skin (\(skin.identifier)) for system:", system) + } + else + { + print("Failed to update default skin for system:", system) + } + + switch system + { + case .ds where core == MelonDS.core: + let predicate = NSPredicate(format: "%K == %@", #keyPath(Game.identifier), Game.melonDSBIOSIdentifier) + if let _ = Game.instancesWithPredicate(predicate, inManagedObjectContext: context, type: Game.self).first + { + // Game already exists, so don't do anything. + break + } + + let game = Game(context: context) + game.identifier = Game.melonDSBIOSIdentifier + game.type = .ds + game.filename = "melonDS-BIOS" + + game.name = NSLocalizedString("Home Screen", comment: "") + + if let sourceURL = Bundle.main.url(forResource: "DS", withExtension: "png") + { + do + { + let destinationURL = DatabaseManager.artworkURL(for: game) + try FileManager.default.copyItem(at: sourceURL, to: destinationURL, shouldReplace: true) + game.artworkURL = destinationURL + } + catch + { + print("Failed to copy default DS home screen artwork.", error) + } + } + + let gameCollection = GameCollection(context: context) + gameCollection.identifier = GameType.ds.rawValue + gameCollection.index = Int16(System.ds.year) + gameCollection.games.insert(game) + + case .ds: + let predicate = NSPredicate(format: "%K == %@", #keyPath(Game.identifier), Game.melonDSBIOSIdentifier) + if let game = Game.instancesWithPredicate(predicate, inManagedObjectContext: context, type: Game.self).first + { + context.delete(game) + } + + default: break + } + } } //MARK: - Update - @@ -113,13 +174,7 @@ private extension DatabaseManager for system in System.allCases { - guard let deltaControllerSkin = DeltaCore.ControllerSkin.standardControllerSkin(for: system.gameType) else { continue } - - let controllerSkin = ControllerSkin(context: context) - controllerSkin.isStandard = true - controllerSkin.filename = deltaControllerSkin.fileURL.lastPathComponent - - controllerSkin.configure(with: deltaControllerSkin) + self.prepare(system.deltaCore, in: context) } do diff --git a/Delta/Database/Model/Human/Game.swift b/Delta/Database/Model/Human/Game.swift index 77c4017..8dcc86a 100644 --- a/Delta/Database/Model/Human/Game.swift +++ b/Delta/Database/Model/Human/Game.swift @@ -11,6 +11,11 @@ import Foundation import DeltaCore import Harmony +public extension Game +{ + static let melonDSBIOSIdentifier = "com.rileytestut.MelonDSDeltaCore.BIOS" +} + @objc(Game) public class Game: _Game, GameProtocol { @@ -151,4 +156,8 @@ extension Game: Syncable public var syncableLocalizedName: String? { return self.name } + + public var isSyncingEnabled: Bool { + return self.identifier != Game.melonDSBIOSIdentifier + } } diff --git a/Delta/Database/Model/Human/GameSave.swift b/Delta/Database/Model/Human/GameSave.swift index da86b8b..caa122b 100644 --- a/Delta/Database/Model/Human/GameSave.swift +++ b/Delta/Database/Model/Human/GameSave.swift @@ -57,4 +57,11 @@ extension GameSave: Syncable public var syncableLocalizedName: String? { return self.game?.name } + + public var isSyncingEnabled: Bool { + // self.game may be nil if being downloaded, so don't enforce it. + // guard let identifier = self.game?.identifier else { return false } + + return self.game?.identifier != Game.melonDSBIOSIdentifier + } } diff --git a/Delta/Database/Model/Human/SaveState.swift b/Delta/Database/Model/Human/SaveState.swift index f676648..6456773 100644 --- a/Delta/Database/Model/Human/SaveState.swift +++ b/Delta/Database/Model/Human/SaveState.swift @@ -123,7 +123,11 @@ extension SaveState: Syncable } public var isSyncingEnabled: Bool { - return self.type != .auto && self.type != .quick + // self.game may be nil if being downloaded, so don't enforce it. + // guard let identifier = self.game?.identifier else { return false } + + let isSyncingEnabled = (self.type != .auto && self.type != .quick) && (self.game?.identifier != Game.melonDSBIOSIdentifier) + return isSyncingEnabled } public var syncableMetadata: [HarmonyMetadataKey : String] { diff --git a/Delta/Extensions/ControllerSkin+Configuring.swift b/Delta/Extensions/ControllerSkin+Configuring.swift index d715540..6dcecbf 100644 --- a/Delta/Extensions/ControllerSkin+Configuring.swift +++ b/Delta/Extensions/ControllerSkin+Configuring.swift @@ -10,6 +10,18 @@ import DeltaCore extension ControllerSkin { + convenience init?(system: System, context: NSManagedObjectContext) + { + guard let deltaControllerSkin = DeltaCore.ControllerSkin.standardControllerSkin(for: system.gameType) else { return nil } + + self.init(context: context) + + self.isStandard = true + self.filename = deltaControllerSkin.fileURL.lastPathComponent + + self.configure(with: deltaControllerSkin) + } + func configure(with skin: DeltaCore.ControllerSkin) { // Manually copy values to be stored in database. diff --git a/Delta/Game Selection/GameCollectionViewController.swift b/Delta/Game Selection/GameCollectionViewController.swift index 31ffe34..28709b4 100644 --- a/Delta/Game Selection/GameCollectionViewController.swift +++ b/Delta/Game Selection/GameCollectionViewController.swift @@ -440,6 +440,7 @@ private extension GameCollectionViewController switch game.type { case GameType.unknown: return [cancelAction, renameAction, changeArtworkAction, shareAction, deleteAction] + case .ds where game.identifier == Game.melonDSBIOSIdentifier: return [cancelAction, renameAction, changeArtworkAction, changeControllerSkinAction, saveStatesAction] default: return [cancelAction, renameAction, changeArtworkAction, changeControllerSkinAction, shareAction, saveStatesAction, importSaveFile, deleteAction] } } diff --git a/Resources/DS.png b/Resources/DS.png new file mode 100644 index 0000000..2c36ce6 Binary files /dev/null and b/Resources/DS.png differ