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 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? {
|
override var game: GameProtocol? {
|
||||||
willSet {
|
willSet {
|
||||||
@ -53,6 +60,10 @@ class PreviewGameViewController: DeltaCore.GameViewController
|
|||||||
|
|
||||||
deinit
|
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)
|
self.emulatorCore?.removeObserver(self, forKeyPath: #keyPath(EmulatorCore.state), context: &kvoContext)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -71,6 +82,13 @@ extension PreviewGameViewController
|
|||||||
self.emulatorCore?.remove(self.gameView)
|
self.emulatorCore?.remove(self.gameView)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override func viewWillAppear(_ animated: Bool)
|
||||||
|
{
|
||||||
|
super.viewWillAppear(animated)
|
||||||
|
|
||||||
|
self.copySaveFiles()
|
||||||
|
}
|
||||||
|
|
||||||
override func viewDidAppear(_ animated: Bool)
|
override func viewDidAppear(_ animated: Bool)
|
||||||
{
|
{
|
||||||
super.viewDidAppear(animated)
|
super.viewDidAppear(animated)
|
||||||
@ -88,6 +106,19 @@ extension PreviewGameViewController
|
|||||||
self.emulatorCore?.pause()
|
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()
|
override func viewDidLayoutSubviews()
|
||||||
{
|
{
|
||||||
super.viewDidLayoutSubviews()
|
super.viewDidLayoutSubviews()
|
||||||
@ -112,13 +143,21 @@ extension PreviewGameViewController
|
|||||||
let state = self.emulatorCore?.state
|
let state = self.emulatorCore?.state
|
||||||
else { return }
|
else { return }
|
||||||
|
|
||||||
if previousState == .stopped, state == .running
|
switch state
|
||||||
{
|
{
|
||||||
|
case .running where previousState == .stopped:
|
||||||
self.emulatorCoreQueue.async {
|
self.emulatorCoreQueue.async {
|
||||||
// Pause to prevent it from starting before visible (in case user peeked slowly)
|
// Pause to prevent it from starting before visible (in case user peeked slowly)
|
||||||
self.emulatorCore?.pause()
|
self.emulatorCore?.pause()
|
||||||
self.preparePreview()
|
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()
|
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