Adds support for handling ActionInputs from GameControllers
• Quick Save • Quick Load • Fast Forward
This commit is contained in:
parent
c6875c44b6
commit
61440ef994
@ -1 +1 @@
|
|||||||
Subproject commit 5d0d2d40b7f7797b3bb270241c7d6a0c16abe4bc
|
Subproject commit ff014bab5c42e5c0a5fcbacb5c3c737ef33564e7
|
||||||
@ -52,7 +52,6 @@
|
|||||||
BF59426B1E09BBD00051894B /* GridCollectionViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5942691E09BBD00051894B /* GridCollectionViewLayout.swift */; };
|
BF59426B1E09BBD00051894B /* GridCollectionViewLayout.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5942691E09BBD00051894B /* GridCollectionViewLayout.swift */; };
|
||||||
BF59426F1E09BC5D0051894B /* DatabaseManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF59426D1E09BC5D0051894B /* DatabaseManager.swift */; };
|
BF59426F1E09BC5D0051894B /* DatabaseManager.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF59426D1E09BC5D0051894B /* DatabaseManager.swift */; };
|
||||||
BF5942701E09BC5D0051894B /* GamesDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF59426E1E09BC5D0051894B /* GamesDatabase.swift */; };
|
BF5942701E09BC5D0051894B /* GamesDatabase.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF59426E1E09BC5D0051894B /* GamesDatabase.swift */; };
|
||||||
BF5942731E09BC700051894B /* Delta.xcdatamodel in Sources */ = {isa = PBXBuildFile; fileRef = BF5942721E09BC700051894B /* Delta.xcdatamodel */; };
|
|
||||||
BF59427C1E09BC830051894B /* Cheat.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5942771E09BC830051894B /* Cheat.swift */; };
|
BF59427C1E09BC830051894B /* Cheat.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5942771E09BC830051894B /* Cheat.swift */; };
|
||||||
BF59427D1E09BC830051894B /* ControllerSkin.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5942781E09BC830051894B /* ControllerSkin.swift */; };
|
BF59427D1E09BC830051894B /* ControllerSkin.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5942781E09BC830051894B /* ControllerSkin.swift */; };
|
||||||
BF59427E1E09BC830051894B /* Game.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5942791E09BC830051894B /* Game.swift */; };
|
BF59427E1E09BC830051894B /* Game.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF5942791E09BC830051894B /* Game.swift */; };
|
||||||
@ -104,11 +103,14 @@
|
|||||||
BFC9B7391CEFCD34008629BB /* CheatsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC9B7381CEFCD34008629BB /* CheatsViewController.swift */; };
|
BFC9B7391CEFCD34008629BB /* CheatsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFC9B7381CEFCD34008629BB /* CheatsViewController.swift */; };
|
||||||
BFCEA67E1D56FF640061A534 /* UIViewControllerContextTransitioning+Conveniences.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFCEA67D1D56FF640061A534 /* UIViewControllerContextTransitioning+Conveniences.swift */; };
|
BFCEA67E1D56FF640061A534 /* UIViewControllerContextTransitioning+Conveniences.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFCEA67D1D56FF640061A534 /* UIViewControllerContextTransitioning+Conveniences.swift */; };
|
||||||
BFD097211D3A01B8005A44C2 /* SaveStatesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF3540041C5DA70400C1184C /* SaveStatesViewController.swift */; };
|
BFD097211D3A01B8005A44C2 /* SaveStatesViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF3540041C5DA70400C1184C /* SaveStatesViewController.swift */; };
|
||||||
|
BFDC7B9F1F7DE0CF0052A7C5 /* Delta.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = BFDC7B9E1F7DE0CF0052A7C5 /* Delta.xcmappingmodel */; };
|
||||||
BFDD04F11D5E2C27002D450E /* GameCollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFDD04F01D5E2C27002D450E /* GameCollectionViewController.swift */; };
|
BFDD04F11D5E2C27002D450E /* GameCollectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFDD04F01D5E2C27002D450E /* GameCollectionViewController.swift */; };
|
||||||
BFE022A01F5B57FF0052D888 /* PopoverMenuButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFE0229F1F5B577D0052D888 /* PopoverMenuButton.swift */; };
|
BFE022A01F5B57FF0052D888 /* PopoverMenuButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFE0229F1F5B577D0052D888 /* PopoverMenuButton.swift */; };
|
||||||
BFE4269E1D9C68E600DC913F /* SaveStatesStoryboardSegue.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFE4269D1D9C68E600DC913F /* SaveStatesStoryboardSegue.swift */; };
|
BFE4269E1D9C68E600DC913F /* SaveStatesStoryboardSegue.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFE4269D1D9C68E600DC913F /* SaveStatesStoryboardSegue.swift */; };
|
||||||
BFEC732D1AAECC4A00650035 /* Roxas.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BFEC732C1AAECC4A00650035 /* Roxas.framework */; };
|
BFEC732D1AAECC4A00650035 /* Roxas.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BFEC732C1AAECC4A00650035 /* Roxas.framework */; };
|
||||||
BFEC732E1AAECC4A00650035 /* Roxas.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = BFEC732C1AAECC4A00650035 /* Roxas.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
BFEC732E1AAECC4A00650035 /* Roxas.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = BFEC732C1AAECC4A00650035 /* Roxas.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||||
|
BFEF24EF1F7DD3F100454C62 /* Delta.xcdatamodeld in Sources */ = {isa = PBXBuildFile; fileRef = BFEF24EC1F7DD3F100454C62 /* Delta.xcdatamodeld */; };
|
||||||
|
BFEF24F31F7DD4FD00454C62 /* SaveStateMigrationPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFEF24F21F7DD4FB00454C62 /* SaveStateMigrationPolicy.swift */; };
|
||||||
BFF0742C1E9DC17500ACDF4A /* GBCDeltaCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BFF0742B1E9DC17500ACDF4A /* GBCDeltaCore.framework */; };
|
BFF0742C1E9DC17500ACDF4A /* GBCDeltaCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = BFF0742B1E9DC17500ACDF4A /* GBCDeltaCore.framework */; };
|
||||||
BFF0742D1E9DC17500ACDF4A /* GBCDeltaCore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = BFF0742B1E9DC17500ACDF4A /* GBCDeltaCore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
BFF0742D1E9DC17500ACDF4A /* GBCDeltaCore.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = BFF0742B1E9DC17500ACDF4A /* GBCDeltaCore.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
|
||||||
BFF6452E1F7CC5060056533E /* GameControllerInputMappingTransformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF6B82A41F7CC2A300042BFB /* GameControllerInputMappingTransformer.swift */; };
|
BFF6452E1F7CC5060056533E /* GameControllerInputMappingTransformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF6B82A41F7CC2A300042BFB /* GameControllerInputMappingTransformer.swift */; };
|
||||||
@ -180,7 +182,6 @@
|
|||||||
BF5942691E09BBD00051894B /* GridCollectionViewLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GridCollectionViewLayout.swift; path = "Components/Collection View/GridCollectionViewLayout.swift"; sourceTree = "<group>"; };
|
BF5942691E09BBD00051894B /* GridCollectionViewLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GridCollectionViewLayout.swift; path = "Components/Collection View/GridCollectionViewLayout.swift"; sourceTree = "<group>"; };
|
||||||
BF59426D1E09BC5D0051894B /* DatabaseManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DatabaseManager.swift; path = Database/DatabaseManager.swift; sourceTree = "<group>"; };
|
BF59426D1E09BC5D0051894B /* DatabaseManager.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = DatabaseManager.swift; path = Database/DatabaseManager.swift; sourceTree = "<group>"; };
|
||||||
BF59426E1E09BC5D0051894B /* GamesDatabase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GamesDatabase.swift; path = Database/OpenVGDB/GamesDatabase.swift; sourceTree = "<group>"; };
|
BF59426E1E09BC5D0051894B /* GamesDatabase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GamesDatabase.swift; path = Database/OpenVGDB/GamesDatabase.swift; sourceTree = "<group>"; };
|
||||||
BF5942721E09BC700051894B /* Delta.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; name = Delta.xcdatamodel; path = Database/Model/Delta.xcdatamodel; sourceTree = "<group>"; };
|
|
||||||
BF5942771E09BC830051894B /* Cheat.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Cheat.swift; path = Database/Model/Human/Cheat.swift; sourceTree = "<group>"; };
|
BF5942771E09BC830051894B /* Cheat.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Cheat.swift; path = Database/Model/Human/Cheat.swift; sourceTree = "<group>"; };
|
||||||
BF5942781E09BC830051894B /* ControllerSkin.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ControllerSkin.swift; path = Database/Model/Human/ControllerSkin.swift; sourceTree = "<group>"; };
|
BF5942781E09BC830051894B /* ControllerSkin.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = ControllerSkin.swift; path = Database/Model/Human/ControllerSkin.swift; sourceTree = "<group>"; };
|
||||||
BF5942791E09BC830051894B /* Game.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Game.swift; path = Database/Model/Human/Game.swift; sourceTree = "<group>"; };
|
BF5942791E09BC830051894B /* Game.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = Game.swift; path = Database/Model/Human/Game.swift; sourceTree = "<group>"; };
|
||||||
@ -232,10 +233,14 @@
|
|||||||
BFC6F7B71F435BC500221B96 /* Input+Display.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Input+Display.swift"; sourceTree = "<group>"; };
|
BFC6F7B71F435BC500221B96 /* Input+Display.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "Input+Display.swift"; sourceTree = "<group>"; };
|
||||||
BFC9B7381CEFCD34008629BB /* CheatsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CheatsViewController.swift; path = "Pause Menu/Cheats/CheatsViewController.swift"; sourceTree = "<group>"; };
|
BFC9B7381CEFCD34008629BB /* CheatsViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CheatsViewController.swift; path = "Pause Menu/Cheats/CheatsViewController.swift"; sourceTree = "<group>"; };
|
||||||
BFCEA67D1D56FF640061A534 /* UIViewControllerContextTransitioning+Conveniences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIViewControllerContextTransitioning+Conveniences.swift"; sourceTree = "<group>"; };
|
BFCEA67D1D56FF640061A534 /* UIViewControllerContextTransitioning+Conveniences.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIViewControllerContextTransitioning+Conveniences.swift"; sourceTree = "<group>"; };
|
||||||
|
BFDC7B9E1F7DE0CF0052A7C5 /* Delta.xcmappingmodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcmappingmodel; name = Delta.xcmappingmodel; path = Database/Model/Migrations/Delta.xcmappingmodel; sourceTree = "<group>"; };
|
||||||
BFDD04F01D5E2C27002D450E /* GameCollectionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GameCollectionViewController.swift; sourceTree = "<group>"; };
|
BFDD04F01D5E2C27002D450E /* GameCollectionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GameCollectionViewController.swift; sourceTree = "<group>"; };
|
||||||
BFE0229F1F5B577D0052D888 /* PopoverMenuButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = PopoverMenuButton.swift; path = "Components/Popover Menu/PopoverMenuButton.swift"; sourceTree = "<group>"; };
|
BFE0229F1F5B577D0052D888 /* PopoverMenuButton.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = PopoverMenuButton.swift; path = "Components/Popover Menu/PopoverMenuButton.swift"; sourceTree = "<group>"; };
|
||||||
BFE4269D1D9C68E600DC913F /* SaveStatesStoryboardSegue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SaveStatesStoryboardSegue.swift; path = Segues/SaveStatesStoryboardSegue.swift; sourceTree = "<group>"; };
|
BFE4269D1D9C68E600DC913F /* SaveStatesStoryboardSegue.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = SaveStatesStoryboardSegue.swift; path = Segues/SaveStatesStoryboardSegue.swift; sourceTree = "<group>"; };
|
||||||
BFEC732C1AAECC4A00650035 /* Roxas.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Roxas.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
BFEC732C1AAECC4A00650035 /* Roxas.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Roxas.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
|
BFEF24ED1F7DD3F100454C62 /* Delta 2.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = "Delta 2.xcdatamodel"; sourceTree = "<group>"; };
|
||||||
|
BFEF24EE1F7DD3F100454C62 /* Delta.xcdatamodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcdatamodel; path = Delta.xcdatamodel; sourceTree = "<group>"; };
|
||||||
|
BFEF24F21F7DD4FB00454C62 /* SaveStateMigrationPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; name = SaveStateMigrationPolicy.swift; path = Database/Model/Migrations/Policies/SaveStateMigrationPolicy.swift; sourceTree = "<group>"; };
|
||||||
BFF0742B1E9DC17500ACDF4A /* GBCDeltaCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = GBCDeltaCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
BFF0742B1E9DC17500ACDF4A /* GBCDeltaCore.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = GBCDeltaCore.framework; sourceTree = BUILT_PRODUCTS_DIR; };
|
||||||
BFF93A9F1E0FB036005EC865 /* InputStreamOutputWriter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = InputStreamOutputWriter.swift; path = Database/InputStreamOutputWriter.swift; sourceTree = "<group>"; };
|
BFF93A9F1E0FB036005EC865 /* InputStreamOutputWriter.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = InputStreamOutputWriter.swift; path = Database/InputStreamOutputWriter.swift; sourceTree = "<group>"; };
|
||||||
BFFA4C081E8A24D600D87934 /* GameMetadataTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GameMetadataTableViewCell.swift; path = Database/OpenVGDB/GameMetadataTableViewCell.swift; sourceTree = "<group>"; };
|
BFFA4C081E8A24D600D87934 /* GameMetadataTableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = GameMetadataTableViewCell.swift; path = Database/OpenVGDB/GameMetadataTableViewCell.swift; sourceTree = "<group>"; };
|
||||||
@ -381,10 +386,11 @@
|
|||||||
BF5942711E09BC690051894B /* Model */ = {
|
BF5942711E09BC690051894B /* Model */ = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
BF5942721E09BC700051894B /* Delta.xcdatamodel */,
|
BFEF24EC1F7DD3F100454C62 /* Delta.xcdatamodeld */,
|
||||||
BF5942741E09BC740051894B /* Human */,
|
BF5942741E09BC740051894B /* Human */,
|
||||||
BF5942751E09BC780051894B /* Machine */,
|
BF5942751E09BC780051894B /* Machine */,
|
||||||
BF6B82A31F7CC29A00042BFB /* Transformers */,
|
BF6B82A31F7CC29A00042BFB /* Transformers */,
|
||||||
|
BFEF24F01F7DD4B600454C62 /* Migrations */,
|
||||||
BF5942761E09BC7C0051894B /* Misc */,
|
BF5942761E09BC7C0051894B /* Misc */,
|
||||||
);
|
);
|
||||||
name = Model;
|
name = Model;
|
||||||
@ -565,6 +571,23 @@
|
|||||||
path = Resources;
|
path = Resources;
|
||||||
sourceTree = "<group>";
|
sourceTree = "<group>";
|
||||||
};
|
};
|
||||||
|
BFEF24F01F7DD4B600454C62 /* Migrations */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
BFDC7B9E1F7DE0CF0052A7C5 /* Delta.xcmappingmodel */,
|
||||||
|
BFEF24F11F7DD4BE00454C62 /* Policies */,
|
||||||
|
);
|
||||||
|
name = Migrations;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
|
BFEF24F11F7DD4BE00454C62 /* Policies */ = {
|
||||||
|
isa = PBXGroup;
|
||||||
|
children = (
|
||||||
|
BFEF24F21F7DD4FB00454C62 /* SaveStateMigrationPolicy.swift */,
|
||||||
|
);
|
||||||
|
name = Policies;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
};
|
||||||
BFFA71CE1AAC406100EE9DD1 = {
|
BFFA71CE1AAC406100EE9DD1 = {
|
||||||
isa = PBXGroup;
|
isa = PBXGroup;
|
||||||
children = (
|
children = (
|
||||||
@ -844,7 +867,6 @@
|
|||||||
BF6BF3131EB7E47F008E83CD /* ImportOption.swift in Sources */,
|
BF6BF3131EB7E47F008E83CD /* ImportOption.swift in Sources */,
|
||||||
BF31878B1D489AAA00BD020D /* CheatValidator.swift in Sources */,
|
BF31878B1D489AAA00BD020D /* CheatValidator.swift in Sources */,
|
||||||
BFFC46201D59823500AF2CC6 /* InitialGamesStoryboardSegue.swift in Sources */,
|
BFFC46201D59823500AF2CC6 /* InitialGamesStoryboardSegue.swift in Sources */,
|
||||||
BF5942731E09BC700051894B /* Delta.xcdatamodel in Sources */,
|
|
||||||
BF15AF841F54B43B009B6AAB /* ActionInput.swift in Sources */,
|
BF15AF841F54B43B009B6AAB /* ActionInput.swift in Sources */,
|
||||||
BF5942951E09BD1A0051894B /* NSManagedObjectContext+Conveniences.swift in Sources */,
|
BF5942951E09BD1A0051894B /* NSManagedObjectContext+Conveniences.swift in Sources */,
|
||||||
BF353FF91C5D870B00C1184C /* MenuItem.swift in Sources */,
|
BF353FF91C5D870B00C1184C /* MenuItem.swift in Sources */,
|
||||||
@ -854,6 +876,7 @@
|
|||||||
BFFA71DD1AAC406100EE9DD1 /* AppDelegate.swift in Sources */,
|
BFFA71DD1AAC406100EE9DD1 /* AppDelegate.swift in Sources */,
|
||||||
BF59426B1E09BBD00051894B /* GridCollectionViewLayout.swift in Sources */,
|
BF59426B1E09BBD00051894B /* GridCollectionViewLayout.swift in Sources */,
|
||||||
BF6424851F5CBDC900D6AB44 /* UIView+ParentViewController.swift in Sources */,
|
BF6424851F5CBDC900D6AB44 /* UIView+ParentViewController.swift in Sources */,
|
||||||
|
BFDC7B9F1F7DE0CF0052A7C5 /* Delta.xcmappingmodel in Sources */,
|
||||||
BF04E6FF1DB8625C000F35D3 /* ControllerSkinsViewController.swift in Sources */,
|
BF04E6FF1DB8625C000F35D3 /* ControllerSkinsViewController.swift in Sources */,
|
||||||
BF5942891E09BC8B0051894B /* _GameCollection.swift in Sources */,
|
BF5942891E09BC8B0051894B /* _GameCollection.swift in Sources */,
|
||||||
BF34FA111CF1899D006624C7 /* CheatTextView.swift in Sources */,
|
BF34FA111CF1899D006624C7 /* CheatTextView.swift in Sources */,
|
||||||
@ -878,6 +901,7 @@
|
|||||||
BF80E1D21F13117000847008 /* ControllerInputsViewController.swift in Sources */,
|
BF80E1D21F13117000847008 /* ControllerInputsViewController.swift in Sources */,
|
||||||
BF5942641E09BBB10051894B /* LoadControllerSkinImageOperation.swift in Sources */,
|
BF5942641E09BBB10051894B /* LoadControllerSkinImageOperation.swift in Sources */,
|
||||||
BF6EE5E91F7C5F860051AD6C /* _GameControllerInputMapping.swift in Sources */,
|
BF6EE5E91F7C5F860051AD6C /* _GameControllerInputMapping.swift in Sources */,
|
||||||
|
BFEF24EF1F7DD3F100454C62 /* Delta.xcdatamodeld in Sources */,
|
||||||
BF5942871E09BC8B0051894B /* _ControllerSkin.swift in Sources */,
|
BF5942871E09BC8B0051894B /* _ControllerSkin.swift in Sources */,
|
||||||
BF95E2791E4982A10030E7AD /* GamesDatabaseBrowserViewController.swift in Sources */,
|
BF95E2791E4982A10030E7AD /* GamesDatabaseBrowserViewController.swift in Sources */,
|
||||||
BFD097211D3A01B8005A44C2 /* SaveStatesViewController.swift in Sources */,
|
BFD097211D3A01B8005A44C2 /* SaveStatesViewController.swift in Sources */,
|
||||||
@ -895,6 +919,7 @@
|
|||||||
BF5942861E09BC8B0051894B /* _Cheat.swift in Sources */,
|
BF5942861E09BC8B0051894B /* _Cheat.swift in Sources */,
|
||||||
BF5E7F441B9A650B00AE44F8 /* SettingsViewController.swift in Sources */,
|
BF5E7F441B9A650B00AE44F8 /* SettingsViewController.swift in Sources */,
|
||||||
BF8CA9361F5F651900499FDD /* PopoverMenuController.swift in Sources */,
|
BF8CA9361F5F651900499FDD /* PopoverMenuController.swift in Sources */,
|
||||||
|
BFEF24F31F7DD4FD00454C62 /* SaveStateMigrationPolicy.swift in Sources */,
|
||||||
BF5942931E09BD1A0051894B /* NSFetchedResultsController+Conveniences.m in Sources */,
|
BF5942931E09BD1A0051894B /* NSFetchedResultsController+Conveniences.m in Sources */,
|
||||||
BF6BF3271EB87EB8008E83CD /* PhotoLibraryImportOption.swift in Sources */,
|
BF6BF3271EB87EB8008E83CD /* PhotoLibraryImportOption.swift in Sources */,
|
||||||
BF5942661E09BBB10051894B /* LoadImageURLOperation.swift in Sources */,
|
BF5942661E09BBB10051894B /* LoadImageURLOperation.swift in Sources */,
|
||||||
@ -1129,6 +1154,21 @@
|
|||||||
defaultConfigurationName = Release;
|
defaultConfigurationName = Release;
|
||||||
};
|
};
|
||||||
/* End XCConfigurationList section */
|
/* End XCConfigurationList section */
|
||||||
|
|
||||||
|
/* Begin XCVersionGroup section */
|
||||||
|
BFEF24EC1F7DD3F100454C62 /* Delta.xcdatamodeld */ = {
|
||||||
|
isa = XCVersionGroup;
|
||||||
|
children = (
|
||||||
|
BFEF24ED1F7DD3F100454C62 /* Delta 2.xcdatamodel */,
|
||||||
|
BFEF24EE1F7DD3F100454C62 /* Delta.xcdatamodel */,
|
||||||
|
);
|
||||||
|
currentVersion = BFEF24ED1F7DD3F100454C62 /* Delta 2.xcdatamodel */;
|
||||||
|
name = Delta.xcdatamodeld;
|
||||||
|
path = Database/Model/Delta.xcdatamodeld;
|
||||||
|
sourceTree = "<group>";
|
||||||
|
versionGroupType = wrapper.xcdatamodel;
|
||||||
|
};
|
||||||
|
/* End XCVersionGroup section */
|
||||||
};
|
};
|
||||||
rootObject = BFFA71CF1AAC406100EE9DD1 /* Project object */;
|
rootObject = BFFA71CF1AAC406100EE9DD1 /* Project object */;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -65,11 +65,10 @@ final class DatabaseManager: NSPersistentContainer
|
|||||||
private init()
|
private init()
|
||||||
{
|
{
|
||||||
guard
|
guard
|
||||||
let modelURL = Bundle(for: DatabaseManager.self).url(forResource: "Delta", withExtension: "mom"),
|
let modelURL = Bundle(for: DatabaseManager.self).url(forResource: "Delta", withExtension: "momd"),
|
||||||
let managedObjectModel = NSManagedObjectModel(contentsOf: modelURL)
|
let managedObjectModel = NSManagedObjectModel(contentsOf: modelURL)
|
||||||
else { fatalError("Core Data model cannot be found. Aborting.") }
|
else { fatalError("Core Data model cannot be found. Aborting.") }
|
||||||
|
|
||||||
|
|
||||||
super.init(name: "Delta", managedObjectModel: managedObjectModel)
|
super.init(name: "Delta", managedObjectModel: managedObjectModel)
|
||||||
|
|
||||||
self.viewContext.automaticallyMergesChangesFromParent = true
|
self.viewContext.automaticallyMergesChangesFromParent = true
|
||||||
|
|||||||
@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>_XCCurrentVersionName</key>
|
||||||
|
<string>Delta 2.xcdatamodel</string>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
||||||
@ -0,0 +1,138 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
|
||||||
|
<model type="com.apple.IDECoreDataModeler.DataModel" documentVersion="1.0" lastSavedToolsVersion="13240" systemVersion="16G29" minimumToolsVersion="Xcode 7.0" sourceLanguage="Objective-C" userDefinedModelVersionIdentifier="1.0">
|
||||||
|
<entity name="Cheat" representedClassName="Cheat" syncable="YES">
|
||||||
|
<attribute name="code" attributeType="String" syncable="YES"/>
|
||||||
|
<attribute name="creationDate" attributeType="Date" usesScalarValueType="NO" syncable="YES"/>
|
||||||
|
<attribute name="identifier" attributeType="String" syncable="YES"/>
|
||||||
|
<attribute name="isEnabled" attributeType="Boolean" defaultValueString="YES" usesScalarValueType="NO" syncable="YES"/>
|
||||||
|
<attribute name="modifiedDate" attributeType="Date" usesScalarValueType="NO" syncable="YES"/>
|
||||||
|
<attribute name="name" optional="YES" attributeType="String" syncable="YES"/>
|
||||||
|
<attribute name="type" attributeType="Transformable" syncable="YES">
|
||||||
|
<userInfo>
|
||||||
|
<entry key="attributeValueClassName" value="CheatType"/>
|
||||||
|
</userInfo>
|
||||||
|
</attribute>
|
||||||
|
<relationship name="game" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Game" inverseName="cheats" inverseEntity="Game" syncable="YES"/>
|
||||||
|
<uniquenessConstraints>
|
||||||
|
<uniquenessConstraint>
|
||||||
|
<constraint value="identifier"/>
|
||||||
|
</uniquenessConstraint>
|
||||||
|
</uniquenessConstraints>
|
||||||
|
</entity>
|
||||||
|
<entity name="ControllerSkin" representedClassName="ControllerSkin" syncable="YES">
|
||||||
|
<attribute name="filename" attributeType="String" syncable="YES"/>
|
||||||
|
<attribute name="gameType" attributeType="Transformable" syncable="YES">
|
||||||
|
<userInfo>
|
||||||
|
<entry key="attributeValueClassName" value="GameType"/>
|
||||||
|
</userInfo>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="identifier" attributeType="String" syncable="YES"/>
|
||||||
|
<attribute name="isStandard" attributeType="Boolean" defaultValueString="NO" usesScalarValueType="YES" syncable="YES"/>
|
||||||
|
<attribute name="name" attributeType="String" syncable="YES"/>
|
||||||
|
<attribute name="supportedConfigurations" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="YES" syncable="YES">
|
||||||
|
<userInfo>
|
||||||
|
<entry key="attributeValueScalarType" value="ControllerSkinConfigurations"/>
|
||||||
|
</userInfo>
|
||||||
|
</attribute>
|
||||||
|
<uniquenessConstraints>
|
||||||
|
<uniquenessConstraint>
|
||||||
|
<constraint value="identifier"/>
|
||||||
|
<constraint value="gameType"/>
|
||||||
|
</uniquenessConstraint>
|
||||||
|
</uniquenessConstraints>
|
||||||
|
</entity>
|
||||||
|
<entity name="Game" representedClassName="Game" syncable="YES">
|
||||||
|
<attribute name="artworkURL" optional="YES" attributeType="Transformable" syncable="YES">
|
||||||
|
<userInfo>
|
||||||
|
<entry key="attributeValueClassName" value="URL"/>
|
||||||
|
</userInfo>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="filename" attributeType="String" syncable="YES">
|
||||||
|
<userInfo>
|
||||||
|
<entry key="attributeValueClassName" value="NSURL"/>
|
||||||
|
</userInfo>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="identifier" attributeType="String" syncable="YES"/>
|
||||||
|
<attribute name="name" attributeType="String" syncable="YES"/>
|
||||||
|
<attribute name="type" attributeType="Transformable" syncable="YES">
|
||||||
|
<userInfo>
|
||||||
|
<entry key="attributeValueClassName" value="GameType"/>
|
||||||
|
</userInfo>
|
||||||
|
</attribute>
|
||||||
|
<relationship name="cheats" toMany="YES" deletionRule="Cascade" destinationEntity="Cheat" inverseName="game" inverseEntity="Cheat" syncable="YES"/>
|
||||||
|
<relationship name="gameCollections" toMany="YES" deletionRule="Nullify" destinationEntity="GameCollection" inverseName="games" inverseEntity="GameCollection" syncable="YES"/>
|
||||||
|
<relationship name="previewSaveState" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="SaveState" inverseName="previewGame" inverseEntity="SaveState" syncable="YES"/>
|
||||||
|
<relationship name="saveStates" toMany="YES" deletionRule="Cascade" destinationEntity="SaveState" inverseName="game" inverseEntity="SaveState" syncable="YES"/>
|
||||||
|
<uniquenessConstraints>
|
||||||
|
<uniquenessConstraint>
|
||||||
|
<constraint value="identifier"/>
|
||||||
|
</uniquenessConstraint>
|
||||||
|
</uniquenessConstraints>
|
||||||
|
</entity>
|
||||||
|
<entity name="GameCollection" representedClassName="GameCollection" syncable="YES">
|
||||||
|
<attribute name="identifier" attributeType="String" syncable="YES"/>
|
||||||
|
<attribute name="index" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="NO" syncable="YES"/>
|
||||||
|
<relationship name="games" toMany="YES" deletionRule="Nullify" destinationEntity="Game" inverseName="gameCollections" inverseEntity="Game" syncable="YES"/>
|
||||||
|
<uniquenessConstraints>
|
||||||
|
<uniquenessConstraint>
|
||||||
|
<constraint value="identifier"/>
|
||||||
|
</uniquenessConstraint>
|
||||||
|
</uniquenessConstraints>
|
||||||
|
</entity>
|
||||||
|
<entity name="GameControllerInputMapping" representedClassName="GameControllerInputMapping" syncable="YES">
|
||||||
|
<attribute name="deltaCoreInputMapping" attributeType="Transformable" valueTransformerName="GameControllerInputMappingTransformer" syncable="YES">
|
||||||
|
<userInfo>
|
||||||
|
<entry key="attributeValueClassName" value="Any"/>
|
||||||
|
</userInfo>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="gameControllerInputType" attributeType="Transformable" valueTransformerName="" syncable="YES">
|
||||||
|
<userInfo>
|
||||||
|
<entry key="attributeValueClassName" value="GameControllerInputType"/>
|
||||||
|
</userInfo>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="gameType" attributeType="Transformable" syncable="YES">
|
||||||
|
<userInfo>
|
||||||
|
<entry key="attributeValueClassName" value="GameType"/>
|
||||||
|
</userInfo>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="playerIndex" attributeType="Integer 16" defaultValueString="0" usesScalarValueType="NO" syncable="YES"/>
|
||||||
|
<uniquenessConstraints>
|
||||||
|
<uniquenessConstraint>
|
||||||
|
<constraint value="gameControllerInputType"/>
|
||||||
|
<constraint value="gameType"/>
|
||||||
|
<constraint value="playerIndex"/>
|
||||||
|
</uniquenessConstraint>
|
||||||
|
</uniquenessConstraints>
|
||||||
|
</entity>
|
||||||
|
<entity name="SaveState" representedClassName="SaveState" versionHashModifier="quick" syncable="YES">
|
||||||
|
<attribute name="creationDate" attributeType="Date" usesScalarValueType="NO" syncable="YES"/>
|
||||||
|
<attribute name="filename" attributeType="String" syncable="YES">
|
||||||
|
<userInfo>
|
||||||
|
<entry key="attributeValueClassName" value="NSURL"/>
|
||||||
|
</userInfo>
|
||||||
|
</attribute>
|
||||||
|
<attribute name="identifier" attributeType="String" syncable="YES"/>
|
||||||
|
<attribute name="modifiedDate" attributeType="Date" usesScalarValueType="NO" syncable="YES"/>
|
||||||
|
<attribute name="name" optional="YES" attributeType="String" syncable="YES"/>
|
||||||
|
<attribute name="type" attributeType="Integer 16" defaultValueString="1" usesScalarValueType="NO" syncable="YES">
|
||||||
|
<userInfo>
|
||||||
|
<entry key="attributeValueScalarType" value="SaveStateType"/>
|
||||||
|
</userInfo>
|
||||||
|
</attribute>
|
||||||
|
<relationship name="game" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Game" inverseName="saveStates" inverseEntity="Game" syncable="YES"/>
|
||||||
|
<relationship name="previewGame" optional="YES" maxCount="1" deletionRule="Nullify" destinationEntity="Game" inverseName="previewSaveState" inverseEntity="Game" syncable="YES"/>
|
||||||
|
<uniquenessConstraints>
|
||||||
|
<uniquenessConstraint>
|
||||||
|
<constraint value="identifier"/>
|
||||||
|
</uniquenessConstraint>
|
||||||
|
</uniquenessConstraints>
|
||||||
|
</entity>
|
||||||
|
<elements>
|
||||||
|
<element name="Cheat" positionX="-198" positionY="-63" width="128" height="165"/>
|
||||||
|
<element name="ControllerSkin" positionX="-387" positionY="90" width="128" height="135"/>
|
||||||
|
<element name="Game" positionX="-378" positionY="-54" width="128" height="180"/>
|
||||||
|
<element name="GameCollection" positionX="-585" positionY="-27" width="128" height="90"/>
|
||||||
|
<element name="GameControllerInputMapping" positionX="-387" positionY="90" width="128" height="105"/>
|
||||||
|
<element name="SaveState" positionX="-198" positionY="113" width="128" height="165"/>
|
||||||
|
</elements>
|
||||||
|
</model>
|
||||||
@ -13,6 +13,7 @@ import DeltaCore
|
|||||||
@objc public enum SaveStateType: Int16
|
@objc public enum SaveStateType: Int16
|
||||||
{
|
{
|
||||||
case auto
|
case auto
|
||||||
|
case quick
|
||||||
case general
|
case general
|
||||||
case locked
|
case locked
|
||||||
}
|
}
|
||||||
@ -78,4 +79,14 @@ public class SaveState: _SaveState, SaveStateProtocol
|
|||||||
print(error)
|
print(error)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class func fetchRequest(for game: Game, type: SaveStateType) -> NSFetchRequest<SaveState>
|
||||||
|
{
|
||||||
|
let predicate = NSPredicate(format: "%K == %@ AND %K == %d", #keyPath(SaveState.game), game, #keyPath(SaveState.type), type.rawValue)
|
||||||
|
|
||||||
|
let fetchRequest: NSFetchRequest<SaveState> = SaveState.fetchRequest()
|
||||||
|
fetchRequest.predicate = predicate
|
||||||
|
|
||||||
|
return fetchRequest
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@ -0,0 +1,25 @@
|
|||||||
|
//
|
||||||
|
// SaveStateMigrationPolicy.swift
|
||||||
|
// Delta
|
||||||
|
//
|
||||||
|
// Created by Riley Testut on 9/28/17.
|
||||||
|
// Copyright © 2017 Riley Testut. All rights reserved.
|
||||||
|
//
|
||||||
|
|
||||||
|
import UIKit
|
||||||
|
|
||||||
|
@objc(SaveStateToSaveStateMigrationPolicy)
|
||||||
|
class SaveStateToSaveStateMigrationPolicy: NSEntityMigrationPolicy
|
||||||
|
{
|
||||||
|
@objc(migrateSaveStateType:)
|
||||||
|
func migrateSaveStateType(_ rawValue: NSNumber) -> NSNumber
|
||||||
|
{
|
||||||
|
switch rawValue.intValue
|
||||||
|
{
|
||||||
|
case 0: return NSNumber(value: SaveStateType.auto.rawValue)
|
||||||
|
case 1: return NSNumber(value: SaveStateType.general.rawValue)
|
||||||
|
case 2: return NSNumber(value: SaveStateType.locked.rawValue)
|
||||||
|
default: return rawValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -15,8 +15,8 @@ public extension GameControllerInputType
|
|||||||
|
|
||||||
enum ActionInput: String
|
enum ActionInput: String
|
||||||
{
|
{
|
||||||
case saveState
|
case quickSave
|
||||||
case loadState
|
case quickLoad
|
||||||
case fastForward
|
case fastForward
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -139,13 +139,41 @@ class GameViewController: DeltaCore.GameViewController
|
|||||||
{
|
{
|
||||||
super.gameController(gameController, didActivate: input)
|
super.gameController(gameController, didActivate: input)
|
||||||
|
|
||||||
guard self.isSelectingSustainedButtons else { return }
|
if self.isSelectingSustainedButtons
|
||||||
|
|
||||||
guard let pausingGameController = self.pausingGameController, gameController == pausingGameController else { return }
|
|
||||||
|
|
||||||
if input != StandardGameControllerInput.menu
|
|
||||||
{
|
{
|
||||||
gameController.sustain(input)
|
guard let pausingGameController = self.pausingGameController, gameController == pausingGameController else { return }
|
||||||
|
|
||||||
|
if input != StandardGameControllerInput.menu
|
||||||
|
{
|
||||||
|
gameController.sustain(input)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if self.emulatorCore?.state == .running
|
||||||
|
{
|
||||||
|
guard let actionInput = ActionInput(input: input) else { return }
|
||||||
|
|
||||||
|
switch actionInput
|
||||||
|
{
|
||||||
|
case .quickSave: self.performQuickSaveAction()
|
||||||
|
case .quickLoad: self.performQuickLoadAction()
|
||||||
|
case .fastForward: self.performFastForwardAction(activate: true)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override func gameController(_ gameController: GameController, didDeactivate input: Input)
|
||||||
|
{
|
||||||
|
super.gameController(gameController, didDeactivate: input)
|
||||||
|
|
||||||
|
guard !self.isSelectingSustainedButtons else { return }
|
||||||
|
|
||||||
|
guard let actionInput = ActionInput(input: input) else { return }
|
||||||
|
|
||||||
|
switch actionInput
|
||||||
|
{
|
||||||
|
case .quickSave: break
|
||||||
|
case .quickLoad: break
|
||||||
|
case .fastForward: self.performFastForwardAction(activate: false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -251,8 +279,7 @@ extension GameViewController
|
|||||||
|
|
||||||
pauseViewController.fastForwardItem?.isSelected = (self.emulatorCore?.rate != self.emulatorCore?.deltaCore.supportedRates.lowerBound)
|
pauseViewController.fastForwardItem?.isSelected = (self.emulatorCore?.rate != self.emulatorCore?.deltaCore.supportedRates.lowerBound)
|
||||||
pauseViewController.fastForwardItem?.action = { [unowned self] item in
|
pauseViewController.fastForwardItem?.action = { [unowned self] item in
|
||||||
guard let emulatorCore = self.emulatorCore else { return }
|
self.performFastForwardAction(activate: item.isSelected)
|
||||||
emulatorCore.rate = item.isSelected ? emulatorCore.deltaCore.supportedRates.upperBound : emulatorCore.deltaCore.supportedRates.lowerBound
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pauseViewController.sustainButtonsItem?.isSelected = gameController.sustainedInputs.count > 0
|
pauseViewController.sustainButtonsItem?.isSelected = gameController.sustainedInputs.count > 0
|
||||||
@ -441,42 +468,37 @@ extension GameViewController: SaveStatesViewControllerDelegate
|
|||||||
|
|
||||||
let game = backgroundContext.object(with: game.objectID) as! Game
|
let game = backgroundContext.object(with: game.objectID) as! Game
|
||||||
|
|
||||||
let predicate = NSPredicate(format: "%K == %d AND %K == %@", #keyPath(SaveState.type), SaveStateType.auto.rawValue, #keyPath(SaveState.game), game)
|
let fetchRequest = SaveState.fetchRequest(for: game, type: .auto)
|
||||||
|
|
||||||
let fetchRequest: NSFetchRequest<SaveState> = SaveState.fetchRequest()
|
|
||||||
fetchRequest.predicate = predicate
|
|
||||||
fetchRequest.sortDescriptors = [NSSortDescriptor(key: #keyPath(SaveState.creationDate), ascending: true)]
|
fetchRequest.sortDescriptors = [NSSortDescriptor(key: #keyPath(SaveState.creationDate), ascending: true)]
|
||||||
|
|
||||||
var saveStates: [SaveState]? = nil
|
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
saveStates = try fetchRequest.execute()
|
let saveStates = try fetchRequest.execute()
|
||||||
|
|
||||||
|
if let saveState = saveStates.first, saveStates.count >= 2
|
||||||
|
{
|
||||||
|
// If there are two or more auto save states, update the oldest one
|
||||||
|
self.update(saveState, with: self.pausedSaveState)
|
||||||
|
|
||||||
|
// Tiny hack: SaveStatesViewController sorts save states by creation date, so we update the creation date too
|
||||||
|
// Simpler than deleting old save states ¯\_(ツ)_/¯
|
||||||
|
saveState.creationDate = saveState.modifiedDate
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Otherwise, create a new one
|
||||||
|
let saveState = SaveState.insertIntoManagedObjectContext(backgroundContext)
|
||||||
|
saveState.type = .auto
|
||||||
|
saveState.game = game
|
||||||
|
|
||||||
|
self.update(saveState, with: self.pausedSaveState)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
print(error)
|
print(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
if let saveStates = saveStates, let saveState = saveStates.first, saveStates.count >= 2
|
|
||||||
{
|
|
||||||
// If there are two or more auto save states, update the oldest one
|
|
||||||
self.update(saveState, with: self.pausedSaveState)
|
|
||||||
|
|
||||||
// Tiny hack; SaveStatesViewController sorts save states by creation date, so we update the creation date too
|
|
||||||
// Simpler than deleting old save states ¯\_(ツ)_/¯
|
|
||||||
saveState.creationDate = saveState.modifiedDate
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// Otherwise, create a new one
|
|
||||||
let saveState = SaveState.insertIntoManagedObjectContext(backgroundContext)
|
|
||||||
saveState.type = .auto
|
|
||||||
saveState.game = game
|
|
||||||
|
|
||||||
self.update(saveState, with: self.pausedSaveState)
|
|
||||||
}
|
|
||||||
|
|
||||||
backgroundContext.saveWithErrorLogging()
|
backgroundContext.saveWithErrorLogging()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -535,25 +557,14 @@ extension GameViewController: SaveStatesViewControllerDelegate
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
//MARK: - SaveStatesViewControllerDelegate
|
fileprivate func load(_ saveState: SaveStateProtocol)
|
||||||
|
|
||||||
func saveStatesViewController(_ saveStatesViewController: SaveStatesViewController, updateSaveState saveState: SaveState)
|
|
||||||
{
|
{
|
||||||
let updatingExistingSaveState = FileManager.default.fileExists(atPath: saveState.fileURL.path)
|
let isRunning = (self.emulatorCore?.state == .running)
|
||||||
|
|
||||||
self.update(saveState)
|
if isRunning
|
||||||
|
|
||||||
// Dismiss if updating an existing save state.
|
|
||||||
// If creating a new one, don't dismiss.
|
|
||||||
if updatingExistingSaveState
|
|
||||||
{
|
{
|
||||||
self.pauseViewController?.dismiss()
|
self.pauseEmulation()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
func saveStatesViewController(_ saveStatesViewController: SaveStatesViewController, loadSaveState saveState: SaveStateProtocol)
|
|
||||||
{
|
|
||||||
self._isLoadingSaveState = true
|
|
||||||
|
|
||||||
// If we're loading the auto save state, we need to create a temporary copy of saveState.
|
// If we're loading the auto save state, we need to create a temporary copy of saveState.
|
||||||
// Then, we update the auto save state, but load our copy so everything works out.
|
// Then, we update the auto save state, but load our copy so everything works out.
|
||||||
@ -597,6 +608,34 @@ extension GameViewController: SaveStatesViewControllerDelegate
|
|||||||
print(error)
|
print(error)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if isRunning
|
||||||
|
{
|
||||||
|
self.resumeEmulation()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//MARK: - SaveStatesViewControllerDelegate
|
||||||
|
|
||||||
|
func saveStatesViewController(_ saveStatesViewController: SaveStatesViewController, updateSaveState saveState: SaveState)
|
||||||
|
{
|
||||||
|
let updatingExistingSaveState = FileManager.default.fileExists(atPath: saveState.fileURL.path)
|
||||||
|
|
||||||
|
self.update(saveState)
|
||||||
|
|
||||||
|
// Dismiss if updating an existing save state.
|
||||||
|
// If creating a new one, don't dismiss.
|
||||||
|
if updatingExistingSaveState
|
||||||
|
{
|
||||||
|
self.pauseViewController?.dismiss()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func saveStatesViewController(_ saveStatesViewController: SaveStatesViewController, loadSaveState saveState: SaveStateProtocol)
|
||||||
|
{
|
||||||
|
self._isLoadingSaveState = true
|
||||||
|
|
||||||
|
self.load(saveState)
|
||||||
|
|
||||||
self.pauseViewController?.dismiss()
|
self.pauseViewController?.dismiss()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -666,6 +705,78 @@ private extension GameViewController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//MARK: - Action Inputs -
|
||||||
|
/// Action Inputs
|
||||||
|
extension GameViewController
|
||||||
|
{
|
||||||
|
func performQuickSaveAction()
|
||||||
|
{
|
||||||
|
guard let game = self.game as? Game else { return }
|
||||||
|
|
||||||
|
let backgroundContext = DatabaseManager.shared.newBackgroundContext()
|
||||||
|
backgroundContext.performAndWait {
|
||||||
|
|
||||||
|
let game = backgroundContext.object(with: game.objectID) as! Game
|
||||||
|
let fetchRequest = SaveState.fetchRequest(for: game, type: .quick)
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if let quickSaveState = try fetchRequest.execute().first
|
||||||
|
{
|
||||||
|
self.update(quickSaveState)
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
let saveState = SaveState(context: backgroundContext)
|
||||||
|
saveState.type = .quick
|
||||||
|
saveState.game = game
|
||||||
|
|
||||||
|
self.update(saveState)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
print(error)
|
||||||
|
}
|
||||||
|
|
||||||
|
backgroundContext.saveWithErrorLogging()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func performQuickLoadAction()
|
||||||
|
{
|
||||||
|
guard let game = self.game as? Game else { return }
|
||||||
|
|
||||||
|
let fetchRequest = SaveState.fetchRequest(for: game, type: .quick)
|
||||||
|
|
||||||
|
do
|
||||||
|
{
|
||||||
|
if let quickSaveState = try fetchRequest.execute().first
|
||||||
|
{
|
||||||
|
self.load(quickSaveState)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
print(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func performFastForwardAction(activate: Bool)
|
||||||
|
{
|
||||||
|
guard let emulatorCore = self.emulatorCore else { return }
|
||||||
|
|
||||||
|
if activate
|
||||||
|
{
|
||||||
|
emulatorCore.rate = emulatorCore.deltaCore.supportedRates.upperBound
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
emulatorCore.rate = emulatorCore.deltaCore.supportedRates.lowerBound
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//MARK: - GameViewControllerDelegate -
|
//MARK: - GameViewControllerDelegate -
|
||||||
/// GameViewControllerDelegate
|
/// GameViewControllerDelegate
|
||||||
extension GameViewController: GameViewControllerDelegate
|
extension GameViewController: GameViewControllerDelegate
|
||||||
|
|||||||
@ -29,6 +29,7 @@ extension SaveStatesViewController
|
|||||||
enum Section: Int
|
enum Section: Int
|
||||||
{
|
{
|
||||||
case auto
|
case auto
|
||||||
|
case quick
|
||||||
case general
|
case general
|
||||||
case locked
|
case locked
|
||||||
}
|
}
|
||||||
@ -268,6 +269,7 @@ private extension SaveStatesViewController
|
|||||||
switch section
|
switch section
|
||||||
{
|
{
|
||||||
case .auto: title = NSLocalizedString("Auto Save", comment: "")
|
case .auto: title = NSLocalizedString("Auto Save", comment: "")
|
||||||
|
case .quick: title = NSLocalizedString("Quick Save", comment: "")
|
||||||
case .general: title = NSLocalizedString("General", comment: "")
|
case .general: title = NSLocalizedString("General", comment: "")
|
||||||
case .locked: title = NSLocalizedString("Locked", comment: "")
|
case .locked: title = NSLocalizedString("Locked", comment: "")
|
||||||
}
|
}
|
||||||
@ -310,6 +312,7 @@ private extension SaveStatesViewController
|
|||||||
let game = backgroundContext.object(with: self.game.objectID) as! Game
|
let game = backgroundContext.object(with: self.game.objectID) as! Game
|
||||||
|
|
||||||
saveState = SaveState.insertIntoManagedObjectContext(backgroundContext)
|
saveState = SaveState.insertIntoManagedObjectContext(backgroundContext)
|
||||||
|
saveState.type = .general
|
||||||
saveState.game = game
|
saveState.game = game
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -480,6 +483,7 @@ private extension SaveStatesViewController
|
|||||||
switch saveState.type
|
switch saveState.type
|
||||||
{
|
{
|
||||||
case .auto: break
|
case .auto: break
|
||||||
|
case .quick: break
|
||||||
case .general:
|
case .general:
|
||||||
let lockAction = Action(title: NSLocalizedString("Lock", comment: ""), style: .default, action: { [unowned self] action in
|
let lockAction = Action(title: NSLocalizedString("Lock", comment: ""), style: .default, action: { [unowned self] action in
|
||||||
self.lockSaveState(saveState)
|
self.lockSaveState(saveState)
|
||||||
@ -643,11 +647,11 @@ extension SaveStatesViewController
|
|||||||
{
|
{
|
||||||
case .saving:
|
case .saving:
|
||||||
|
|
||||||
let section = self.correctedSectionForSectionIndex((indexPath as NSIndexPath).section)
|
let section = self.correctedSectionForSectionIndex(indexPath.section)
|
||||||
switch section
|
switch section
|
||||||
{
|
{
|
||||||
case .auto: break
|
case .auto: break
|
||||||
case .general:
|
case .quick, .general:
|
||||||
let backgroundContext = DatabaseManager.shared.newBackgroundContext()
|
let backgroundContext = DatabaseManager.shared.newBackgroundContext()
|
||||||
backgroundContext.performAndWait() {
|
backgroundContext.performAndWait() {
|
||||||
let temporarySaveState = backgroundContext.object(with: saveState.objectID) as! SaveState
|
let temporarySaveState = backgroundContext.object(with: saveState.objectID) as! SaveState
|
||||||
|
|||||||
@ -31,7 +31,7 @@ class ControllerInputsViewController: UIViewController
|
|||||||
fileprivate lazy var managedObjectContext: NSManagedObjectContext = DatabaseManager.shared.newBackgroundContext()
|
fileprivate lazy var managedObjectContext: NSManagedObjectContext = DatabaseManager.shared.newBackgroundContext()
|
||||||
fileprivate var inputMappings = [System: GameControllerInputMapping]()
|
fileprivate var inputMappings = [System: GameControllerInputMapping]()
|
||||||
|
|
||||||
fileprivate let supportedActionInputs: [ActionInput] = [.saveState, .loadState, .fastForward]
|
fileprivate let supportedActionInputs: [ActionInput] = [.quickSave, .quickLoad, .fastForward]
|
||||||
|
|
||||||
fileprivate var gameViewController: DeltaCore.GameViewController!
|
fileprivate var gameViewController: DeltaCore.GameViewController!
|
||||||
fileprivate var actionsMenuViewController: GridMenuViewController!
|
fileprivate var actionsMenuViewController: GridMenuViewController!
|
||||||
@ -188,13 +188,13 @@ private extension ControllerInputsViewController
|
|||||||
|
|
||||||
switch input
|
switch input
|
||||||
{
|
{
|
||||||
case .saveState:
|
case .quickSave:
|
||||||
image = #imageLiteral(resourceName: "SaveSaveState")
|
image = #imageLiteral(resourceName: "SaveSaveState")
|
||||||
text = NSLocalizedString("Save State", comment: "")
|
text = NSLocalizedString("Quick Save", comment: "")
|
||||||
|
|
||||||
case .loadState:
|
case .quickLoad:
|
||||||
image = #imageLiteral(resourceName: "LoadSaveState")
|
image = #imageLiteral(resourceName: "LoadSaveState")
|
||||||
text = NSLocalizedString("Load State", comment: "")
|
text = NSLocalizedString("Quick Load", comment: "")
|
||||||
|
|
||||||
case .fastForward:
|
case .fastForward:
|
||||||
image = #imageLiteral(resourceName: "FastForward")
|
image = #imageLiteral(resourceName: "FastForward")
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user