Fixes overwriting save file when previewing games
This commit is contained in:
parent
e11e4437c5
commit
75869c06fd
@ -28,6 +28,13 @@ class PreviewGameViewController: DeltaCore.GameViewController
|
||||
}
|
||||
|
||||
private var emulatorCoreQueue = DispatchQueue(label: "com.rileytestut.Delta.PreviewGameViewController.emulatorCoreQueue", qos: .userInitiated)
|
||||
private var copiedSaveFiles = [(originalURL: URL, copyURL: URL)]()
|
||||
|
||||
private lazy var temporaryDirectoryURL: URL = {
|
||||
let directoryURL = FileManager.default.temporaryDirectory.appendingPathComponent("preview-" + UUID().uuidString)
|
||||
try? FileManager.default.createDirectory(at: directoryURL, withIntermediateDirectories: true, attributes: nil)
|
||||
return directoryURL
|
||||
}()
|
||||
|
||||
override var game: GameProtocol? {
|
||||
willSet {
|
||||
@ -53,6 +60,10 @@ class PreviewGameViewController: DeltaCore.GameViewController
|
||||
|
||||
deinit
|
||||
{
|
||||
// Explicitly stop emulatorCore _before_ we remove ourselves as observer
|
||||
// so we can wait until stopped before restoring save files (again).
|
||||
self.emulatorCore?.stop()
|
||||
|
||||
self.emulatorCore?.removeObserver(self, forKeyPath: #keyPath(EmulatorCore.state), context: &kvoContext)
|
||||
}
|
||||
}
|
||||
@ -70,6 +81,13 @@ extension PreviewGameViewController
|
||||
// Temporarily prevent emulatorCore from updating gameView to prevent flicker of black, or other visual glitches
|
||||
self.emulatorCore?.remove(self.gameView)
|
||||
}
|
||||
|
||||
override func viewWillAppear(_ animated: Bool)
|
||||
{
|
||||
super.viewWillAppear(animated)
|
||||
|
||||
self.copySaveFiles()
|
||||
}
|
||||
|
||||
override func viewDidAppear(_ animated: Bool)
|
||||
{
|
||||
@ -88,6 +106,19 @@ extension PreviewGameViewController
|
||||
self.emulatorCore?.pause()
|
||||
}
|
||||
|
||||
override func viewDidDisappear(_ animated: Bool)
|
||||
{
|
||||
super.viewDidDisappear(animated)
|
||||
|
||||
// Already stopped = we've already restored save files and removed directory.
|
||||
if self.emulatorCore?.state != .stopped
|
||||
{
|
||||
// Pre-emptively restore save files in case something goes wrong while stopping emulation.
|
||||
// This also ensures if the core is never stopped (for some reason), saves are still restored.
|
||||
self.restoreSaveFiles(removeCopyDirectory: false)
|
||||
}
|
||||
}
|
||||
|
||||
override func viewDidLayoutSubviews()
|
||||
{
|
||||
super.viewDidLayoutSubviews()
|
||||
@ -112,13 +143,21 @@ extension PreviewGameViewController
|
||||
let state = self.emulatorCore?.state
|
||||
else { return }
|
||||
|
||||
if previousState == .stopped, state == .running
|
||||
switch state
|
||||
{
|
||||
case .running where previousState == .stopped:
|
||||
self.emulatorCoreQueue.async {
|
||||
// Pause to prevent it from starting before visible (in case user peeked slowly)
|
||||
self.emulatorCore?.pause()
|
||||
self.preparePreview()
|
||||
}
|
||||
|
||||
case .stopped:
|
||||
// Emulation has stopped, so we can safely restore save files,
|
||||
// and also remove the directory they were copied to.
|
||||
self.restoreSaveFiles(removeCopyDirectory: true)
|
||||
|
||||
default: break
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -172,4 +211,56 @@ private extension PreviewGameViewController
|
||||
|
||||
self.emulatorCore?.resume()
|
||||
}
|
||||
|
||||
func copySaveFiles()
|
||||
{
|
||||
guard let game = self.game as? Game, let gameSave = game.gameSave else { return }
|
||||
|
||||
self.copiedSaveFiles.removeAll()
|
||||
|
||||
let fileURLs = gameSave.syncableFiles.lazy.map { $0.fileURL }
|
||||
for fileURL in fileURLs
|
||||
{
|
||||
do
|
||||
{
|
||||
let destinationURL = self.temporaryDirectoryURL.appendingPathComponent(fileURL.lastPathComponent)
|
||||
try FileManager.default.copyItem(at: fileURL, to: destinationURL, shouldReplace: true)
|
||||
|
||||
self.copiedSaveFiles.append((fileURL, destinationURL))
|
||||
print("Copied save file:", fileURL.lastPathComponent)
|
||||
}
|
||||
catch
|
||||
{
|
||||
print("Failed to back up save file \(fileURL.lastPathComponent).", error)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func restoreSaveFiles(removeCopyDirectory: Bool)
|
||||
{
|
||||
for (originalURL, copyURL) in self.copiedSaveFiles
|
||||
{
|
||||
do
|
||||
{
|
||||
try FileManager.default.copyItem(at: copyURL, to: originalURL, shouldReplace: true)
|
||||
print("Restored save file:", originalURL.lastPathComponent)
|
||||
}
|
||||
catch
|
||||
{
|
||||
print("Failed to restore copied save file \(copyURL.lastPathComponent).", error)
|
||||
}
|
||||
}
|
||||
|
||||
if removeCopyDirectory
|
||||
{
|
||||
do
|
||||
{
|
||||
try FileManager.default.removeItem(at: self.temporaryDirectoryURL)
|
||||
}
|
||||
catch
|
||||
{
|
||||
print("Failed to remove preview temporary directory.", error)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user