Skip to content

Commit

Permalink
Adds support for GBC games
Browse files Browse the repository at this point in the history
Adds System enum to represent supported game systems, simplifying the process to add future game systems.
  • Loading branch information
rileytestut committed May 1, 2017
1 parent d7db699 commit 9349353
Show file tree
Hide file tree
Showing 20 changed files with 315 additions and 215 deletions.
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,6 @@
[submodule "Cores/GBADeltaCore"]
path = Cores/GBADeltaCore
url = [email protected]:rileytestut/GBADeltaCore.git
[submodule "Cores/GBCDeltaCore"]
path = Cores/GBCDeltaCore
url = [email protected]:rileytestut/GBCDeltaCore.git
1 change: 1 addition & 0 deletions Cores/GBCDeltaCore
Submodule GBCDeltaCore added at 0e622c
34 changes: 22 additions & 12 deletions Delta.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

3 changes: 3 additions & 0 deletions Delta.xcworkspace/contents.xcworkspacedata

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 2 additions & 6 deletions Delta/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
import UIKit

import DeltaCore
import SNESDeltaCore
import GBADeltaCore

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate
Expand All @@ -21,8 +19,7 @@ class AppDelegate: UIResponder, UIApplicationDelegate
{
Settings.registerDefaults()

Delta.register(SNES.core)
Delta.register(GBA.core)
System.supportedSystems.forEach { Delta.register($0.deltaCore) }

self.configureAppearance()

Expand Down Expand Up @@ -92,8 +89,7 @@ extension AppDelegate
{
guard url.isFileURL else { return false }

let gameType = GameType.gameType(forFileExtension: url.pathExtension)
if gameType != .unknown || url.pathExtension.lowercased() == "zip"
if GameType(fileExtension: url.pathExtension) != nil || url.pathExtension.lowercased() == "zip"
{
return self.importGame(at: url)
}
Expand Down
4 changes: 2 additions & 2 deletions Delta/Components/Importing/ImportController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ class ImportController: NSObject
{
self.presentingViewController = presentingViewController

var documentTypes = GameType.supportedTypes.map { $0.rawValue }
var documentTypes = System.supportedSystems.map { $0.gameType.rawValue }
documentTypes.append(kUTTypeDeltaControllerSkin as String)
documentTypes.append(kUTTypeZipArchive as String)

Expand Down Expand Up @@ -75,7 +75,7 @@ class ImportController: NSObject
let controllerSkinURLs = contents.filter { $0.pathExtension.lowercased() == "deltaskin" }
self.importControllerSkins(at: Set(controllerSkinURLs))

let gameURLs = contents.filter { GameType.gameType(forFileExtension: $0.pathExtension) != .unknown || $0.pathExtension.lowercased() == "zip" }
let gameURLs = contents.filter { GameType(fileExtension: $0.pathExtension) != nil || $0.pathExtension.lowercased() == "zip" }
self.importGames(at: Set(gameURLs))
}

Expand Down
36 changes: 22 additions & 14 deletions Delta/Database/DatabaseManager.swift
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ extension DatabaseManager
{
case doesNotExist(URL)
case invalid(URL)
case unsupported(URL)
case unknown(URL, NSError)
case saveFailed(Set<URL>, NSError)

Expand All @@ -30,8 +31,9 @@ extension DatabaseManager
{
case .doesNotExist: return 0
case .invalid: return 1
case .unknown: return 2
case .saveFailed: return 3
case .unsupported: return 2
case .unknown: return 3
case .saveFailed: return 4
}
}

Expand All @@ -41,10 +43,12 @@ extension DatabaseManager
{
case (let .doesNotExist(url1), let .doesNotExist(url2)) where url1 == url2: return true
case (let .invalid(url1), let .invalid(url2)) where url1 == url2: return true
case (let .unsupported(url1), let .unsupported(url2)) where url1 == url2: return true
case (let .unknown(url1, error1), let .unknown(url2, error2)) where url1 == url2 && error1 == error2: return true
case (let .saveFailed(urls1, error1), let .saveFailed(urls2, error2)) where urls1 == urls2 && error1 == error2: return true
case (.doesNotExist, _): return false
case (.invalid, _): return false
case (.unsupported, _): return false
case (.unknown, _): return false
case (.saveFailed, _): return false
}
Expand Down Expand Up @@ -99,9 +103,9 @@ private extension DatabaseManager
{
self.performBackgroundTask { (context) in

for gameType in GameType.supportedTypes
for system in System.supportedSystems
{
guard let deltaControllerSkin = DeltaCore.ControllerSkin.standardControllerSkin(for: gameType) else { continue }
guard let deltaControllerSkin = DeltaCore.ControllerSkin.standardControllerSkin(for: system.gameType) else { continue }

let controllerSkin = ControllerSkin(context: context)
controllerSkin.isStandard = true
Expand Down Expand Up @@ -173,21 +177,27 @@ extension DatabaseManager
continue
}

let identifier = FileHash.sha1HashOfFile(atPath: url.path) as String
guard let gameType = GameType(fileExtension: url.pathExtension), let system = System(gameType: gameType) else {
errors.insert(.unsupported(url))
continue
}

let identifier = FileHash.sha1HashOfFile(atPath: url.path) as String
let filename = identifier + "." + url.pathExtension

let game = Game.insertIntoManagedObjectContext(context)
let game = Game(context: context)
game.identifier = identifier
game.type = gameType
game.filename = filename

let databaseMetadata = self.gamesDatabase?.metadata(for: game)
game.name = databaseMetadata?.name ?? url.deletingPathExtension().lastPathComponent
game.artworkURL = databaseMetadata?.artworkURL

let gameCollection = GameCollection.gameSystemCollectionForPathExtension(url.pathExtension, inManagedObjectContext: context)
game.type = GameType(rawValue: gameCollection.identifier)
game.gameCollections.insert(gameCollection)

let gameCollection = GameCollection(context: context)
gameCollection.identifier = gameType.rawValue
gameCollection.index = Int16(system.year)
gameCollection.games.insert(game)

do
{
Expand All @@ -212,7 +222,6 @@ extension DatabaseManager

errors.insert(.unknown(url, error))
}

}

do
Expand Down Expand Up @@ -328,9 +337,8 @@ extension DatabaseManager
guard !entry.fileName.contains("/") else { continue }

let fileExtension = (entry.fileName as NSString).pathExtension
let gameType = GameType.gameType(forFileExtension: fileExtension)

guard gameType != .unknown else { continue }

guard GameType(fileExtension: fileExtension) != nil else { continue }

// At least one entry is a valid game file, so we set archiveContainsValidGameFile to true
// This will result in this archive being considered valid, and thus we will not return an ImportError.invalid error for the archive
Expand Down
44 changes: 9 additions & 35 deletions Delta/Database/Model/Human/GameCollection.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,48 +9,22 @@
import CoreData

import DeltaCore
import SNESDeltaCore
import GBADeltaCore

@objc(GameCollection)
public class GameCollection: _GameCollection
public class GameCollection: _GameCollection
{
var name: String
{
let gameType = GameType(rawValue: self.identifier)
return gameType.localizedName
var name: String {
return self.system?.localizedName ?? NSLocalizedString("Unknown", comment: "")
}

var shortName: String
{
let gameType = GameType(rawValue: self.identifier)
return gameType.localizedShortName
var shortName: String {
return self.system?.localizedShortName ?? NSLocalizedString("Unknown", comment: "")
}

class func gameSystemCollectionForPathExtension(_ pathExtension: String?, inManagedObjectContext managedObjectContext: NSManagedObjectContext) -> GameCollection
{
let gameType = GameType.gameType(forFileExtension: pathExtension ?? "")
let identifier = gameType.rawValue

let index: Int16

switch gameType
{
case GameType.snes: index = 1990
case GameType.gba: index = 2001
default: index = Int16(INT16_MAX)
}

let predicate = NSPredicate(format: "%K == %@", #keyPath(GameCollection.identifier), identifier)

var gameCollection = GameCollection.instancesWithPredicate(predicate, inManagedObjectContext: managedObjectContext, type: GameCollection.self).first
if gameCollection == nil
{
gameCollection = GameCollection.insertIntoManagedObjectContext(managedObjectContext)
gameCollection?.identifier = identifier
gameCollection?.index = index
}
var system: System? {
let gameType = GameType(rawValue: self.identifier)

return gameCollection!
let system = System(gameType: gameType)
return system
}
}
8 changes: 4 additions & 4 deletions Delta/Emulation/GameViewController.swift
Original file line number Diff line number Diff line change
Expand Up @@ -391,11 +391,11 @@ private extension GameViewController

func updateControllerSkin()
{
guard let game = self.game else { return }
guard let game = self.game, let system = System(gameType: game.type) else { return }

let traits = DeltaCore.ControllerSkin.Traits.defaults(for: self.view)

let controllerSkin = Settings.preferredControllerSkin(for: game.type, traits: traits)
let controllerSkin = Settings.preferredControllerSkin(for: system, traits: traits)
self.controllerView.controllerSkin = controllerSkin

if controllerSkin?.isTranslucent(for: traits) ?? false
Expand Down Expand Up @@ -807,12 +807,12 @@ private extension GameViewController

case .preferredControllerSkin:
guard
let gameType = notification.userInfo?[Settings.NotificationUserInfoKey.gameType] as? GameType,
let system = notification.userInfo?[Settings.NotificationUserInfoKey.system] as? System,
let traits = notification.userInfo?[Settings.NotificationUserInfoKey.traits] as? DeltaCore.ControllerSkin.Traits
else { return }

let currentTraits = DeltaCore.ControllerSkin.Traits.defaults(for: self.view)
if gameType == self.game?.type && traits == currentTraits
if system.gameType == self.game?.type && traits == currentTraits
{
self.updateControllerSkin()
}
Expand Down
10 changes: 6 additions & 4 deletions Delta/Extensions/DeltaCoreProtocol+Delta.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,15 +7,17 @@
//

import DeltaCore
import GBADeltaCore

extension DeltaCoreProtocol
{
var supportedRates: ClosedRange<Double> {
switch self.gameType
guard let system = System(gameType: self.gameType) else { return 1...1 }

switch system
{
case GameType.gba: return 1...3
default: return 1...4
case .snes: return 1...4
case .gba: return 1...3
case .gbc: return 1...4
}
}
}
31 changes: 0 additions & 31 deletions Delta/Extensions/GameType+Delta.swift

This file was deleted.

34 changes: 0 additions & 34 deletions Delta/Extensions/GameType+Localization.swift

This file was deleted.

1 change: 1 addition & 0 deletions Delta/Extensions/UIAlertController+Importing.swift
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ extension UIAlertController
{
case .doesNotExist(let url): urls.insert(url)
case .invalid(let url): urls.insert(url)
case .unsupported(let url): urls.insert(url)
case .unknown(let url, _): urls.insert(url)
case .saveFailed(let errorURLs, _): urls.formUnion(errorURLs)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ extension ControllerSkinsViewController

class ControllerSkinsViewController: UITableViewController
{
var gameType: GameType! {
var system: System! {
didSet {
self.updateDataSource()
}
Expand Down Expand Up @@ -67,12 +67,12 @@ private extension ControllerSkinsViewController
//MARK: - Update
func updateDataSource()
{
guard let gameType = self.gameType, let traits = self.traits else { return }
guard let system = self.system, let traits = self.traits else { return }

let configuration = ControllerSkinConfigurations(traits: traits)

let fetchRequest: NSFetchRequest<ControllerSkin> = ControllerSkin.fetchRequest()
fetchRequest.predicate = NSPredicate(format: "%K == %@ AND (%K & %d) == %d", #keyPath(ControllerSkin.gameType), gameType.rawValue, #keyPath(ControllerSkin.supportedConfigurations), configuration.rawValue, configuration.rawValue)
fetchRequest.predicate = NSPredicate(format: "%K == %@ AND (%K & %d) == %d", #keyPath(ControllerSkin.gameType), system.gameType.rawValue, #keyPath(ControllerSkin.supportedConfigurations), configuration.rawValue, configuration.rawValue)
fetchRequest.sortDescriptors = [NSSortDescriptor(key: #keyPath(ControllerSkin.isStandard), ascending: false), NSSortDescriptor(key: #keyPath(ControllerSkin.name), ascending: true)]

self.dataSource.fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: DatabaseManager.shared.viewContext, sectionNameKeyPath: #keyPath(ControllerSkin.name), cacheName: nil)
Expand Down Expand Up @@ -159,7 +159,7 @@ extension ControllerSkinsViewController
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
let controllerSkin = self.dataSource.item(at: indexPath)
Settings.setPreferredControllerSkin(controllerSkin, for: self.gameType, traits: self.traits)
Settings.setPreferredControllerSkin(controllerSkin, for: self.system, traits: self.traits)

_ = self.navigationController?.popViewController(animated: true)
}
Expand Down
Loading

0 comments on commit 9349353

Please sign in to comment.