From 3d16fed35adb038b6c7e15c81b23f3146f1c58d8 Mon Sep 17 00:00:00 2001 From: Riley Testut Date: Fri, 12 Aug 2016 01:09:52 -0500 Subject: [PATCH] Refactors previewing GameViewController logic into new PreviewGameViewController --- Cores/DeltaCore | 2 +- Delta.xcodeproj/project.pbxproj | 8 + Delta/Emulation/GameViewController.swift | 95 +--------- .../Emulation/PreviewGameViewController.swift | 176 ++++++++++++++++++ Delta/Extensions/EmulatorCore+Cheats.swift | 66 +++++++ Delta/Launch/LaunchViewController.swift | 1 - .../SaveStatesViewController.swift | 142 ++++++-------- 7 files changed, 309 insertions(+), 181 deletions(-) create mode 100644 Delta/Emulation/PreviewGameViewController.swift create mode 100644 Delta/Extensions/EmulatorCore+Cheats.swift diff --git a/Cores/DeltaCore b/Cores/DeltaCore index d9b61b6..d489536 160000 --- a/Cores/DeltaCore +++ b/Cores/DeltaCore @@ -1 +1 @@ -Subproject commit d9b61b60c23286a4758bab06ed4a89de641f2628 +Subproject commit d4895367427ffed6ef1fd04e60868cf799fb3371 diff --git a/Delta.xcodeproj/project.pbxproj b/Delta.xcodeproj/project.pbxproj index 2b6e55a..23f7444 100644 --- a/Delta.xcodeproj/project.pbxproj +++ b/Delta.xcodeproj/project.pbxproj @@ -13,6 +13,8 @@ BF090CF41B490D8300DCAB45 /* UIDevice+Vibration.m in Sources */ = {isa = PBXBuildFile; fileRef = BF090CF31B490D8300DCAB45 /* UIDevice+Vibration.m */; }; BF0CDDAD1C8155D200640168 /* LoadImageOperation.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF0CDDAC1C8155D200640168 /* LoadImageOperation.swift */; }; BF107EC41BF413F000E0C32C /* GamesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF107EC31BF413F000E0C32C /* GamesViewController.swift */; }; + BF13A7561D5D29B0000BB055 /* PreviewGameViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF13A7551D5D29B0000BB055 /* PreviewGameViewController.swift */; }; + BF13A7581D5D2FD9000BB055 /* EmulatorCore+Cheats.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF13A7571D5D2FD9000BB055 /* EmulatorCore+Cheats.swift */; }; BF172AEB1C68986300C26774 /* NSManagedObjectContext+Conveniences.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF172AEA1C68986300C26774 /* NSManagedObjectContext+Conveniences.swift */; }; BF1FB1861C5EE643007E2494 /* SaveState.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF1FB1831C5EE643007E2494 /* SaveState.swift */; }; BF27CC8E1BC9FEA200A20D89 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BF6BB2451BB73FE800CCF94A /* Assets.xcassets */; }; @@ -99,6 +101,8 @@ BF090CF31B490D8300DCAB45 /* UIDevice+Vibration.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "UIDevice+Vibration.m"; sourceTree = ""; }; BF0CDDAC1C8155D200640168 /* LoadImageOperation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = LoadImageOperation.swift; path = Components/LoadImageOperation.swift; sourceTree = ""; }; BF107EC31BF413F000E0C32C /* GamesViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GamesViewController.swift; sourceTree = ""; }; + BF13A7551D5D29B0000BB055 /* PreviewGameViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PreviewGameViewController.swift; sourceTree = ""; }; + BF13A7571D5D2FD9000BB055 /* EmulatorCore+Cheats.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "EmulatorCore+Cheats.swift"; sourceTree = ""; }; BF172AEA1C68986300C26774 /* NSManagedObjectContext+Conveniences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "NSManagedObjectContext+Conveniences.swift"; sourceTree = ""; }; BF1FB1831C5EE643007E2494 /* SaveState.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SaveState.swift; sourceTree = ""; }; BF27CC861BC9E3C600A20D89 /* Delta.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.xml; path = Delta.entitlements; sourceTree = ""; }; @@ -189,6 +193,7 @@ BF797A2C1C2D339F00F1A000 /* UILabel+FontSize.swift */, BF7AE8091C2E8C7600B1B5BC /* UIColor+Delta.swift */, BFCEA67D1D56FF640061A534 /* UIViewControllerContextTransitioning+Conveniences.swift */, + BF13A7571D5D2FD9000BB055 /* EmulatorCore+Cheats.swift */, ); path = Extensions; sourceTree = ""; @@ -412,6 +417,7 @@ isa = PBXGroup; children = ( BF63BDE91D389EEB00FCB040 /* GameViewController.swift */, + BF13A7551D5D29B0000BB055 /* PreviewGameViewController.swift */, ); path = Emulation; sourceTree = ""; @@ -573,6 +579,7 @@ BF7AE8241C2E984300B1B5BC /* GridCollectionViewLayout.swift in Sources */, BF1FB1861C5EE643007E2494 /* SaveState.swift in Sources */, BFA0D1271D3AE1F600565894 /* GameViewController.swift in Sources */, + BF13A7581D5D2FD9000BB055 /* EmulatorCore+Cheats.swift in Sources */, BF31878B1D489AAA00BD020D /* CheatValidator.swift in Sources */, BFB141181BE46934004FBF46 /* GameCollectionViewDataSource.swift in Sources */, BFFC46201D59823500AF2CC6 /* InitialGamesStoryboardSegue.swift in Sources */, @@ -605,6 +612,7 @@ BF0CDDAD1C8155D200640168 /* LoadImageOperation.swift in Sources */, BF107EC41BF413F000E0C32C /* GamesViewController.swift in Sources */, BF172AEB1C68986300C26774 /* NSManagedObjectContext+Conveniences.swift in Sources */, + BF13A7561D5D29B0000BB055 /* PreviewGameViewController.swift in Sources */, BFCEA67E1D56FF640061A534 /* UIViewControllerContextTransitioning+Conveniences.swift in Sources */, BFFC461E1D59823500AF2CC6 /* GamesPresentationController.swift in Sources */, BF5E7F441B9A650B00AE44F8 /* SettingsViewController.swift in Sources */, diff --git a/Delta/Emulation/GameViewController.swift b/Delta/Emulation/GameViewController.swift index c1dc3ce..ba1813e 100644 --- a/Delta/Emulation/GameViewController.swift +++ b/Delta/Emulation/GameViewController.swift @@ -39,19 +39,10 @@ class GameViewController: DeltaCore.GameViewController self.emulatorCore?.removeObserver(self, forKeyPath: #keyPath(EmulatorCore.state), context: &kvoContext) } didSet { - guard let emulatorCore = self.emulatorCore else { return } - self.preferredContentSize = emulatorCore.preferredRenderingSize - - emulatorCore.addObserver(self, forKeyPath: #keyPath(EmulatorCore.state), options: [.old], context: &kvoContext) + self.emulatorCore?.addObserver(self, forKeyPath: #keyPath(EmulatorCore.state), options: [.old], context: &kvoContext) } } - // If non-nil, will override the default preview action items returned in previewActionItems() - var overridePreviewActionItems: [UIPreviewActionItem]? - - // Set to true to handle automatically updating auto save state - var updatesAutoSaveState = false - //MARK: - Private Properties - private var pauseViewController: PauseViewController? private var pausingGameController: GameController? @@ -86,26 +77,6 @@ class GameViewController: DeltaCore.GameViewController private var sustainButtonsBlurView: UIVisualEffectView! private var sustainButtonsBackgroundView: RSTBackgroundView! - override var previewActionItems: [UIPreviewActionItem] - { - if let previewActionItems = self.overridePreviewActionItems - { - return previewActionItems - } - - guard let game = self.game as? Game else { return [] } - - let presentingViewController = self.presentingViewController - - let launchGameAction = UIPreviewAction(title: NSLocalizedString("Launch \(game.name)", comment: ""), style: .default) { (action, viewController) in - // Delaying until next run loop prevents self from being dismissed immediately - DispatchQueue.main.async { - presentingViewController?.present(viewController, animated: true, completion: nil) - } - } - return [launchGameAction] - } - required init() { self.reactivateSustainedInputsQueue = OperationQueue() @@ -349,7 +320,7 @@ extension GameViewController if previousState == .stopped { - self.updateCheats() + self.emulatorCore?.updateCheats() } } } @@ -396,9 +367,7 @@ private extension GameViewController extension GameViewController: SaveStatesViewControllerDelegate { private func updateAutoSaveState() - { - guard self.updatesAutoSaveState else { return } - + { // If pausedSaveState exists and has already been saved, don't update auto save state // This prevents us from filling our auto save state slots with the same save state let savedPausedSaveState = self.pausedSaveState?.isSaved ?? false @@ -566,7 +535,7 @@ extension GameViewController: SaveStatesViewControllerDelegate print(error) } - self.updateCheats() + self.emulatorCore?.updateCheats() self.pauseViewController?.dismiss() } @@ -578,67 +547,13 @@ extension GameViewController: CheatsViewControllerDelegate { func cheatsViewController(_ cheatsViewController: CheatsViewController, activateCheat cheat: Cheat) { - self.activate(cheat) + self.emulatorCore?.activateCheatWithErrorLogging(cheat) } func cheatsViewController(_ cheatsViewController: CheatsViewController, deactivateCheat cheat: Cheat) { self.emulatorCore?.deactivate(cheat) } - - private func activate(_ cheat: Cheat) - { - do - { - try self.emulatorCore?.activate(cheat) - } - catch EmulatorCore.CheatError.invalid - { - print("Invalid cheat:", cheat.name, cheat.code) - } - catch let error as NSError - { - print("Unknown Cheat Error:", error, cheat.name, cheat.code) - } - } - - private func updateCheats() - { - guard let game = self.game as? Game else { return } - - let running = (self.emulatorCore?.state == .running) - - if running - { - // Core MUST be paused when activating cheats, or else race conditions could crash the core - self.pauseEmulation() - } - - let backgroundContext = DatabaseManager.shared.newBackgroundContext() - backgroundContext.performAndWait { - - let predicate = NSPredicate(format: "%K == %@", Cheat.Attributes.game.rawValue, game) - - let cheats = Cheat.instancesWithPredicate(predicate, inManagedObjectContext: backgroundContext, type: Cheat.self) - for cheat in cheats - { - if cheat.enabled - { - self.activate(cheat) - } - else - { - self.emulatorCore?.deactivate(cheat) - } - } - } - - if running - { - self.resumeEmulation() - } - - } } //MARK: - Sustain Buttons - diff --git a/Delta/Emulation/PreviewGameViewController.swift b/Delta/Emulation/PreviewGameViewController.swift new file mode 100644 index 0000000..5838438 --- /dev/null +++ b/Delta/Emulation/PreviewGameViewController.swift @@ -0,0 +1,176 @@ +// +// PreviewGameViewController.swift +// Delta +// +// Created by Riley Testut on 8/11/16. +// Copyright © 2016 Riley Testut. All rights reserved. +// + +import UIKit + +import DeltaCore + +private var kvoContext = 0 + +class PreviewGameViewController: DeltaCore.GameViewController +{ + // If non-nil, will override the default preview action items returned in previewActionItems() + var overridePreviewActionItems: [UIPreviewActionItem]? + + // Save state to be loaded upon preview + var previewSaveState: SaveStateProtocol? + + // Initial image to be shown while loading + var previewImage: UIImage? { + didSet { + self.updatePreviewImage() + } + } + + private var emulatorCoreQueue = DispatchQueue(label: "com.rileytestut.Delta.PreviewGameViewController.emulatorCoreQueue", qos: .userInitiated) + + override var game: GameProtocol? { + willSet { + self.emulatorCore?.removeObserver(self, forKeyPath: #keyPath(EmulatorCore.state), context: &kvoContext) + } + didSet { + guard let emulatorCore = self.emulatorCore else { + self.preferredContentSize = CGSize.zero + return + } + + emulatorCore.addObserver(self, forKeyPath: #keyPath(EmulatorCore.state), options: [.old], context: &kvoContext) + + self.preferredContentSize = emulatorCore.preferredRenderingSize + } + } + + override var previewActionItems: [UIPreviewActionItem] { + guard let previewActionItems = self.overridePreviewActionItems else { return [] } + return previewActionItems + } + + deinit + { + self.emulatorCore?.removeObserver(self, forKeyPath: #keyPath(EmulatorCore.state), context: &kvoContext) + } +} + +//MARK: - UIViewController - +/// UIViewController +extension PreviewGameViewController +{ + override func viewDidLoad() + { + super.viewDidLoad() + + self.controllerView.isHidden = true + + // Temporarily prevent emulatorCore from updating gameView to prevent flicker of black, or other visual glitches + self.emulatorCore?.remove(self.gameView) + } + + override func viewDidAppear(_ animated: Bool) + { + super.viewDidAppear(animated) + + self.emulatorCoreQueue.async { + self.emulatorCore?.resume() + } + } + + override func viewWillDisappear(_ animated: Bool) + { + super.viewWillDisappear(animated) + + // Pause in viewWillDisappear and not viewDidDisappear like DeltaCore.GameViewController so the audio cuts off earlier if being dismissed + self.emulatorCore?.pause() + } + + override func viewDidLayoutSubviews() + { + super.viewDidLayoutSubviews() + + // Need to update in viewDidLayoutSubviews() to ensure bounds of gameView are not CGRect.zero + self.updatePreviewImage() + } + + override func didReceiveMemoryWarning() + { + super.didReceiveMemoryWarning() + // Dispose of any resources that can be recreated. + } + + override func observeValue(forKeyPath keyPath: String?, of object: AnyObject?, change: [NSKeyValueChangeKey : AnyObject]?, context: UnsafeMutablePointer?) + { + guard context == &kvoContext else { return super.observeValue(forKeyPath: keyPath, of: object, change: change, context: context) } + + guard + let rawValue = change?[.oldKey] as? Int, + let previousState = EmulatorCore.State(rawValue: rawValue), + let state = self.emulatorCore?.state + else { return } + + if previousState == .stopped, state == .running + { + self.emulatorCoreQueue.sync { + if self.isAppearing + { + // Pause to prevent it from starting before visible (in case user peeked slowly) + self.emulatorCore?.pause() + } + + self.preparePreview() + } + } + } +} + +//MARK: - Private - +private extension PreviewGameViewController +{ + func updatePreviewImage() + { + if let previewImage = self.previewImage + { + self.gameView?.inputImage = CIImage(image: previewImage) + } + else + { + self.gameView?.inputImage = nil + } + } + + func preparePreview() + { + var previewSaveState = self.previewSaveState + + if let saveState = self.previewSaveState as? SaveState + { + saveState.managedObjectContext?.performAndWait { + previewSaveState = DeltaCore.SaveState(fileURL: saveState.fileURL, gameType: saveState.gameType) + } + } + + if let saveState = previewSaveState + { + do + { + try self.emulatorCore?.load(saveState) + } + catch EmulatorCore.SaveStateError.doesNotExist + { + print("Save State does not exist.") + } + catch + { + print(error) + } + } + + self.emulatorCore?.updateCheats() + + // Re-enable emulatorCore to update gameView again + self.emulatorCore?.add(self.gameView) + } +} diff --git a/Delta/Extensions/EmulatorCore+Cheats.swift b/Delta/Extensions/EmulatorCore+Cheats.swift new file mode 100644 index 0000000..d5fc5b7 --- /dev/null +++ b/Delta/Extensions/EmulatorCore+Cheats.swift @@ -0,0 +1,66 @@ +// +// EmulatorCore+Cheats.swift +// Delta +// +// Created by Riley Testut on 8/11/16. +// Copyright © 2016 Riley Testut. All rights reserved. +// + +import DeltaCore + +extension EmulatorCore +{ + func activateCheatWithErrorLogging(_ cheat: Cheat) + { + do + { + try self.activate(cheat) + } + catch EmulatorCore.CheatError.invalid + { + print("Invalid cheat:", cheat.name, cheat.code) + } + catch + { + print("Unknown Cheat Error:", error, cheat.name, cheat.code) + } + } + + func updateCheats() + { + guard let game = self.game as? Game else { return } + + let running = (self.state == .running) + + if running + { + // Core MUST be paused when activating cheats, or else race conditions could crash the core + self.pause() + } + + let backgroundContext = DatabaseManager.shared.newBackgroundContext() + backgroundContext.performAndWait { + + let predicate = NSPredicate(format: "%K == %@", Cheat.Attributes.game.rawValue, game) + + let cheats = Cheat.instancesWithPredicate(predicate, inManagedObjectContext: backgroundContext, type: Cheat.self) + for cheat in cheats + { + if cheat.enabled + { + self.activateCheatWithErrorLogging(cheat) + } + else + { + self.deactivate(cheat) + } + } + } + + if running + { + self.resume() + } + + } +} diff --git a/Delta/Launch/LaunchViewController.swift b/Delta/Launch/LaunchViewController.swift index 7b89de7..1f88f54 100644 --- a/Delta/Launch/LaunchViewController.swift +++ b/Delta/Launch/LaunchViewController.swift @@ -43,6 +43,5 @@ class LaunchViewController: UIViewController guard segue.identifier == "embedGameViewController" else { return } self.gameViewController = segue.destination as! GameViewController - self.gameViewController.updatesAutoSaveState = true } } diff --git a/Delta/Pause Menu/Save States/SaveStatesViewController.swift b/Delta/Pause Menu/Save States/SaveStatesViewController.swift index 8df3348..9323753 100644 --- a/Delta/Pause Menu/Save States/SaveStatesViewController.swift +++ b/Delta/Pause Menu/Save States/SaveStatesViewController.swift @@ -65,8 +65,6 @@ class SaveStatesViewController: UICollectionViewController private let dateFormatter: DateFormatter - private let previewGameViewController = GameViewController() - required init?(coder aDecoder: NSCoder) { self.dateFormatter = DateFormatter() @@ -122,9 +120,8 @@ extension SaveStatesViewController let longPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(SaveStatesViewController.handleLongPressGesture(_:))) self.collectionView?.addGestureRecognizer(longPressGestureRecognizer) - - // Pre-initialize previewGameViewController with game and start/pause emulation to ensure previewingContext(_:viewControllerForLocation:) callback doesn't take too long + break 3D Touch animation - self.preparePreviewGameViewController() + + self.prepareEmulatorCoreSaveState() self.registerForPreviewing(with: self, sourceView: self.collectionView!) @@ -286,23 +283,13 @@ private extension SaveStatesViewController func updateSaveState(_ saveState: SaveState) { - // Stop previewGameViewController.emulatorCore, and switch to self.emulatorCore + // Switch back to self.emulatorCore self.prepareEmulatorCore() saveState.managedObjectContext?.performAndWait { self.delegate?.saveStatesViewController(self, updateSaveState: saveState) saveState.managedObjectContext?.saveWithErrorLogging() } - - DispatchQueue.main.async { - // Only restart self.previewGameViewController.emulatorCore if we're not being dismissed - if !self.isDisappearing - { - self.emulatorCore?.stop() - self.previewGameViewController.emulatorCore?.start() - self.previewGameViewController.emulatorCore?.pause() - } - } } func loadSaveState(_ saveState: SaveStateProtocol) @@ -492,9 +479,14 @@ private extension SaveStatesViewController func resetEmulatorCoreIfNeeded() { - guard let saveState = self.emulatorCoreSaveState else { return } + // Kinda hacky, but isMovingFromParentViewController only returns yes when popping off navigation controller, and not being dismissed modally + // Because of this, this is only run when the user returns to PauseMenuViewController, and not when they choose a save state to load + if self.isMovingFromParentViewController + { + self.prepareEmulatorCore() + } - defer + if let saveState = self.emulatorCoreSaveState { // Remove temporary save state file do @@ -506,76 +498,57 @@ private extension SaveStatesViewController print(error) } } - - self.previewGameViewController.emulatorCore?.stop() - - // Kinda hacky, but isMovingFromParentViewController only returns yes when popping off navigation controller, and not being dismissed modally - // Because of this, this is only run when the user returns to PauseMenuViewController, and not when they choose a save state to load - if self.isMovingFromParentViewController - { - self.prepareEmulatorCore() - } } func prepareEmulatorCore() { - self.previewGameViewController.emulatorCore?.stop() - // We stopped emulation for 3D Touch, so now we must resume emulation and load the save state we made to make it seem like it was never stopped - if let emulatorCore = self.emulatorCore + guard let emulatorCore = self.emulatorCore else { return } + + // Temporarily disable video rendering to prevent flickers + emulatorCore.videoManager.isEnabled = false + + // Load the save state we stored a reference to + emulatorCore.start() + emulatorCore.pause() + + if let saveState = self.emulatorCoreSaveState { - // Temporarily disable video rendering to prevent flickers - emulatorCore.videoManager.isEnabled = false - - // Load the save state we stored a reference to - emulatorCore.start() - emulatorCore.pause() - - if let saveState = self.emulatorCoreSaveState + do { - do - { - try emulatorCore.load(saveState) - } - catch EmulatorCore.SaveStateError.doesNotExist - { - print("Save State does not exist.") - } - catch let error as NSError - { - print(error) - } + try emulatorCore.load(saveState) + } + catch EmulatorCore.SaveStateError.doesNotExist + { + print("Save State does not exist.") + } + catch let error as NSError + { + print(error) } - - // Re-enable video rendering - emulatorCore.videoManager.isEnabled = true } + + // Re-enable video rendering + emulatorCore.videoManager.isEnabled = true } } //MARK: - 3D Touch - extension SaveStatesViewController: UIViewControllerPreviewingDelegate { - private func preparePreviewGameViewController() + private func prepareEmulatorCoreSaveState() { - if let emulatorCore = self.emulatorCore + guard let emulatorCore = self.emulatorCore else { return } + + // Store reference to current game state before we stop emulation so we can resume it if user decides to not load a save state + + let fileURL = FileManager.uniqueTemporaryURL() + self.emulatorCoreSaveState = emulatorCore.saveSaveState(to: fileURL) + + if self.emulatorCoreSaveState != nil { - // Store reference to current game state before we stop emulation so we can resume it if user decides to not load a save state - - let fileURL = FileManager.uniqueTemporaryURL() - self.emulatorCoreSaveState = emulatorCore.saveSaveState(to: fileURL) - - guard self.emulatorCoreSaveState != nil else { return } - emulatorCore.stop() } - - self.previewGameViewController.loadViewIfNeeded() - self.previewGameViewController.controllerView.isHidden = true - - self.previewGameViewController.game = self.game - self.previewGameViewController.emulatorCore?.start() - self.previewGameViewController.emulatorCore?.pause() } func previewingContext(_ previewingContext: UIViewControllerPreviewing, viewControllerForLocation location: CGPoint) -> UIViewController? @@ -589,37 +562,28 @@ extension SaveStatesViewController: UIViewControllerPreviewingDelegate previewingContext.sourceRect = layoutAttributes.frame let saveState = self.fetchedResultsController.object(at: indexPath) as! SaveState + let actions = self.actionsForSaveState(saveState)?.lazy.filter{ $0.style != .cancel }.map{ $0.previewAction } ?? [] + let previewImage = self.imageCache.object(forKey: saveState.imageFileURL) ?? UIImage(contentsOfFile: saveState.imageFileURL.path) - do - { - try self.previewGameViewController.emulatorCore?.load(saveState) - - let actions = self.actionsForSaveState(saveState)?.lazy.filter{ $0.style != .cancel }.map{ $0.previewAction } ?? [] - self.previewGameViewController.overridePreviewActionItems = Array(actions) - - return self.previewGameViewController - } - catch EmulatorCore.SaveStateError.doesNotExist - { - print("Save State \(saveState.name) does not exist.") - } - catch let error as NSError - { - print(error) - } + let previewGameViewController = PreviewGameViewController() + previewGameViewController.game = self.game + previewGameViewController.overridePreviewActionItems = actions + previewGameViewController.previewSaveState = saveState + previewGameViewController.previewImage = previewImage - return nil + return previewGameViewController } func previewingContext(_ previewingContext: UIViewControllerPreviewing, commit viewControllerToCommit: UIViewController) { - let gameViewController = viewControllerToCommit as! GameViewController - + let gameViewController = viewControllerToCommit as! PreviewGameViewController gameViewController.emulatorCore?.pause() let fileURL = FileManager.uniqueTemporaryURL() if let saveState = gameViewController.emulatorCore?.saveSaveState(to: fileURL) { + gameViewController.emulatorCore?.stop() + self.loadSaveState(saveState) do