Fixes issue where creating auto save state would fail when backgrounded with SaveStatesViewController visible
This commit is contained in:
parent
30eec7bc2f
commit
b017be6368
@ -14,22 +14,31 @@ import Roxas
|
|||||||
|
|
||||||
private var kvoContext = 0
|
private var kvoContext = 0
|
||||||
|
|
||||||
|
private extension GameViewController
|
||||||
|
{
|
||||||
|
struct PausedSaveState: SaveStateProtocol
|
||||||
|
{
|
||||||
|
var fileURL: URL
|
||||||
|
var gameType: GameType
|
||||||
|
|
||||||
|
var isSaved = false
|
||||||
|
|
||||||
|
init(fileURL: URL, gameType: GameType)
|
||||||
|
{
|
||||||
|
self.fileURL = fileURL
|
||||||
|
self.gameType = gameType
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class GameViewController: DeltaCore.GameViewController
|
class GameViewController: DeltaCore.GameViewController
|
||||||
{
|
{
|
||||||
/// Assumed to be Delta.Game instance
|
/// Assumed to be Delta.Game instance
|
||||||
override var game: GameProtocol? {
|
override var game: GameProtocol? {
|
||||||
willSet
|
willSet {
|
||||||
{
|
|
||||||
self.emulatorCore?.removeObserver(self, forKeyPath: #keyPath(EmulatorCore.state), context: &kvoContext)
|
self.emulatorCore?.removeObserver(self, forKeyPath: #keyPath(EmulatorCore.state), context: &kvoContext)
|
||||||
}
|
}
|
||||||
didSet
|
didSet {
|
||||||
{
|
|
||||||
if self.game?.fileURL != oldValue?.fileURL
|
|
||||||
{
|
|
||||||
// Game changed, so we make sure auto save states are enabled again
|
|
||||||
self.ignoreAutoSaveStateUpdates = false
|
|
||||||
}
|
|
||||||
|
|
||||||
guard let emulatorCore = self.emulatorCore else { return }
|
guard let emulatorCore = self.emulatorCore else { return }
|
||||||
self.preferredContentSize = emulatorCore.preferredRenderingSize
|
self.preferredContentSize = emulatorCore.preferredRenderingSize
|
||||||
|
|
||||||
@ -47,8 +56,23 @@ class GameViewController: DeltaCore.GameViewController
|
|||||||
private var pauseViewController: PauseViewController?
|
private var pauseViewController: PauseViewController?
|
||||||
private var pausingGameController: GameController?
|
private var pausingGameController: GameController?
|
||||||
|
|
||||||
// Prevents the "same" save state from being saved multiple times
|
// Prevents the same save state from being saved multiple times
|
||||||
private var ignoreAutoSaveStateUpdates = false
|
private var pausedSaveState: PausedSaveState? {
|
||||||
|
didSet
|
||||||
|
{
|
||||||
|
if let saveState = oldValue, self.pausedSaveState == nil
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
try FileManager.default.removeItem(at: saveState.fileURL)
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
print(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private var context = CIContext(options: [kCIContextWorkingColorSpace: NSNull()])
|
private var context = CIContext(options: [kCIContextWorkingColorSpace: NSNull()])
|
||||||
|
|
||||||
@ -211,6 +235,15 @@ extension GameViewController
|
|||||||
self.updateAutoSaveState()
|
self.updateAutoSaveState()
|
||||||
|
|
||||||
case "pause":
|
case "pause":
|
||||||
|
|
||||||
|
if let game = self.game
|
||||||
|
{
|
||||||
|
let fileURL = FileManager.uniqueTemporaryURL()
|
||||||
|
self.pausedSaveState = PausedSaveState(fileURL: fileURL, gameType: game.type)
|
||||||
|
|
||||||
|
self.emulatorCore?.saveSaveState(to: fileURL)
|
||||||
|
}
|
||||||
|
|
||||||
guard let gameController = sender as? GameController else {
|
guard let gameController = sender as? GameController else {
|
||||||
fatalError("sender for pauseSegue must be the game controller that pressed the Menu button")
|
fatalError("sender for pauseSegue must be the game controller that pressed the Menu button")
|
||||||
}
|
}
|
||||||
@ -257,6 +290,9 @@ extension GameViewController
|
|||||||
switch identifier
|
switch identifier
|
||||||
{
|
{
|
||||||
case "unwindFromPauseMenu":
|
case "unwindFromPauseMenu":
|
||||||
|
|
||||||
|
self.pausedSaveState = nil
|
||||||
|
|
||||||
DispatchQueue.main.async {
|
DispatchQueue.main.async {
|
||||||
if
|
if
|
||||||
let transitionCoordinator = self.transitionCoordinator,
|
let transitionCoordinator = self.transitionCoordinator,
|
||||||
@ -299,6 +335,7 @@ extension GameViewController
|
|||||||
|
|
||||||
@IBAction private func unwindFromGamesViewController(with segue: UIStoryboardSegue)
|
@IBAction private func unwindFromGamesViewController(with segue: UIStoryboardSegue)
|
||||||
{
|
{
|
||||||
|
self.pausedSaveState = nil
|
||||||
self.emulatorCore?.resume()
|
self.emulatorCore?.resume()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -314,11 +351,6 @@ extension GameViewController
|
|||||||
{
|
{
|
||||||
self.updateCheats()
|
self.updateCheats()
|
||||||
}
|
}
|
||||||
|
|
||||||
if self.emulatorCore?.state == .running
|
|
||||||
{
|
|
||||||
self.ignoreAutoSaveStateUpdates = false
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -365,14 +397,14 @@ extension GameViewController: SaveStatesViewControllerDelegate
|
|||||||
{
|
{
|
||||||
private func updateAutoSaveState()
|
private func updateAutoSaveState()
|
||||||
{
|
{
|
||||||
guard !self.ignoreAutoSaveStateUpdates else { return }
|
|
||||||
|
|
||||||
// If not in view hierarchy, don't update auto save state
|
|
||||||
guard self.updatesAutoSaveState else { return }
|
guard self.updatesAutoSaveState else { return }
|
||||||
|
|
||||||
// Ignore future update auto save state requests until we resume emulation again
|
// 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
|
// This prevents us from filling our auto save state slots with the same save state
|
||||||
self.ignoreAutoSaveStateUpdates = true
|
let savedPausedSaveState = self.pausedSaveState?.isSaved ?? false
|
||||||
|
guard !savedPausedSaveState else { return }
|
||||||
|
|
||||||
|
self.pausedSaveState?.isSaved = true
|
||||||
|
|
||||||
// Must be done synchronously
|
// Must be done synchronously
|
||||||
let backgroundContext = DatabaseManager.shared.newBackgroundContext()
|
let backgroundContext = DatabaseManager.shared.newBackgroundContext()
|
||||||
@ -400,7 +432,7 @@ extension GameViewController: SaveStatesViewControllerDelegate
|
|||||||
if let saveStates = saveStates, let saveState = saveStates.first, saveStates.count >= 2
|
if let saveStates = saveStates, let saveState = saveStates.first, saveStates.count >= 2
|
||||||
{
|
{
|
||||||
// If there are two or more auto save states, update the oldest one
|
// If there are two or more auto save states, update the oldest one
|
||||||
self.update(saveState)
|
self.update(saveState, with: self.pausedSaveState)
|
||||||
|
|
||||||
// Tiny hack; SaveStatesViewController sorts save states by creation date, so we update the creation date too
|
// Tiny hack; SaveStatesViewController sorts save states by creation date, so we update the creation date too
|
||||||
// Simpler than deleting old save states ¯\_(ツ)_/¯
|
// Simpler than deleting old save states ¯\_(ツ)_/¯
|
||||||
@ -413,14 +445,14 @@ extension GameViewController: SaveStatesViewControllerDelegate
|
|||||||
saveState.type = .auto
|
saveState.type = .auto
|
||||||
saveState.game = game
|
saveState.game = game
|
||||||
|
|
||||||
self.update(saveState)
|
self.update(saveState, with: self.pausedSaveState)
|
||||||
}
|
}
|
||||||
|
|
||||||
backgroundContext.saveWithErrorLogging()
|
backgroundContext.saveWithErrorLogging()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private func update(_ saveState: SaveState)
|
private func update(_ saveState: SaveState, with replacementSaveState: SaveStateProtocol? = nil)
|
||||||
{
|
{
|
||||||
let isRunning = (self.emulatorCore?.state == .running)
|
let isRunning = (self.emulatorCore?.state == .running)
|
||||||
|
|
||||||
@ -429,7 +461,27 @@ extension GameViewController: SaveStatesViewControllerDelegate
|
|||||||
self.pauseEmulation()
|
self.pauseEmulation()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let replacementSaveState = replacementSaveState
|
||||||
|
{
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if FileManager.default.fileExists(atPath: saveState.fileURL.path)
|
||||||
|
{
|
||||||
|
// Don't use replaceItem(), since that removes the original file as well
|
||||||
|
try FileManager.default.removeItem(at: saveState.fileURL)
|
||||||
|
}
|
||||||
|
|
||||||
|
try FileManager.default.copyItem(at: replacementSaveState.fileURL, to: saveState.fileURL)
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
print(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
self.emulatorCore?.saveSaveState(to: saveState.fileURL)
|
self.emulatorCore?.saveSaveState(to: saveState.fileURL)
|
||||||
|
}
|
||||||
|
|
||||||
if
|
if
|
||||||
let outputImage = self.gameView.outputImage,
|
let outputImage = self.gameView.outputImage,
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user