Merge pull request #225 from rileytestut/1.4

Delta 1.4
This commit is contained in:
Riley Testut 2023-02-28 17:35:56 -06:00 committed by GitHub
commit cfa31678ea
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
65 changed files with 9457 additions and 7433 deletions

3
.gitmodules vendored
View File

@ -31,3 +31,6 @@
[submodule "Cores/GPGXDeltaCore"] [submodule "Cores/GPGXDeltaCore"]
path = Cores/GPGXDeltaCore path = Cores/GPGXDeltaCore
url = https://github.com/rileytestut/GPGXDeltaCore.git url = https://github.com/rileytestut/GPGXDeltaCore.git
[submodule "External/CheatBase"]
path = External/CheatBase
url = https://github.com/rileytestut/CheatBase.git

@ -1 +1 @@
Subproject commit e2b3f0e46b4c64670e13fd0466ebdac719f84555 Subproject commit 81362dd5def310f4dd908513574c7e2fd10c7d75

@ -1 +1 @@
Subproject commit 8523e03358559cebaa36b67bd0a87698df238512 Subproject commit c07950a584ed3153b90349059629db85b1c330ac

@ -1 +1 @@
Subproject commit 4313fa6670ab534e70d13532c2504761f849c432 Subproject commit 338a3b32c01413999e390c681dc336fdcdff1ca1

@ -1 +1 @@
Subproject commit ad4ba365acf1800d372ebfaa98df86b9c1b23dce Subproject commit aed30506c77096c3e854c9a38fe9cc893e9480a1

@ -1 +1 @@
Subproject commit d6b33d89043898d521546d9062d12a505b7d2101 Subproject commit 16f79982e468137c3bfe11a2dbff97423a5ce128

@ -1 +1 @@
Subproject commit e598f512b498e1b639a8d2134113169f4b8d0d26 Subproject commit c581c6f51efd61dc5891fac22dbada7df347c003

@ -1 +1 @@
Subproject commit 78fa7db707655962a1077f4681c35fcf81510060 Subproject commit e5221a06ff2ff830bf60302ef0678fe5e554a925

@ -1 +1 @@
Subproject commit 7539cbaac26a3d2ca9daf47ba22d1b0ebbc41a2b Subproject commit 2ef4c123b43565688f7b7d3aa5099559b633f7ba

View File

@ -3,7 +3,7 @@
archiveVersion = 1; archiveVersion = 1;
classes = { classes = {
}; };
objectVersion = 46; objectVersion = 52;
objects = { objects = {
/* Begin PBXAggregateTarget section */ /* Begin PBXAggregateTarget section */
@ -165,6 +165,20 @@
BFFDF03723E3BB2600931B96 /* libSnes9x.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BFFDF03623E3BB2600931B96 /* libSnes9x.a */; }; BFFDF03723E3BB2600931B96 /* libSnes9x.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BFFDF03623E3BB2600931B96 /* libSnes9x.a */; };
BFFDF03F23E3C28A00931B96 /* libGambatte.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BFFDF03D23E3C0F000931B96 /* libGambatte.a */; }; BFFDF03F23E3C28A00931B96 /* libGambatte.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BFFDF03D23E3C0F000931B96 /* libGambatte.a */; };
BFFDF04623E3D3A600931B96 /* libMupen64Plus.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BFFDF04523E3D3A600931B96 /* libMupen64Plus.a */; }; BFFDF04623E3D3A600931B96 /* libMupen64Plus.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BFFDF04523E3D3A600931B96 /* libMupen64Plus.a */; };
D524F4A1273DE9A100D500B2 /* AltKit in Frameworks */ = {isa = PBXBuildFile; productRef = D524F4A0273DE9A100D500B2 /* AltKit */; };
D524F4A3273DE9C000D500B2 /* ProcessInfo+JIT.swift in Sources */ = {isa = PBXBuildFile; fileRef = D524F4A2273DE9C000D500B2 /* ProcessInfo+JIT.swift */; };
D524F4A5273DEBB400D500B2 /* ServerManager+Delta.swift in Sources */ = {isa = PBXBuildFile; fileRef = D524F4A4273DEBB400D500B2 /* ServerManager+Delta.swift */; };
D5011C48281B6E8B00A0760B /* CharacterSet+Filename.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5011C47281B6E8B00A0760B /* CharacterSet+Filename.swift */; };
D53415A5298C782A00FD67B1 /* ContributorsView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D53415A4298C782A00FD67B1 /* ContributorsView.swift */; };
D53415A7298C78BC00FD67B1 /* Contributors.plist in Resources */ = {isa = PBXBuildFile; fileRef = D53415A6298C78BC00FD67B1 /* Contributors.plist */; };
D5864970297734280081477E /* CheatMetadata.swift in Sources */ = {isa = PBXBuildFile; fileRef = D586496F297734280081477E /* CheatMetadata.swift */; };
D586497229774ABD0081477E /* CheatBase.swift in Sources */ = {isa = PBXBuildFile; fileRef = D586497129774ABD0081477E /* CheatBase.swift */; };
D5864978297756CE0081477E /* CheatBaseView.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5864977297756CE0081477E /* CheatBaseView.swift */; };
D5A98CE2284EF14B00E023E5 /* SceneDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5A98CE1284EF14B00E023E5 /* SceneDelegate.swift */; };
D5AAF27729884F8600F21ACF /* CheatDevice.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5AAF27629884F8600F21ACF /* CheatDevice.swift */; };
D5D797E6298D946200738869 /* Contributor.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5D797E5298D946200738869 /* Contributor.swift */; };
D5D797E9298DCC7300738869 /* cheatbase.zip in Resources */ = {isa = PBXBuildFile; fileRef = D5D797E7298DC9E200738869 /* cheatbase.zip */; };
D5F82FB82981D3AC00B229AF /* LegacySearchBar.swift in Sources */ = {isa = PBXBuildFile; fileRef = D5F82FB72981D3AC00B229AF /* LegacySearchBar.swift */; };
/* End PBXBuildFile section */ /* End PBXBuildFile section */
/* Begin PBXContainerItemProxy section */ /* Begin PBXContainerItemProxy section */
@ -358,6 +372,19 @@
BFFDF03D23E3C0F000931B96 /* libGambatte.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libGambatte.a; sourceTree = BUILT_PRODUCTS_DIR; }; BFFDF03D23E3C0F000931B96 /* libGambatte.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libGambatte.a; sourceTree = BUILT_PRODUCTS_DIR; };
BFFDF04523E3D3A600931B96 /* libMupen64Plus.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libMupen64Plus.a; sourceTree = BUILT_PRODUCTS_DIR; }; BFFDF04523E3D3A600931B96 /* libMupen64Plus.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; path = libMupen64Plus.a; sourceTree = BUILT_PRODUCTS_DIR; };
C786AF1D2DDB6223BE2063CC /* Pods-Delta.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Delta.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Delta/Pods-Delta.debug.xcconfig"; sourceTree = "<group>"; }; C786AF1D2DDB6223BE2063CC /* Pods-Delta.debug.xcconfig */ = {isa = PBXFileReference; includeInIndex = 1; lastKnownFileType = text.xcconfig; name = "Pods-Delta.debug.xcconfig"; path = "Pods/Target Support Files/Pods-Delta/Pods-Delta.debug.xcconfig"; sourceTree = "<group>"; };
D524F4A2273DE9C000D500B2 /* ProcessInfo+JIT.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ProcessInfo+JIT.swift"; sourceTree = "<group>"; };
D524F4A4273DEBB400D500B2 /* ServerManager+Delta.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "ServerManager+Delta.swift"; sourceTree = "<group>"; };
D5011C47281B6E8B00A0760B /* CharacterSet+Filename.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "CharacterSet+Filename.swift"; sourceTree = "<group>"; };
D53415A4298C782A00FD67B1 /* ContributorsView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ContributorsView.swift; sourceTree = "<group>"; };
D53415A6298C78BC00FD67B1 /* Contributors.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = Contributors.plist; sourceTree = "<group>"; };
D586496F297734280081477E /* CheatMetadata.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheatMetadata.swift; sourceTree = "<group>"; };
D586497129774ABD0081477E /* CheatBase.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheatBase.swift; sourceTree = "<group>"; };
D5864977297756CE0081477E /* CheatBaseView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheatBaseView.swift; sourceTree = "<group>"; };
D5A98CE1284EF14B00E023E5 /* SceneDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SceneDelegate.swift; sourceTree = "<group>"; };
D5AAF27629884F8600F21ACF /* CheatDevice.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CheatDevice.swift; sourceTree = "<group>"; };
D5D797E5298D946200738869 /* Contributor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Contributor.swift; sourceTree = "<group>"; };
D5D797E7298DC9E200738869 /* cheatbase.zip */ = {isa = PBXFileReference; lastKnownFileType = archive.zip; path = cheatbase.zip; sourceTree = "<group>"; };
D5F82FB72981D3AC00B229AF /* LegacySearchBar.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LegacySearchBar.swift; sourceTree = "<group>"; };
DC866E433B3BA9AE18ABA1EC /* libPods-Delta.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Delta.a"; sourceTree = BUILT_PRODUCTS_DIR; }; DC866E433B3BA9AE18ABA1EC /* libPods-Delta.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = "libPods-Delta.a"; sourceTree = BUILT_PRODUCTS_DIR; };
/* End PBXFileReference section */ /* End PBXFileReference section */
@ -373,6 +400,7 @@
BFDCA1E6244EBAA900B8FBDB /* liblibDeSmuME.a in Frameworks */, BFDCA1E6244EBAA900B8FBDB /* liblibDeSmuME.a in Frameworks */,
BFCADF1E25D22FE2008D78FB /* Systems.framework in Frameworks */, BFCADF1E25D22FE2008D78FB /* Systems.framework in Frameworks */,
BF69FBC923E3A8380051BEEA /* libNestopia.a in Frameworks */, BF69FBC923E3A8380051BEEA /* libNestopia.a in Frameworks */,
D524F4A1273DE9A100D500B2 /* AltKit in Frameworks */,
1FA4ABA79AB72914FE414A61 /* libPods-Delta.a in Frameworks */, 1FA4ABA79AB72914FE414A61 /* libPods-Delta.a in Frameworks */,
BFFDF03F23E3C28A00931B96 /* libGambatte.a in Frameworks */, BFFDF03F23E3C28A00931B96 /* libGambatte.a in Frameworks */,
BFFDF03723E3BB2600931B96 /* libSnes9x.a in Frameworks */, BFFDF03723E3BB2600931B96 /* libSnes9x.a in Frameworks */,
@ -403,6 +431,9 @@
BF647A6922FB8FCE0061D76D /* Bundle+SwizzleBundleID.swift */, BF647A6922FB8FCE0061D76D /* Bundle+SwizzleBundleID.swift */,
BFD1EF3F2336BD8800D197CF /* UIDevice+Processor.swift */, BFD1EF3F2336BD8800D197CF /* UIDevice+Processor.swift */,
BFE56E1823EB7BE00014FECD /* UIImage+SymbolFallback.swift */, BFE56E1823EB7BE00014FECD /* UIImage+SymbolFallback.swift */,
D524F4A2273DE9C000D500B2 /* ProcessInfo+JIT.swift */,
D524F4A4273DEBB400D500B2 /* ServerManager+Delta.swift */,
D5011C47281B6E8B00A0760B /* CharacterSet+Filename.swift */,
); );
path = Extensions; path = Extensions;
sourceTree = "<group>"; sourceTree = "<group>";
@ -514,6 +545,7 @@
BF59426D1E09BC5D0051894B /* DatabaseManager.swift */, BF59426D1E09BC5D0051894B /* DatabaseManager.swift */,
BF5942711E09BC690051894B /* Model */, BF5942711E09BC690051894B /* Model */,
BF95E2751E49763D0030E7AD /* OpenVGDB */, BF95E2751E49763D0030E7AD /* OpenVGDB */,
D586496E297734060081477E /* Cheats */,
); );
path = Database; path = Database;
sourceTree = "<group>"; sourceTree = "<group>";
@ -718,6 +750,7 @@
BF11734E1DA32CEC00047DF8 /* Controllers */, BF11734E1DA32CEC00047DF8 /* Controllers */,
BF1DAD5B1D9F574900E752A7 /* Controller Skins */, BF1DAD5B1D9F574900E752A7 /* Controller Skins */,
BF48F74C219A16C100BC2FC1 /* Syncing */, BF48F74C219A16C100BC2FC1 /* Syncing */,
D5D797E4298D944C00738869 /* Contributors */,
); );
path = Settings; path = Settings;
sourceTree = "<group>"; sourceTree = "<group>";
@ -768,6 +801,8 @@
children = ( children = (
BF6BB2451BB73FE800CCF94A /* Assets.xcassets */, BF6BB2451BB73FE800CCF94A /* Assets.xcassets */,
BF02D5D91DDEBB3000A5E131 /* openvgdb.sqlite */, BF02D5D91DDEBB3000A5E131 /* openvgdb.sqlite */,
D5D797E7298DC9E200738869 /* cheatbase.zip */,
D53415A6298C78BC00FD67B1 /* Contributors.plist */,
); );
path = Resources; path = Resources;
sourceTree = "<group>"; sourceTree = "<group>";
@ -817,6 +852,7 @@
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
BFFA71DC1AAC406100EE9DD1 /* AppDelegate.swift */, BFFA71DC1AAC406100EE9DD1 /* AppDelegate.swift */,
D5A98CE1284EF14B00E023E5 /* SceneDelegate.swift */,
BFFA71E01AAC406100EE9DD1 /* Main.storyboard */, BFFA71E01AAC406100EE9DD1 /* Main.storyboard */,
BFFC46211D59848000AF2CC6 /* Launch */, BFFC46211D59848000AF2CC6 /* Launch */,
BF46894D1AAC469800A2586D /* Game Selection */, BF46894D1AAC469800A2586D /* Game Selection */,
@ -877,6 +913,27 @@
path = Launch; path = Launch;
sourceTree = "<group>"; sourceTree = "<group>";
}; };
D586496E297734060081477E /* Cheats */ = {
isa = PBXGroup;
children = (
D586496F297734280081477E /* CheatMetadata.swift */,
D5AAF27629884F8600F21ACF /* CheatDevice.swift */,
D586497129774ABD0081477E /* CheatBase.swift */,
D5864977297756CE0081477E /* CheatBaseView.swift */,
D5F82FB72981D3AC00B229AF /* LegacySearchBar.swift */,
);
path = Cheats;
sourceTree = "<group>";
};
D5D797E4298D944C00738869 /* Contributors */ = {
isa = PBXGroup;
children = (
D5D797E5298D946200738869 /* Contributor.swift */,
D53415A4298C782A00FD67B1 /* ContributorsView.swift */,
);
path = Contributors;
sourceTree = "<group>";
};
FD1E8AE87FA2DB8793F7B937 /* Pods */ = { FD1E8AE87FA2DB8793F7B937 /* Pods */ = {
isa = PBXGroup; isa = PBXGroup;
children = ( children = (
@ -908,6 +965,7 @@
); );
name = Delta; name = Delta;
packageProductDependencies = ( packageProductDependencies = (
D524F4A0273DE9A100D500B2 /* AltKit */,
); );
productName = Delta; productName = Delta;
productReference = BFFA71D71AAC406100EE9DD1 /* Delta.app */; productReference = BFFA71D71AAC406100EE9DD1 /* Delta.app */;
@ -957,6 +1015,9 @@
Base, Base,
); );
mainGroup = BFFA71CE1AAC406100EE9DD1; mainGroup = BFFA71CE1AAC406100EE9DD1;
packageReferences = (
D524F49F273DE9A100D500B2 /* XCRemoteSwiftPackageReference "AltKit" */,
);
productRefGroup = BFFA71D81AAC406100EE9DD1 /* Products */; productRefGroup = BFFA71D81AAC406100EE9DD1 /* Products */;
projectDirPath = ""; projectDirPath = "";
projectRoot = ""; projectRoot = "";
@ -973,12 +1034,14 @@
isa = PBXResourcesBuildPhase; isa = PBXResourcesBuildPhase;
buildActionMask = 2147483647; buildActionMask = 2147483647;
files = ( files = (
D5D797E9298DCC7300738869 /* cheatbase.zip in Resources */,
BFFA71E21AAC406100EE9DD1 /* Main.storyboard in Resources */, BFFA71E21AAC406100EE9DD1 /* Main.storyboard in Resources */,
BF6BF3211EB82362008E83CD /* GamesDatabase.storyboard in Resources */, BF6BF3211EB82362008E83CD /* GamesDatabase.storyboard in Resources */,
BFAB9F88219A4B670080EC7D /* GoogleService-Info.plist in Resources */, BFAB9F88219A4B670080EC7D /* GoogleService-Info.plist in Resources */,
BF3540001C5DA3C500C1184C /* PausePresentationControllerContentView.xib in Resources */, BF3540001C5DA3C500C1184C /* PausePresentationControllerContentView.xib in Resources */,
BF5E7F461B9A652600AE44F8 /* Settings.storyboard in Resources */, BF5E7F461B9A652600AE44F8 /* Settings.storyboard in Resources */,
BF02D5DA1DDEBB3000A5E131 /* openvgdb.sqlite in Resources */, BF02D5DA1DDEBB3000A5E131 /* openvgdb.sqlite in Resources */,
D53415A7298C78BC00FD67B1 /* Contributors.plist in Resources */,
BF71CF8A1FE904B1001F1613 /* GameTableViewCell.xib in Resources */, BF71CF8A1FE904B1001F1613 /* GameTableViewCell.xib in Resources */,
BFFC46461D59861000AF2CC6 /* LaunchScreen.storyboard in Resources */, BFFC46461D59861000AF2CC6 /* LaunchScreen.storyboard in Resources */,
BF1F45AB21AF4B5800EF9895 /* SyncResultsViewController.storyboard in Resources */, BF1F45AB21AF4B5800EF9895 /* SyncResultsViewController.storyboard in Resources */,
@ -1114,6 +1177,7 @@
BF525EEA1FF6CD12004AA849 /* DeepLink.swift in Sources */, BF525EEA1FF6CD12004AA849 /* DeepLink.swift in Sources */,
BF8A334621A4926F00A42FD4 /* GameSyncStatusViewController.swift in Sources */, BF8A334621A4926F00A42FD4 /* GameSyncStatusViewController.swift in Sources */,
BF59427E1E09BC830051894B /* Game.swift in Sources */, BF59427E1E09BC830051894B /* Game.swift in Sources */,
D5011C48281B6E8B00A0760B /* CharacterSet+Filename.swift in Sources */,
BFE593CC21F3F8C2003412A6 /* _GameSave.swift in Sources */, BFE593CC21F3F8C2003412A6 /* _GameSave.swift in Sources */,
BF63A1A321A4AAAE00EE8F61 /* RecordSyncStatusViewController.swift in Sources */, BF63A1A321A4AAAE00EE8F61 /* RecordSyncStatusViewController.swift in Sources */,
BFAA1FED1B8AA4FA00495943 /* Settings.swift in Sources */, BFAA1FED1B8AA4FA00495943 /* Settings.swift in Sources */,
@ -1137,8 +1201,10 @@
BF5942951E09BD1A0051894B /* NSManagedObjectContext+Conveniences.swift in Sources */, BF5942951E09BD1A0051894B /* NSManagedObjectContext+Conveniences.swift in Sources */,
BFC3628021ADE2BA00EF2BE6 /* UIAlertController+Error.swift in Sources */, BFC3628021ADE2BA00EF2BE6 /* UIAlertController+Error.swift in Sources */,
BF353FF91C5D870B00C1184C /* MenuItem.swift in Sources */, BF353FF91C5D870B00C1184C /* MenuItem.swift in Sources */,
D5D797E6298D946200738869 /* Contributor.swift in Sources */,
BFDB3418219E4B1700595A62 /* SyncStatusViewController.swift in Sources */, BFDB3418219E4B1700595A62 /* SyncStatusViewController.swift in Sources */,
BF18B61F1E2985F900F70067 /* UIAlertController+Importing.swift in Sources */, BF18B61F1E2985F900F70067 /* UIAlertController+Importing.swift in Sources */,
D586497229774ABD0081477E /* CheatBase.swift in Sources */,
BFDD04F11D5E2C27002D450E /* GameCollectionViewController.swift in Sources */, BFDD04F11D5E2C27002D450E /* GameCollectionViewController.swift in Sources */,
BFE4269E1D9C68E600DC913F /* SaveStatesStoryboardSegue.swift in Sources */, BFE4269E1D9C68E600DC913F /* SaveStatesStoryboardSegue.swift in Sources */,
BFFA71DD1AAC406100EE9DD1 /* AppDelegate.swift in Sources */, BFFA71DD1AAC406100EE9DD1 /* AppDelegate.swift in Sources */,
@ -1146,8 +1212,11 @@
BF59426B1E09BBD00051894B /* GridCollectionViewLayout.swift in Sources */, BF59426B1E09BBD00051894B /* GridCollectionViewLayout.swift in Sources */,
BF6424851F5CBDC900D6AB44 /* UIView+ParentViewController.swift in Sources */, BF6424851F5CBDC900D6AB44 /* UIView+ParentViewController.swift in Sources */,
BF04E6FF1DB8625C000F35D3 /* ControllerSkinsViewController.swift in Sources */, BF04E6FF1DB8625C000F35D3 /* ControllerSkinsViewController.swift in Sources */,
D53415A5298C782A00FD67B1 /* ContributorsView.swift in Sources */,
BF5942891E09BC8B0051894B /* _GameCollection.swift in Sources */, BF5942891E09BC8B0051894B /* _GameCollection.swift in Sources */,
BF34FA111CF1899D006624C7 /* CheatTextView.swift in Sources */, BF34FA111CF1899D006624C7 /* CheatTextView.swift in Sources */,
D524F4A5273DEBB400D500B2 /* ServerManager+Delta.swift in Sources */,
D5AAF27729884F8600F21ACF /* CheatDevice.swift in Sources */,
BF1F45AD21AF57BA00EF9895 /* HarmonyMetadataKey+Keys.swift in Sources */, BF1F45AD21AF57BA00EF9895 /* HarmonyMetadataKey+Keys.swift in Sources */,
BFD1EF402336BD8800D197CF /* UIDevice+Processor.swift in Sources */, BFD1EF402336BD8800D197CF /* UIDevice+Processor.swift in Sources */,
BF71CF871FE90006001F1613 /* AppIconShortcutsViewController.swift in Sources */, BF71CF871FE90006001F1613 /* AppIconShortcutsViewController.swift in Sources */,
@ -1156,6 +1225,7 @@
BF6BF31C1EB821A0008E83CD /* GamesDatabaseImportOption.swift in Sources */, BF6BF31C1EB821A0008E83CD /* GamesDatabaseImportOption.swift in Sources */,
BFFA4C091E8A24D600D87934 /* GameTableViewCell.swift in Sources */, BFFA4C091E8A24D600D87934 /* GameTableViewCell.swift in Sources */,
BFFC46231D5984A000AF2CC6 /* LaunchViewController.swift in Sources */, BFFC46231D5984A000AF2CC6 /* LaunchViewController.swift in Sources */,
D5864970297734280081477E /* CheatMetadata.swift in Sources */,
BF8DDD241F4F6C880088A21B /* InputCalloutView.swift in Sources */, BF8DDD241F4F6C880088A21B /* InputCalloutView.swift in Sources */,
BF5942701E09BC5D0051894B /* GamesDatabase.swift in Sources */, BF5942701E09BC5D0051894B /* GamesDatabase.swift in Sources */,
BF34FA071CF0F510006624C7 /* EditCheatViewController.swift in Sources */, BF34FA071CF0F510006624C7 /* EditCheatViewController.swift in Sources */,
@ -1167,6 +1237,7 @@
BFFC461F1D59823500AF2CC6 /* GamesStoryboardSegue.swift in Sources */, BFFC461F1D59823500AF2CC6 /* GamesStoryboardSegue.swift in Sources */,
BF2B98E61C97E32F00F6D57D /* SaveStatesCollectionHeaderView.swift in Sources */, BF2B98E61C97E32F00F6D57D /* SaveStatesCollectionHeaderView.swift in Sources */,
BFC9B7391CEFCD34008629BB /* CheatsViewController.swift in Sources */, BFC9B7391CEFCD34008629BB /* CheatsViewController.swift in Sources */,
D5864978297756CE0081477E /* CheatBaseView.swift in Sources */,
BF353FFF1C5DA3C500C1184C /* PausePresentationController.swift in Sources */, BF353FFF1C5DA3C500C1184C /* PausePresentationController.swift in Sources */,
BFFC464C1D5998D600AF2CC6 /* CheatTableViewCell.swift in Sources */, BFFC464C1D5998D600AF2CC6 /* CheatTableViewCell.swift in Sources */,
BF5942941E09BD1A0051894B /* NSManagedObject+Conveniences.swift in Sources */, BF5942941E09BD1A0051894B /* NSManagedObject+Conveniences.swift in Sources */,
@ -1175,14 +1246,17 @@
BF797A2D1C2D339F00F1A000 /* UILabel+FontSize.swift in Sources */, BF797A2D1C2D339F00F1A000 /* UILabel+FontSize.swift in Sources */,
BF80E1D21F13117000847008 /* ControllerInputsViewController.swift in Sources */, BF80E1D21F13117000847008 /* ControllerInputsViewController.swift in Sources */,
BF5942641E09BBB10051894B /* LoadControllerSkinImageOperation.swift in Sources */, BF5942641E09BBB10051894B /* LoadControllerSkinImageOperation.swift in Sources */,
D5A98CE2284EF14B00E023E5 /* SceneDelegate.swift in Sources */,
BFE56E1923EB7BE00014FECD /* UIImage+SymbolFallback.swift in Sources */, BFE56E1923EB7BE00014FECD /* UIImage+SymbolFallback.swift in Sources */,
BF6EE5E91F7C5F860051AD6C /* _GameControllerInputMapping.swift in Sources */, BF6EE5E91F7C5F860051AD6C /* _GameControllerInputMapping.swift in Sources */,
BF5942871E09BC8B0051894B /* _ControllerSkin.swift in Sources */, BF5942871E09BC8B0051894B /* _ControllerSkin.swift in Sources */,
BF95E2791E4982A10030E7AD /* GamesDatabaseBrowserViewController.swift in Sources */, BF95E2791E4982A10030E7AD /* GamesDatabaseBrowserViewController.swift in Sources */,
D524F4A3273DE9C000D500B2 /* ProcessInfo+JIT.swift in Sources */,
BFDCA1E9244F7E1000B8FBDB /* Delta5ToDelta6.xcmappingmodel in Sources */, BFDCA1E9244F7E1000B8FBDB /* Delta5ToDelta6.xcmappingmodel in Sources */,
BFD097211D3A01B8005A44C2 /* SaveStatesViewController.swift in Sources */, BFD097211D3A01B8005A44C2 /* SaveStatesViewController.swift in Sources */,
BF6EE5EB1F7C5F8F0051AD6C /* GameControllerInputMapping.swift in Sources */, BF6EE5EB1F7C5F8F0051AD6C /* GameControllerInputMapping.swift in Sources */,
BF8A333421A484A000A42FD4 /* BadgedTableViewCell.swift in Sources */, BF8A333421A484A000A42FD4 /* BadgedTableViewCell.swift in Sources */,
D5F82FB82981D3AC00B229AF /* LegacySearchBar.swift in Sources */,
BF3540021C5DA3D500C1184C /* PauseStoryboardSegue.swift in Sources */, BF3540021C5DA3D500C1184C /* PauseStoryboardSegue.swift in Sources */,
BF107EC41BF413F000E0C32C /* GamesViewController.swift in Sources */, BF107EC41BF413F000E0C32C /* GamesViewController.swift in Sources */,
BF3D6C512202865F0083E05A /* Delta2ToDelta3.xcmappingmodel in Sources */, BF3D6C512202865F0083E05A /* Delta2ToDelta3.xcmappingmodel in Sources */,
@ -1407,7 +1481,8 @@
PRODUCT_BUNDLE_IDENTIFIER = com.rileytestut.Delta; PRODUCT_BUNDLE_IDENTIFIER = com.rileytestut.Delta;
PRODUCT_NAME = Delta; PRODUCT_NAME = Delta;
SDKROOT = iphoneos; SDKROOT = iphoneos;
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_OPTIMIZATION_LEVEL = "-O";
VALIDATE_PRODUCT = YES; VALIDATE_PRODUCT = YES;
}; };
name = Release; name = Release;
@ -1422,11 +1497,11 @@
CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 43; CURRENT_PROJECT_VERSION = 61;
DEVELOPMENT_TEAM = ""; DEVELOPMENT_TEAM = "";
INFOPLIST_FILE = "Delta/Supporting Files/Info.plist"; INFOPLIST_FILE = "Delta/Supporting Files/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 1.3; MARKETING_VERSION = 1.4;
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" -DDEBUG"; OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" -DDEBUG";
PRODUCT_BUNDLE_IDENTIFIER = com.rileytestut.Delta; PRODUCT_BUNDLE_IDENTIFIER = com.rileytestut.Delta;
PROVISIONING_PROFILE = ""; PROVISIONING_PROFILE = "";
@ -1438,6 +1513,7 @@
SWIFT_OBJC_BRIDGING_HEADER = "Delta/Supporting Files/Delta-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Delta/Supporting Files/Delta-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Onone"; SWIFT_OPTIMIZATION_LEVEL = "-Onone";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
}; };
name = Debug; name = Debug;
}; };
@ -1451,21 +1527,23 @@
CODE_SIGN_IDENTITY = "iPhone Developer"; CODE_SIGN_IDENTITY = "iPhone Developer";
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
CODE_SIGN_STYLE = Automatic; CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 43; CURRENT_PROJECT_VERSION = 61;
DEVELOPMENT_TEAM = ""; DEVELOPMENT_TEAM = "";
INFOPLIST_FILE = "Delta/Supporting Files/Info.plist"; INFOPLIST_FILE = "Delta/Supporting Files/Info.plist";
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 1.3; MARKETING_VERSION = 1.4;
OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" -DIMPACTOR"; OTHER_SWIFT_FLAGS = "$(inherited) \"-D\" \"COCOAPODS\" -DIMPACTOR";
PRODUCT_BUNDLE_IDENTIFIER = com.rileytestut.Delta; PRODUCT_BUNDLE_IDENTIFIER = com.rileytestut.Delta;
PROVISIONING_PROFILE = ""; PROVISIONING_PROFILE = "";
PROVISIONING_PROFILE_SPECIFIER = ""; PROVISIONING_PROFILE_SPECIFIER = "";
STRIP_INSTALLED_PRODUCT = YES; STRIP_INSTALLED_PRODUCT = YES;
STRIP_STYLE = "non-global"; STRIP_STYLE = "non-global";
SWIFT_COMPILATION_MODE = wholemodule;
SWIFT_INCLUDE_PATHS = "$(inherited) \"$(SRCROOT)/Cores/GPGXDeltaCore/Sources/GPGXBridge\""; SWIFT_INCLUDE_PATHS = "$(inherited) \"$(SRCROOT)/Cores/GPGXDeltaCore/Sources/GPGXBridge\"";
SWIFT_OBJC_BRIDGING_HEADER = "Delta/Supporting Files/Delta-Bridging-Header.h"; SWIFT_OBJC_BRIDGING_HEADER = "Delta/Supporting Files/Delta-Bridging-Header.h";
SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; SWIFT_OPTIMIZATION_LEVEL = "-O";
SWIFT_VERSION = 5.0; SWIFT_VERSION = 5.0;
TARGETED_DEVICE_FAMILY = "1,2";
}; };
name = Release; name = Release;
}; };
@ -1510,6 +1588,25 @@
}; };
/* End XCConfigurationList section */ /* End XCConfigurationList section */
/* Begin XCRemoteSwiftPackageReference section */
D524F49F273DE9A100D500B2 /* XCRemoteSwiftPackageReference "AltKit" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/rileytestut/AltKit.git";
requirement = {
kind = revision;
revision = 2fd376df1c79ec06a5c80cc8933da027f65b3148;
};
};
/* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
D524F4A0273DE9A100D500B2 /* AltKit */ = {
isa = XCSwiftPackageProductDependency;
package = D524F49F273DE9A100D500B2 /* XCRemoteSwiftPackageReference "AltKit" */;
productName = AltKit;
};
/* End XCSwiftPackageProductDependency section */
/* Begin XCVersionGroup section */ /* Begin XCVersionGroup section */
BF4828811F9027B600028B97 /* Delta.xcdatamodeld */ = { BF4828811F9027B600028B97 /* Delta.xcdatamodeld */ = {
isa = XCVersionGroup; isa = XCVersionGroup;

View File

@ -3,7 +3,7 @@
LastUpgradeVersion = "1020" LastUpgradeVersion = "1020"
version = "1.3"> version = "1.3">
<BuildAction <BuildAction
parallelizeBuildables = "NO" parallelizeBuildables = "YES"
buildImplicitDependencies = "YES"> buildImplicitDependencies = "YES">
<BuildActionEntries> <BuildActionEntries>
<BuildActionEntry <BuildActionEntry

View File

@ -1,12 +1,21 @@
{ {
"object": { "object": {
"pins": [ "pins": [
{
"package": "AltKit",
"repositoryURL": "https://github.com/rileytestut/AltKit.git",
"state": {
"branch": null,
"revision": "2fd376df1c79ec06a5c80cc8933da027f65b3148",
"version": null
}
},
{ {
"package": "DeltaCore", "package": "DeltaCore",
"repositoryURL": "https://github.com/rileytestut/DeltaCore.git", "repositoryURL": "https://github.com/rileytestut/DeltaCore.git",
"state": { "state": {
"branch": "main", "branch": "main",
"revision": "eeefb30bd78fb130f1113e823afbce6f4f767cfb", "revision": "27a574a46238817084f80d811b3e6c2884d9cdc0",
"version": null "version": null
} }
}, },
@ -15,8 +24,8 @@
"repositoryURL": "https://github.com/weichsel/ZIPFoundation.git", "repositoryURL": "https://github.com/weichsel/ZIPFoundation.git",
"state": { "state": {
"branch": null, "branch": null,
"revision": "ec32d62d412578542c0ffb7a6ce34d3e64b43b94", "revision": "f6a22e7da26314b38bf9befce34ae8e4b2543090",
"version": "0.9.11" "version": "0.9.15"
} }
} }
] ]

View File

@ -10,6 +10,7 @@ import UIKit
import DeltaCore import DeltaCore
import Harmony import Harmony
import AltKit
import Fabric import Fabric
import Crashlytics import Crashlytics
@ -63,6 +64,9 @@ class AppDelegate: UIResponder, UIApplicationDelegate
// Controllers // Controllers
ExternalGameControllerManager.shared.startMonitoring() ExternalGameControllerManager.shared.startMonitoring()
// JIT
ServerManager.shared.prepare()
// Notifications // Notifications
let center = CFNotificationCenterGetDarwinNotifyCenter() let center = CFNotificationCenterGetDarwinNotifyCenter()
CFNotificationCenterAddObserver(center, nil, ReceivedApplicationState, CFNotificationName.altstoreRequestAppState.rawValue, nil, .deliverImmediately) CFNotificationCenterAddObserver(center, nil, ReceivedApplicationState, CFNotificationName.altstoreRequestAppState.rawValue, nil, .deliverImmediately)
@ -110,6 +114,24 @@ class AppDelegate: UIResponder, UIApplicationDelegate
} }
} }
@available(iOS 13, *)
extension AppDelegate
{
func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration
{
// Called when a new scene session is being created.
// Use this method to select a configuration to create the new scene with.
return UISceneConfiguration(name: "Main", sessionRole: connectingSceneSession.role)
}
func application(_ application: UIApplication, didDiscardSceneSessions sceneSessions: Set<UISceneSession>)
{
// Called when the user discards a scene session.
// If any sessions were discarded while the application was not running, this will be called shortly after application:didFinishLaunchingWithOptions.
// Use this method to release any resources that were specific to the discarded scenes, as they will not return.
}
}
private extension AppDelegate private extension AppDelegate
{ {
func registerCores() func registerCores()

View File

@ -46,6 +46,9 @@
</connections> </connections>
</barButtonItem> </barButtonItem>
</navigationItem> </navigationItem>
<connections>
<outlet property="importButton" destination="FeA-O5-xd2" id="A44-3S-Okz"/>
</connections>
</viewController> </viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="JYx-xE-nis" userLabel="First Responder" sceneMemberID="firstResponder"/> <placeholder placeholderIdentifier="IBFirstResponder" id="JYx-xE-nis" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects> </objects>

View File

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="18121" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="ssH-mM-uG6"> <document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="21507" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="ssH-mM-uG6">
<device id="retina4_7" orientation="portrait" appearance="light"/> <device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies> <dependencies>
<deployment identifier="iOS"/> <deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18092"/> <plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="21505"/>
<capability name="Named colors" minToolsVersion="9.0"/> <capability name="Named colors" minToolsVersion="9.0"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/> <capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="System colors in document resources" minToolsVersion="11.0"/> <capability name="System colors in document resources" minToolsVersion="11.0"/>
@ -279,26 +279,26 @@
</tableViewCell> </tableViewCell>
</cells> </cells>
</tableViewSection> </tableViewSection>
<tableViewSection headerTitle="Haptic Feedback" footerTitle="When enabled, your device will vibrate in response to touch screen controls." id="aJ4-xT-aZL"> <tableViewSection headerTitle="Game Audio" footerTitle="When enabled, Delta will only play game audio if your device isn't silenced." id="aJ4-xT-aZL">
<cells> <cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="SwitchCell" id="mRV-Bi-pZ8" customClass="SwitchTableViewCell"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="SwitchCell" id="mRV-Bi-pZ8" customClass="SwitchTableViewCell">
<rect key="frame" x="0.0" y="765" width="375" height="44"/> <rect key="frame" x="0.0" y="794.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="mRV-Bi-pZ8" id="RtM-ok-LGu"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="mRV-Bi-pZ8" id="RtM-ok-LGu">
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/> <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Buttons" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="mue-uO-1xE"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Respect Silent Mode" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="mue-uO-1xE">
<rect key="frame" x="8" y="11.5" width="302" height="21"/> <rect key="frame" x="16" y="11.5" width="286" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/> <fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/> <nil key="textColor"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="mlO-iy-zU2"> <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="mlO-iy-zU2">
<rect key="frame" x="318" y="6.5" width="51" height="31"/> <rect key="frame" x="310" y="6.5" width="51" height="31"/>
<color key="onTintColor" name="Purple"/> <color key="onTintColor" name="Purple"/>
<connections> <connections>
<action selector="toggleButtonHapticFeedbackEnabled:" destination="eHi-aO-uGS" eventType="primaryActionTriggered" id="au3-JT-77n"/> <action selector="toggleRespectSilentMode:" destination="eHi-aO-uGS" eventType="primaryActionTriggered" id="dyA-el-uRa"/>
</connections> </connections>
</switch> </switch>
</subviews> </subviews>
@ -311,33 +311,67 @@
</constraints> </constraints>
</tableViewCellContentView> </tableViewCellContentView>
</tableViewCell> </tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="SwitchCell" id="2Kn-Xu-sTo" customClass="SwitchTableViewCell"> </cells>
<rect key="frame" x="0.0" y="809" width="375" height="44"/> </tableViewSection>
<tableViewSection headerTitle="Haptic Feedback" footerTitle="When enabled, your device will vibrate in response to touch screen controls." id="avK-bg-nm6">
<cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="SwitchCell" id="ZUx-5m-gPq" customClass="SwitchTableViewCell">
<rect key="frame" x="0.0" y="930" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="2Kn-Xu-sTo" id="2pb-gv-gY2"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="ZUx-5m-gPq" id="7fY-cO-dht">
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/> <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Control Sticks" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="UoA-qC-cKc"> <label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Buttons" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="XPP-qe-q75">
<rect key="frame" x="8" y="11.5" width="302" height="21"/> <rect key="frame" x="16" y="11.5" width="286" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/> <fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/> <nil key="textColor"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="s5f-Uz-GpH"> <switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="g7m-wj-ueP">
<rect key="frame" x="318" y="6.5" width="51" height="31"/> <rect key="frame" x="310" y="6.5" width="51" height="31"/>
<color key="onTintColor" name="Purple"/> <color key="onTintColor" name="Purple"/>
<connections> <connections>
<action selector="toggleThumbstickHapticFeedbackEnabled:" destination="eHi-aO-uGS" eventType="primaryActionTriggered" id="ELm-nK-kTr"/> <action selector="toggleButtonHapticFeedbackEnabled:" destination="eHi-aO-uGS" eventType="primaryActionTriggered" id="JkH-Ha-NqO"/>
</connections> </connections>
</switch> </switch>
</subviews> </subviews>
<constraints> <constraints>
<constraint firstItem="s5f-Uz-GpH" firstAttribute="centerY" secondItem="2pb-gv-gY2" secondAttribute="centerY" id="1yP-Wt-XbP"/> <constraint firstItem="XPP-qe-q75" firstAttribute="centerY" secondItem="7fY-cO-dht" secondAttribute="centerY" id="ML4-2L-ivB"/>
<constraint firstAttribute="trailingMargin" secondItem="s5f-Uz-GpH" secondAttribute="trailing" id="3XM-jj-6TV"/> <constraint firstItem="XPP-qe-q75" firstAttribute="leading" secondItem="7fY-cO-dht" secondAttribute="leadingMargin" id="RcM-9w-cj3"/>
<constraint firstItem="UoA-qC-cKc" firstAttribute="centerY" secondItem="2pb-gv-gY2" secondAttribute="centerY" id="AMH-D3-llc"/> <constraint firstItem="g7m-wj-ueP" firstAttribute="leading" secondItem="XPP-qe-q75" secondAttribute="trailing" constant="8" symbolic="YES" id="U9Z-lS-tZm"/>
<constraint firstItem="UoA-qC-cKc" firstAttribute="leading" secondItem="2pb-gv-gY2" secondAttribute="leadingMargin" id="Fi5-Td-wMi"/> <constraint firstAttribute="trailingMargin" secondItem="g7m-wj-ueP" secondAttribute="trailing" id="W92-fx-sPH"/>
<constraint firstItem="s5f-Uz-GpH" firstAttribute="leading" secondItem="UoA-qC-cKc" secondAttribute="trailing" constant="8" symbolic="YES" id="L7N-F1-Maf"/> <constraint firstItem="g7m-wj-ueP" firstAttribute="centerY" secondItem="7fY-cO-dht" secondAttribute="centerY" id="mKM-Rs-8FG"/>
</constraints>
</tableViewCellContentView>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="SwitchCell" id="p47-ru-O9r" customClass="SwitchTableViewCell">
<rect key="frame" x="0.0" y="974" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="p47-ru-O9r" id="o9R-cP-Tge">
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Control Sticks" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="MDR-bb-TYm">
<rect key="frame" x="16" y="11.5" width="286" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="19A-ef-F3V">
<rect key="frame" x="310" y="6.5" width="51" height="31"/>
<color key="onTintColor" name="Purple"/>
<connections>
<action selector="toggleThumbstickHapticFeedbackEnabled:" destination="eHi-aO-uGS" eventType="primaryActionTriggered" id="pHq-hK-bcL"/>
</connections>
</switch>
</subviews>
<constraints>
<constraint firstItem="19A-ef-F3V" firstAttribute="centerY" secondItem="o9R-cP-Tge" secondAttribute="centerY" id="7S9-gQ-Elk"/>
<constraint firstAttribute="trailingMargin" secondItem="19A-ef-F3V" secondAttribute="trailing" id="IVw-V1-wRU"/>
<constraint firstItem="19A-ef-F3V" firstAttribute="leading" secondItem="MDR-bb-TYm" secondAttribute="trailing" constant="8" symbolic="YES" id="hPx-zJ-0qA"/>
<constraint firstItem="MDR-bb-TYm" firstAttribute="centerY" secondItem="o9R-cP-Tge" secondAttribute="centerY" id="m0V-TQ-ajv"/>
<constraint firstItem="MDR-bb-TYm" firstAttribute="leading" secondItem="o9R-cP-Tge" secondAttribute="leadingMargin" id="pSi-wU-tje"/>
</constraints> </constraints>
</tableViewCellContentView> </tableViewCellContentView>
</tableViewCell> </tableViewCell>
@ -502,15 +536,38 @@
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<subviews> <subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Riley Testut" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Pum-dL-hGn"> <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Riley Testut" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Pum-dL-hGn">
<rect key="frame" x="16" y="13" width="84" height="19.5"/> <rect key="frame" x="16" y="12" width="88" height="20.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/> <fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Developer" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="WQ6-m7-zhh"> <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Developer" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="WQ6-m7-zhh">
<rect key="frame" x="267.5" y="13" width="74" height="19.5"/> <rect key="frame" x="262.5" y="12" width="78" height="20.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/> <fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" systemColor="secondaryLabelColor"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</tableViewCellContentView>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="DetailCell" textLabel="cht-lO-kpR" detailTextLabel="0pG-CT-ZWR" style="IBUITableViewCellStyleValue1" id="CV9-Df-mUX">
<rect key="frame" x="0.0" y="1590.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="CV9-Df-mUX" id="gLC-z2-rMU">
<rect key="frame" x="0.0" y="0.0" width="348.5" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Shane Gill" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="cht-lO-kpR">
<rect key="frame" x="16" y="12" width="76" height="20.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Operations" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="0pG-CT-ZWR">
<rect key="frame" x="256.5" y="12" width="84" height="20.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" systemColor="secondaryLabelColor"/> <color key="textColor" systemColor="secondaryLabelColor"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
@ -527,13 +584,13 @@
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Caroline Moore" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="gWx-Xn-5Nf"> <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Caroline Moore" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="gWx-Xn-5Nf">
<rect key="frame" x="16" y="13" width="110.5" height="19.5"/> <rect key="frame" x="16" y="13" width="110.5" height="19.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/> <fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Graphic Designer" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="09x-GX-cpy"> <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Graphic Designer" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="09x-GX-cpy">
<rect key="frame" x="215.5" y="13" width="126" height="19.5"/> <rect key="frame" x="215.5" y="13" width="126" height="19.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/> <fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" systemColor="secondaryLabelColor"/> <color key="textColor" systemColor="secondaryLabelColor"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
@ -550,13 +607,13 @@
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Grant Gliner" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="zro-BX-EY9"> <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Grant Gliner" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="zro-BX-EY9">
<rect key="frame" x="16" y="13" width="87.5" height="19.5"/> <rect key="frame" x="16" y="13" width="87.5" height="19.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/> <fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Icon Guy" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="e45-FD-ug2"> <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Icon Guy" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="e45-FD-ug2">
<rect key="frame" x="277.5" y="13" width="64" height="19.5"/> <rect key="frame" x="277.5" y="13" width="64" height="19.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/> <fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" systemColor="secondaryLabelColor"/> <color key="textColor" systemColor="secondaryLabelColor"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
@ -573,19 +630,35 @@
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Chris Rittenhouse" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="w1i-mR-wOF"> <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Chris Rittenhouse" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="w1i-mR-wOF">
<rect key="frame" x="16" y="13" width="129" height="19.5"/> <rect key="frame" x="16" y="13" width="129" height="19.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/> <fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Genesis Skin" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="jRO-48-iRO"> <label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Genesis Skin" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="jRO-48-iRO">
<rect key="frame" x="248" y="13" width="93.5" height="19.5"/> <rect key="frame" x="248" y="13" width="93.5" height="19.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="16"/> <fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" systemColor="secondaryLabelColor"/> <color key="textColor" systemColor="secondaryLabelColor"/>
<nil key="highlightedColor"/> <nil key="highlightedColor"/>
</label> </label>
</subviews> </subviews>
</tableViewCellContentView> </tableViewCellContentView>
</tableViewCell> </tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="DetailCell" textLabel="g59-8E-zW7" style="IBUITableViewCellStyleDefault" id="hkv-lx-68h">
<rect key="frame" x="0.0" y="1766.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="hkv-lx-68h" id="bNT-kB-3cI">
<rect key="frame" x="0.0" y="0.0" width="348.5" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" ambiguous="YES" text="Contributors" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="g59-8E-zW7">
<rect key="frame" x="16" y="0.0" width="324.5" height="44"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</tableViewCellContentView>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="DetailCell" textLabel="2K3-IL-94S" style="IBUITableViewCellStyleDefault" id="j7p-ZK-mHq"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="DetailCell" textLabel="2K3-IL-94S" style="IBUITableViewCellStyleDefault" id="j7p-ZK-mHq">
<rect key="frame" x="0.0" y="1567.5" width="375" height="44"/> <rect key="frame" x="0.0" y="1567.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
@ -621,12 +694,13 @@
</barButtonItem> </barButtonItem>
</navigationItem> </navigationItem>
<connections> <connections>
<outlet property="buttonHapticFeedbackEnabledSwitch" destination="mlO-iy-zU2" id="ObD-uL-Si0"/> <outlet property="buttonHapticFeedbackEnabledSwitch" destination="g7m-wj-ueP" id="nOj-sc-foi"/>
<outlet property="controllerOpacityLabel" destination="zaz-yD-CYG" id="eUW-u9-xxx"/> <outlet property="controllerOpacityLabel" destination="zaz-yD-CYG" id="eUW-u9-xxx"/>
<outlet property="controllerOpacitySlider" destination="whi-If-wFf" id="6Cx-HY-xLG"/> <outlet property="controllerOpacitySlider" destination="whi-If-wFf" id="6Cx-HY-xLG"/>
<outlet property="previewsEnabledSwitch" destination="OJE-9e-9i3" id="Ndg-eN-PPs"/> <outlet property="previewsEnabledSwitch" destination="OJE-9e-9i3" id="Ndg-eN-PPs"/>
<outlet property="respectSilentModeSwitch" destination="mlO-iy-zU2" id="TDT-cx-kCf"/>
<outlet property="syncingServiceLabel" destination="kLY-5g-v8n" id="zzx-qM-q1g"/> <outlet property="syncingServiceLabel" destination="kLY-5g-v8n" id="zzx-qM-q1g"/>
<outlet property="thumbstickHapticFeedbackEnabledSwitch" destination="s5f-Uz-GpH" id="ffp-3M-FDL"/> <outlet property="thumbstickHapticFeedbackEnabledSwitch" destination="19A-ef-F3V" id="K03-kQ-lv3"/>
<outlet property="versionLabel" destination="Str-BY-agW" id="gU2-L0-pYt"/> <outlet property="versionLabel" destination="Str-BY-agW" id="gU2-L0-pYt"/>
<segue destination="uBz-mm-mXr" kind="show" identifier="controllersSegue" id="MLY-hF-UB8"/> <segue destination="uBz-mm-mXr" kind="show" identifier="controllersSegue" id="MLY-hF-UB8"/>
<segue destination="56e-ul-z6v" kind="show" identifier="controllerSkinsSegue" id="GNM-Gt-YFf"/> <segue destination="56e-ul-z6v" kind="show" identifier="controllerSkinsSegue" id="GNM-Gt-YFf"/>
@ -1048,6 +1122,7 @@
<objects> <objects>
<navigationController automaticallyAdjustsScrollViewInsets="NO" id="0QR-U9-gtx" customClass="RSTNavigationController" sceneMemberID="viewController"> <navigationController automaticallyAdjustsScrollViewInsets="NO" id="0QR-U9-gtx" customClass="RSTNavigationController" sceneMemberID="viewController">
<toolbarItems/> <toolbarItems/>
<value key="contentSizeForViewInPopover" type="size" width="375" height="667"/>
<simulatedNavigationBarMetrics key="simulatedTopBarMetrics" barStyle="black" prompted="NO"/> <simulatedNavigationBarMetrics key="simulatedTopBarMetrics" barStyle="black" prompted="NO"/>
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" barStyle="black" id="Y5H-O6-CQ5"> <navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" barStyle="black" id="Y5H-O6-CQ5">
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/> <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
@ -1861,10 +1936,48 @@ Delta uses OpenVGDB to provide automatic artwork for imported games.</string>
</tableViewCell> </tableViewCell>
</cells> </cells>
</tableViewSection> </tableViewSection>
<tableViewSection headerTitle="Performance" footerTitle="When enabled, Delta will automatically enable JIT when on the same WiFi network as AltServer." id="MyM-jI-qtY" userLabel="Performance">
<cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="none" indentationWidth="10" reuseIdentifier="SwitchCell" id="uXJ-qB-E2e" customClass="SwitchTableViewCell">
<rect key="frame" x="0.0" y="284" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="uXJ-qB-E2e" id="mkz-9w-FlW">
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Use AltJIT" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" translatesAutoresizingMaskIntoConstraints="NO" id="XPc-dG-N6R">
<rect key="frame" x="16" y="11.5" width="286" height="21"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<nil key="textColor"/>
<nil key="highlightedColor"/>
</label>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="4Y4-gY-MaX">
<rect key="frame" x="310" y="6.5" width="51" height="31"/>
<color key="onTintColor" name="Purple"/>
<connections>
<action selector="toggleAltJITEnabled:" destination="OwL-4c-EEA" eventType="valueChanged" id="lfe-xg-J5o"/>
<action selector="togglePreviewsEnabled:" destination="eHi-aO-uGS" eventType="primaryActionTriggered" id="BKJ-dV-k7X"/>
</connections>
</switch>
</subviews>
<constraints>
<constraint firstAttribute="trailingMargin" secondItem="4Y4-gY-MaX" secondAttribute="trailing" id="6Rs-qs-gFM"/>
<constraint firstItem="XPc-dG-N6R" firstAttribute="leading" secondItem="mkz-9w-FlW" secondAttribute="leadingMargin" id="BBM-mW-kez"/>
<constraint firstItem="4Y4-gY-MaX" firstAttribute="centerY" secondItem="mkz-9w-FlW" secondAttribute="centerY" id="CY7-Kt-ggC"/>
<constraint firstItem="4Y4-gY-MaX" firstAttribute="leading" secondItem="XPc-dG-N6R" secondAttribute="trailing" constant="8" symbolic="YES" id="Qce-jc-vX3"/>
<constraint firstItem="XPc-dG-N6R" firstAttribute="centerY" secondItem="mkz-9w-FlW" secondAttribute="centerY" id="Xzp-aR-4Dz"/>
</constraints>
</tableViewCellContentView>
<connections>
<outlet property="switchView" destination="4Y4-gY-MaX" id="NDr-Y9-9RS"/>
</connections>
</tableViewCell>
</cells>
</tableViewSection>
<tableViewSection headerTitle="DS BIOS Files" footerTitle="Delta requires these BIOS files in order to play Nintendo DS games. Tap one to import it from Files." id="ObZ-cl-5sV"> <tableViewSection headerTitle="DS BIOS Files" footerTitle="Delta requires these BIOS files in order to play Nintendo DS games. Tap one to import it from Files." id="ObZ-cl-5sV">
<cells> <cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="gray" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="Cell" textLabel="Bfp-iA-wWE" detailTextLabel="Xpe-sd-GRy" style="IBUITableViewCellStyleValue1" id="ian-1X-SOi"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="gray" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="Cell" textLabel="Bfp-iA-wWE" detailTextLabel="Xpe-sd-GRy" style="IBUITableViewCellStyleValue1" id="ian-1X-SOi">
<rect key="frame" x="0.0" y="284" width="375" height="44"/> <rect key="frame" x="0.0" y="408" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="ian-1X-SOi" id="nE9-5Y-G2k"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="ian-1X-SOi" id="nE9-5Y-G2k">
<rect key="frame" x="0.0" y="0.0" width="349.5" height="44"/> <rect key="frame" x="0.0" y="0.0" width="349.5" height="44"/>
@ -1887,7 +2000,7 @@ Delta uses OpenVGDB to provide automatic artwork for imported games.</string>
</tableViewCellContentView> </tableViewCellContentView>
</tableViewCell> </tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="gray" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="Cell" textLabel="fgD-y0-55T" detailTextLabel="b8s-cx-IgW" style="IBUITableViewCellStyleValue1" id="dwT-0T-gFD"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="gray" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="Cell" textLabel="fgD-y0-55T" detailTextLabel="b8s-cx-IgW" style="IBUITableViewCellStyleValue1" id="dwT-0T-gFD">
<rect key="frame" x="0.0" y="328" width="375" height="44"/> <rect key="frame" x="0.0" y="452" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="dwT-0T-gFD" id="KEg-18-WYZ"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="dwT-0T-gFD" id="KEg-18-WYZ">
<rect key="frame" x="0.0" y="0.0" width="349.5" height="44"/> <rect key="frame" x="0.0" y="0.0" width="349.5" height="44"/>
@ -1910,7 +2023,7 @@ Delta uses OpenVGDB to provide automatic artwork for imported games.</string>
</tableViewCellContentView> </tableViewCellContentView>
</tableViewCell> </tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="gray" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="Cell" textLabel="SIu-zD-qfE" detailTextLabel="CW8-h0-YST" style="IBUITableViewCellStyleValue1" id="Tll-tX-97T"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="gray" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="Cell" textLabel="SIu-zD-qfE" detailTextLabel="CW8-h0-YST" style="IBUITableViewCellStyleValue1" id="Tll-tX-97T">
<rect key="frame" x="0.0" y="372" width="375" height="44"/> <rect key="frame" x="0.0" y="496" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Tll-tX-97T" id="4ca-AM-jBE"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Tll-tX-97T" id="4ca-AM-jBE">
<rect key="frame" x="0.0" y="0.0" width="349.5" height="44"/> <rect key="frame" x="0.0" y="0.0" width="349.5" height="44"/>
@ -1937,7 +2050,7 @@ Delta uses OpenVGDB to provide automatic artwork for imported games.</string>
<tableViewSection headerTitle="DSi BIOS Files" footerTitle="Delta requires these BIOS files in order to play Nintendo DSi games. Tap one to import it from Files." id="SAz-hG-O4G"> <tableViewSection headerTitle="DSi BIOS Files" footerTitle="Delta requires these BIOS files in order to play Nintendo DSi games. Tap one to import it from Files." id="SAz-hG-O4G">
<cells> <cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="gray" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="Cell" textLabel="QKd-rm-101" detailTextLabel="pJb-OR-TGs" style="IBUITableViewCellStyleValue1" id="jwN-8n-xgM"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="gray" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="Cell" textLabel="QKd-rm-101" detailTextLabel="pJb-OR-TGs" style="IBUITableViewCellStyleValue1" id="jwN-8n-xgM">
<rect key="frame" x="0.0" y="496" width="375" height="44"/> <rect key="frame" x="0.0" y="620" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="jwN-8n-xgM" id="b29-V1-qt3"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="jwN-8n-xgM" id="b29-V1-qt3">
<rect key="frame" x="0.0" y="0.0" width="349.5" height="44"/> <rect key="frame" x="0.0" y="0.0" width="349.5" height="44"/>
@ -1960,7 +2073,7 @@ Delta uses OpenVGDB to provide automatic artwork for imported games.</string>
</tableViewCellContentView> </tableViewCellContentView>
</tableViewCell> </tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="gray" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="Cell" textLabel="6OX-32-izR" detailTextLabel="2bc-8r-epB" style="IBUITableViewCellStyleValue1" id="3ka-mn-QqR"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="gray" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="Cell" textLabel="6OX-32-izR" detailTextLabel="2bc-8r-epB" style="IBUITableViewCellStyleValue1" id="3ka-mn-QqR">
<rect key="frame" x="0.0" y="540" width="375" height="44"/> <rect key="frame" x="0.0" y="664" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="3ka-mn-QqR" id="4ya-QS-s5w"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="3ka-mn-QqR" id="4ya-QS-s5w">
<rect key="frame" x="0.0" y="0.0" width="349.5" height="44"/> <rect key="frame" x="0.0" y="0.0" width="349.5" height="44"/>
@ -1983,7 +2096,7 @@ Delta uses OpenVGDB to provide automatic artwork for imported games.</string>
</tableViewCellContentView> </tableViewCellContentView>
</tableViewCell> </tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="gray" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="Cell" textLabel="Czu-qN-Luq" detailTextLabel="eVw-7r-BEf" style="IBUITableViewCellStyleValue1" id="4FF-9a-jq2"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="gray" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="Cell" textLabel="Czu-qN-Luq" detailTextLabel="eVw-7r-BEf" style="IBUITableViewCellStyleValue1" id="4FF-9a-jq2">
<rect key="frame" x="0.0" y="584" width="375" height="44"/> <rect key="frame" x="0.0" y="708" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="4FF-9a-jq2" id="emb-d3-TgY"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="4FF-9a-jq2" id="emb-d3-TgY">
<rect key="frame" x="0.0" y="0.0" width="349.5" height="44"/> <rect key="frame" x="0.0" y="0.0" width="349.5" height="44"/>
@ -2006,7 +2119,7 @@ Delta uses OpenVGDB to provide automatic artwork for imported games.</string>
</tableViewCellContentView> </tableViewCellContentView>
</tableViewCell> </tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="gray" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="Cell" textLabel="VWi-nu-uMv" detailTextLabel="8JD-uT-eoA" style="IBUITableViewCellStyleValue1" id="we3-0h-uKq"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="gray" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="Cell" textLabel="VWi-nu-uMv" detailTextLabel="8JD-uT-eoA" style="IBUITableViewCellStyleValue1" id="we3-0h-uKq">
<rect key="frame" x="0.0" y="628" width="375" height="44"/> <rect key="frame" x="0.0" y="752" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="we3-0h-uKq" id="cG1-a2-Nez"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="we3-0h-uKq" id="cG1-a2-Nez">
<rect key="frame" x="0.0" y="0.0" width="349.5" height="44"/> <rect key="frame" x="0.0" y="0.0" width="349.5" height="44"/>
@ -2033,7 +2146,7 @@ Delta uses OpenVGDB to provide automatic artwork for imported games.</string>
<tableViewSection headerTitle="" footerTitle="Changing cores may improve performance at the cost of additional features." id="hbM-mL-bIr"> <tableViewSection headerTitle="" footerTitle="Changing cores may improve performance at the cost of additional features." id="hbM-mL-bIr">
<cells> <cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="gray" indentationWidth="10" reuseIdentifier="ChangeCell" textLabel="Jmx-Jw-278" style="IBUITableViewCellStyleDefault" id="p1T-4d-fC3"> <tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="gray" indentationWidth="10" reuseIdentifier="ChangeCell" textLabel="Jmx-Jw-278" style="IBUITableViewCellStyleDefault" id="p1T-4d-fC3">
<rect key="frame" x="0.0" y="737.5" width="375" height="44"/> <rect key="frame" x="0.0" y="861.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/> <autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="p1T-4d-fC3" id="3bs-Bp-nd4"> <tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="p1T-4d-fC3" id="3bs-Bp-nd4">
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/> <rect key="frame" x="0.0" y="0.0" width="375" height="44"/>

View File

@ -21,7 +21,8 @@ class ListMenuViewController: UITableViewController
override var preferredContentSize: CGSize { override var preferredContentSize: CGSize {
get { get {
let navigationBarHeight = self.navigationController?.navigationBar.bounds.height ?? 0.0 // Don't include navigation bar height in calculation (as of iOS 13).
let navigationBarHeight = 0.0 // self.navigationController?.navigationBar.bounds.height ?? 0.0
return CGSize(width: 0, height: (self.tableView.rowHeight * CGFloat(self.items.count)) + navigationBarHeight) return CGSize(width: 0, height: (self.tableView.rowHeight * CGFloat(self.items.count)) + navigationBarHeight)
} }
set {} set {}

View File

@ -38,11 +38,23 @@ extension UINavigationBar
private var _defaultTitleTextAttributes: [NSAttributedString.Key: Any]? { private var _defaultTitleTextAttributes: [NSAttributedString.Key: Any]? {
guard self.titleTextAttributes == nil else { return self.titleTextAttributes } guard self.titleTextAttributes == nil else { return self.titleTextAttributes }
guard guard let contentView = self.subviews.first(where: { NSStringFromClass(type(of: $0)).contains("ContentView") || NSStringFromClass(type(of: $0)).contains("ItemView") })
let contentView = self.subviews.first(where: { NSStringFromClass(type(of: $0)).contains("ContentView") || NSStringFromClass(type(of: $0)).contains("ItemView") }),
let titleLabel = contentView.subviews.first(where: { $0 is UILabel }) as? UILabel
else { return nil } else { return nil }
let containerView: UIView
if #available(iOS 16, *)
{
guard let titleControl = contentView.subviews.first(where: { NSStringFromClass(type(of: $0)).contains("Title") }) else { return nil }
containerView = titleControl
}
else
{
containerView = contentView
}
guard let titleLabel = containerView.subviews.first(where: { $0 is UILabel }) as? UILabel else { return nil }
let textAttributes = titleLabel.attributedText?.attributes(at: 0, effectiveRange: nil) let textAttributes = titleLabel.attributedText?.attributes(at: 0, effectiveRange: nil)
return textAttributes return textAttributes
} }

View File

@ -0,0 +1,143 @@
//
// CheatBase.swift
// Delta
//
// Created by Riley Testut on 1/17/23.
// Copyright © 2023 Riley Testut. All rights reserved.
//
import Foundation
import SQLite
import Roxas
private extension UserDefaults
{
@NSManaged var previousCheatBaseVersion: Int
}
extension ExpressionType
{
static var cheatID: SQLite.Expression<Int> {
return SQLite.Expression<Int>("cheatID")
}
static var cheatName: SQLite.Expression<String> {
return SQLite.Expression<String>("cheatName")
}
static var cheatDescription: SQLite.Expression<String?> {
return SQLite.Expression<String?>("cheatDescription")
}
static var cheatCode: SQLite.Expression<String> {
return SQLite.Expression<String>("cheatCode")
}
static var cheatDeviceID: SQLite.Expression<Int> {
return SQLite.Expression<Int>("cheatDeviceID")
}
static var cheatActivation: SQLite.Expression<String?> {
return SQLite.Expression<String?>("cheatActivation")
}
static var cheatCategoryID: SQLite.Expression<Int> {
return SQLite.Expression<Int>("cheatCategoryID")
}
static var cheatCategoryName: SQLite.Expression<String> {
return SQLite.Expression<String>("cheatCategory")
}
static var cheatCategoryDescription: SQLite.Expression<String> {
return SQLite.Expression<String>("cheatCategoryDescription")
}
}
extension Table
{
static var cheats: Table {
return Table("CHEATS")
}
static var cheatCategories: Table {
return Table("CHEAT_CATEGORIES")
}
}
@available(iOS 14, *)
class CheatBase: GamesDatabase
{
static let cheatsVersion = 1
static var previousCheatsVersion: Int? {
return UserDefaults.standard.previousCheatBaseVersion
}
private let connection: Connection
override init() throws
{
let fileURL = DatabaseManager.cheatBaseURL
guard FileManager.default.fileExists(atPath: fileURL.path) else { throw GamesDatabase.Error.doesNotExist }
self.connection = try Connection(fileURL.path)
try super.init()
UserDefaults.standard.previousCheatBaseVersion = CheatBase.cheatsVersion
}
func cheats(for game: Game) async throws -> [CheatMetadata]?
{
let metadata = await withCheckedContinuation { continuation in
if let context = game.managedObjectContext
{
context.perform {
let metadata = self.metadata(for: game)
continuation.resume(returning: metadata)
}
}
else
{
let metadata = self.metadata(for: game)
continuation.resume(returning: metadata)
}
}
guard let romIDValue = metadata?.romID else { return nil }
let cheatID = Expression<Any>.cheatID
let cheatName = Expression<Any>.cheatName
let cheatCode = Expression<Any>.cheatCode
let cheatDescription = Expression<Any>.cheatDescription
let cheatActivation = Expression<Any>.cheatActivation
let cheatDeviceID = Expression<Any>.cheatDeviceID
let categoryID = Expression<Any>.cheatCategoryID
let categoryName = Expression<Any>.cheatCategoryName
let categoryDescription = Expression<Any>.cheatCategoryDescription
let romID = Expression<Any>.romID
let query = Table.cheats.select(cheatID, cheatName, cheatCode, cheatDescription, cheatActivation, cheatDeviceID, Table.cheats[categoryID], categoryName, categoryDescription)
.filter(romID == romIDValue)
.join(Table.cheatCategories, on: Table.cheats[categoryID] == Table.cheatCategories[categoryID])
.order(cheatName)
let rows = try self.connection.prepare(query)
let results = rows.compactMap { (row) -> CheatMetadata? in
guard case let deviceID = Int16(row[cheatDeviceID]), let device = CheatDevice(rawValue: deviceID) else { return nil }
let id = row[Table.cheats[categoryID]]
let category = CheatCategory(id: id, name: row[categoryName], categoryDescription: row[categoryDescription])
let metadata = CheatMetadata(id: row[cheatID], name: row[cheatName], code: row[cheatCode], description: row[cheatDescription], activationHint: row[cheatActivation], device: device, category: category)
return metadata
}
return results
}
}

View File

@ -0,0 +1,273 @@
//
// CheatBaseView.swift
// Delta
//
// Created by Riley Testut on 1/17/23.
// Copyright © 2023 Riley Testut. All rights reserved.
//
import SwiftUI
import enum SQLite.Result
@available(iOS 14, *)
extension CheatBaseView
{
private class ViewModel: ObservableObject
{
@Published
var allCheats: [CheatMetadata]? {
didSet {
guard let cheats = allCheats else {
self.cheatsByCategory = nil
return
}
let cheatsByCategory = Dictionary(grouping: cheats, by: { $0.category }).sorted { $0.key.id < $1.key.id }
self.cheatsByCategory = cheatsByCategory
}
}
@Published
private(set) var cheatsByCategory: [(CheatCategory, [CheatMetadata])]?
@Published
private(set) var error: Error?
@Published
var searchText: String = "" {
didSet {
self.searchCheats()
}
}
@Published
private(set) var filteredCheats: [CheatMetadata]?
@MainActor
func fetchCheats(for game: Game) async
{
guard self.allCheats == nil else { return }
do
{
let database = try CheatBase()
let cheats = try await database.cheats(for: game) ?? []
self.allCheats = cheats
}
catch
{
self.error = error
}
}
private func searchCheats()
{
if let cheats = self.allCheats, !self.searchText.isEmpty
{
let predicate = NSPredicate(forSearchingForText: self.searchText, inValuesForKeyPaths: [#keyPath(CheatMetadata.name), #keyPath(CheatMetadata.cheatDescription)])
let filteredCheats = cheats.filter { predicate.evaluate(with: $0) }
self.filteredCheats = filteredCheats
}
else
{
self.filteredCheats = nil
}
}
}
}
@available(iOS 14, *)
struct CheatBaseView: View
{
let game: Game?
var cancellationHandler: (() -> Void)?
var selectionHandler: ((CheatMetadata) -> Void)?
@StateObject
private var viewModel = ViewModel()
@State
private var activationHintCheat: CheatMetadata?
var body: some View {
NavigationView {
ZStack {
if let cheats = viewModel.allCheats, !cheats.isEmpty
{
// Only show List if there is at least one cheat for this game.
cheatList()
}
// Place above List
placeholderView()
}
.alert(item: $activationHintCheat) { cheat in
Alert(title: Text("How to Activate"),
message: Text(cheat.activationHint ?? ""),
dismissButton: .default(Text("OK")))
}
.navigationTitle(Text(game?.name ?? "CheatBase"))
.navigationBarTitleDisplayMode(.inline)
.toolbar {
ToolbarItem(placement: .cancellationAction) {
Button("Cancel") {
cancellationHandler?()
}
}
}
}
.onAppear {
Task {
guard let game = self.game else { return }
await viewModel.fetchCheats(for: game)
}
}
}
private func cheatList() -> some View
{
VStack {
if #unavailable(iOS 15)
{
LegacySearchBar(text: $viewModel.searchText)
}
let listView = List {
if let filteredCheats = viewModel.filteredCheats
{
ForEach(filteredCheats) { cheat in
cell(for: cheat)
}
}
else if let cheats = viewModel.cheatsByCategory
{
ForEach(cheats, id: \.0.id) { (category, cheats) in
Section {
DisclosureGroup {
ForEach(cheats) { cheat in
cell(for: cheat)
}
} label: {
Text(category.name)
}
} footer: {
Text(category.categoryDescription)
}
}
}
}
if #available(iOS 15, *)
{
listView.searchable(text: $viewModel.searchText)
}
else
{
listView
}
}
.listStyle(.insetGrouped)
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .top)
}
private func cell(for cheat: CheatMetadata) -> some View
{
ZStack(alignment: .leading) {
Button(action: { choose(cheat) }) {}
HStack {
// Name + Description
VStack(alignment: .leading, spacing: 4) {
Text(cheat.name)
if let description = cheat.cheatDescription
{
Text(description)
.font(.caption)
}
}
// Activation Hint
if cheat.activationHint != nil
{
Spacer()
Button(action: { activationHintCheat = cheat }) {
Image(systemName: "info.circle")
}
.buttonStyle(.borderless)
}
}
.multilineTextAlignment(.leading)
}
}
private func placeholderView() -> some View
{
VStack(spacing: 8) {
if let error = viewModel.error
{
Text("Unable to Load Cheats")
.font(.title)
if let error = error as? SQLite.Result
{
// SQLite.Result implements CustomStringConvertible.description, but not localizedDescription.
Text(String(describing: error))
.font(.callout)
}
else
{
Text(error.localizedDescription)
.font(.callout)
}
}
else if let filteredCheats = viewModel.filteredCheats, filteredCheats.isEmpty
{
Text("Cheat Not Found")
.font(.title)
Text("Please make sure the name is correct, or try searching for another cheat.")
.font(.callout)
}
else if let cheats = viewModel.allCheats, cheats.isEmpty
{
Text("No Cheats")
.font(.title)
Text("There are no cheats for this game in Delta's CheatBase. Please try a different game.")
.font(.callout)
}
else if viewModel.allCheats == nil
{
ProgressView()
.progressViewStyle(.circular)
}
}
.frame(minWidth: 0, maxWidth: .infinity, minHeight: 0, maxHeight: .infinity, alignment: .center)
.foregroundColor(.gray)
.padding()
}
init(game: Game, cheats: [CheatMetadata]? = nil)
{
self.game = game
let viewModel = ViewModel()
viewModel.allCheats = cheats
self._viewModel = StateObject(wrappedValue: viewModel)
}
}
@available(iOS 14, *)
private extension CheatBaseView
{
func choose(_ cheatMetadata: CheatMetadata)
{
self.selectionHandler?(cheatMetadata)
}
}

View File

@ -0,0 +1,111 @@
//
// CheatDevice.swift
// Delta
//
// Created by Riley Testut on 1/30/23.
// Copyright © 2023 Riley Testut. All rights reserved.
//
import Foundation
import DeltaCore
import NESDeltaCore
@objc
enum CheatDevice: Int16
{
case famicomGameGenie = 1
case famicomRaw = 2
case famicomRawCompare = 3
case gbGameGenie = 4
case gbaActionReplayMax = 5
case gbaCodeBreaker = 6
case gbaGameShark = 7
case gbcGameShark = 8
case n64GameShark = 9
case dsActionReplay = 10
case dsCodeBreaker = 11
case nesGameGenie = 12
case nesRaw = 13
case nesRawCompare = 14
case snesActionReplay = 15
case snesGameGenie = 16
case gameGearActionReplay = 17
case gameGearGameGenie = 18
case masterSystemActionReplay = 19
case masterSystemGameGenie = 20
case cdActionReplay10 = 21
case cdActionReplay8 = 22
case genesisActionReplay10 = 23
case genesisActionReplay8 = 24
}
extension CheatDevice
{
var cheatType: CheatType? {
switch self
{
case .snesActionReplay, .gbaActionReplayMax, .dsActionReplay, .gameGearActionReplay, .masterSystemActionReplay, .genesisActionReplay8, .genesisActionReplay10, .cdActionReplay8, .cdActionReplay10:
return .actionReplay
case .n64GameShark, .gbcGameShark, .gbaGameShark:
return .gameShark
case .famicomGameGenie, .snesGameGenie, .gbGameGenie, .gameGearGameGenie, .masterSystemGameGenie:
return .gameGenie
case .nesGameGenie:
return CheatType(rawValue: DeltaCore.CheatType.gameGenie8.rawValue)
case .gbaCodeBreaker, .dsCodeBreaker:
return .codeBreaker
case .famicomRaw, .famicomRawCompare:
return nil
case .nesRaw, .nesRawCompare:
return nil
}
}
var gameType: GameType? {
switch self
{
case .famicomGameGenie, .famicomRaw, .famicomRawCompare: return .nes
case .nesGameGenie, .nesRaw, .nesRawCompare: return .nes
case .snesActionReplay, .snesGameGenie: return .snes
case .n64GameShark: return .n64
case .gbGameGenie, .gbcGameShark: return .gbc
case .gbaActionReplayMax, .gbaGameShark, .gbaCodeBreaker: return .gba
case .dsActionReplay, .dsCodeBreaker: return .ds
case .genesisActionReplay8, .genesisActionReplay10: return .genesis
case .cdActionReplay8, .cdActionReplay10: return .genesis
// Not yet supported
case .gameGearActionReplay, .gameGearGameGenie: return nil
case .masterSystemActionReplay, .masterSystemGameGenie: return nil
}
}
var cheatFormat: CheatFormat? {
guard
let cheatType = self.cheatType,
let gameType = self.gameType,
let deltaCore = Delta.core(for: gameType)
else { return nil }
let cheatFormat = deltaCore.supportedCheatFormats.first { $0.type == cheatType }
return cheatFormat
}
}

View File

@ -0,0 +1,45 @@
//
// CheatMetadata.swift
// Delta
//
// Created by Riley Testut on 1/17/23.
// Copyright © 2023 Riley Testut. All rights reserved.
//
import UIKit
import DeltaCore
struct CheatCategory: Identifiable, Hashable
{
var id: Int
var name: String
var categoryDescription: String
}
@objcMembers // @objcMembers required for NSPredicate-based filtering.
final class CheatMetadata: NSObject, Identifiable
{
let id: Int
let name: String
let code: String
let cheatDescription: String?
let activationHint: String?
let device: CheatDevice
let category: CheatCategory
init(id: Int, name: String, code: String, description: String?, activationHint: String?, device: CheatDevice, category: CheatCategory)
{
self.id = id
self.name = name
self.code = code
self.cheatDescription = description
self.activationHint = activationHint
self.device = device
self.category = category
}
}

View File

@ -0,0 +1,51 @@
//
// LegacySearchBar.swift
// Delta
//
// Created by Riley Testut on 1/25/23.
// Copyright © 2023 Riley Testut. All rights reserved.
//
import UIKit
import SwiftUI
@available(iOS 13, *)
struct LegacySearchBar: UIViewRepresentable
{
class Coordinator: NSObject, UISearchBarDelegate
{
@Binding
var text: String
init(text: Binding<String>)
{
self._text = text
}
func searchBar(_ searchBar: UISearchBar, textDidChange searchText: String)
{
self.text = searchText
}
}
@Binding
var text: String
func makeUIView(context: Context) -> UISearchBar
{
let searchBar = UISearchBar(frame: .zero)
searchBar.delegate = context.coordinator
searchBar.placeholder = NSLocalizedString("Search", comment: "")
return searchBar
}
func updateUIView(_ uiView: UISearchBar, context: Context)
{
uiView.text = self.text
}
func makeCoordinator() -> Coordinator
{
return Coordinator(text: $text)
}
}

View File

@ -255,10 +255,27 @@ private extension DatabaseManager
do do
{ {
if !FileManager.default.fileExists(atPath: DatabaseManager.gamesDatabaseURL.path) if !FileManager.default.fileExists(atPath: DatabaseManager.gamesDatabaseURL.path) || GamesDatabase.version != GamesDatabase.previousVersion
{ {
guard let bundleURL = Bundle.main.url(forResource: "openvgdb", withExtension: "sqlite") else { throw GamesDatabase.Error.doesNotExist } guard let bundleURL = Bundle.main.url(forResource: "openvgdb", withExtension: "sqlite") else { throw GamesDatabase.Error.doesNotExist }
try FileManager.default.copyItem(at: bundleURL, to: DatabaseManager.gamesDatabaseURL) try FileManager.default.copyItem(at: bundleURL, to: DatabaseManager.gamesDatabaseURL, shouldReplace: true)
}
if #available(iOS 14, *), !FileManager.default.fileExists(atPath: DatabaseManager.cheatBaseURL.path) || CheatBase.cheatsVersion != CheatBase.previousCheatsVersion
{
guard let archiveURL = Bundle.main.url(forResource: "cheatbase", withExtension: "zip") else { throw GamesDatabase.Error.doesNotExist }
let temporaryDirectoryURL = FileManager.default.uniqueTemporaryURL()
try FileManager.default.createDirectory(at: temporaryDirectoryURL, withIntermediateDirectories: true)
defer {
try? FileManager.default.removeItem(at: temporaryDirectoryURL)
}
// Unzip to temporaryDirectoryURL first to ensure we don't accidentally unzip other items into DatabaseManager.cheatBaseURL directory (e.g. __MACOSX directory).
try FileManager.default.unzipItem(at: archiveURL, to: temporaryDirectoryURL, skipCRC32: true) // skipCRC32 to avoid ~10 second extraction.
let extractedDatabaseURL = temporaryDirectoryURL.appendingPathComponent("cheatbase.sqlite")
try FileManager.default.copyItem(at: extractedDatabaseURL, to: DatabaseManager.cheatBaseURL, shouldReplace: true)
} }
self.gamesDatabase = try GamesDatabase() self.gamesDatabase = try GamesDatabase()
@ -618,6 +635,12 @@ extension DatabaseManager
let gamesDatabaseURL = self.defaultDirectoryURL().appendingPathComponent("openvgdb.sqlite") let gamesDatabaseURL = self.defaultDirectoryURL().appendingPathComponent("openvgdb.sqlite")
return gamesDatabaseURL return gamesDatabaseURL
} }
class var cheatBaseURL: URL
{
let gamesDatabaseURL = self.defaultDirectoryURL().appendingPathComponent("cheatbase.sqlite")
return gamesDatabaseURL
}
class var gamesDirectoryURL: URL class var gamesDirectoryURL: URL
{ {

View File

@ -71,11 +71,6 @@ extension ControllerSkin: ControllerSkinProtocol
return self.controllerSkin?.thumbstick(for: item, traits: traits, preferredSize: preferredSize) return self.controllerSkin?.thumbstick(for: item, traits: traits, preferredSize: preferredSize)
} }
public func inputs(for traits: DeltaCore.ControllerSkin.Traits, at point: CGPoint) -> [Input]?
{
return self.controllerSkin?.inputs(for: traits, at: point)
}
public func items(for traits: DeltaCore.ControllerSkin.Traits) -> [DeltaCore.ControllerSkin.Item]? public func items(for traits: DeltaCore.ControllerSkin.Traits) -> [DeltaCore.ControllerSkin.Item]?
{ {
return self.controllerSkin?.items(for: traits) return self.controllerSkin?.items(for: traits)

View File

@ -45,12 +45,16 @@ public class Game: _Game, GameProtocol
// Recreate the stored URL relative to current sandbox location. // Recreate the stored URL relative to current sandbox location.
artworkURL = URL(fileURLWithPath: unwrappedArtworkURL.relativePath, relativeTo: DatabaseManager.gamesDirectoryURL) artworkURL = URL(fileURLWithPath: unwrappedArtworkURL.relativePath, relativeTo: DatabaseManager.gamesDirectoryURL)
} }
else if unwrappedArtworkURL.host?.lowercased() == "img.gamefaqs.net", var components = URLComponents(url: unwrappedArtworkURL, resolvingAgainstBaseURL: false) else if let host = unwrappedArtworkURL.host?.lowercased(), host == "img.gamefaqs.net" || host == "gamefaqs1.cbsistatic.com",
var components = URLComponents(url: unwrappedArtworkURL, resolvingAgainstBaseURL: false)
{ {
// Quick fix for broken album artwork URLs due to host change. // Quick fix for broken album artwork URLs due to host change.
components.host = "gamefaqs1.cbsistatic.com" components.host = "gamefaqs.gamespot.com"
components.scheme = "https" components.scheme = "https"
let updatedPath = "/a" + components.path
components.path = updatedPath
if let url = components.url if let url = components.url
{ {
artworkURL = url artworkURL = url

View File

@ -11,15 +11,17 @@ import Foundation
// Must be an NSObject subclass so it can be used with RSTCellContentDataSource. // Must be an NSObject subclass so it can be used with RSTCellContentDataSource.
class GameMetadata: NSObject class GameMetadata: NSObject
{ {
let identifier: Int let releaseID: Int
let romID: Int
let name: String? let name: String?
let artworkURL: URL? let artworkURL: URL?
init(identifier: Int, name: String?, artworkURL: URL?) init(releaseID: Int, romID: Int, name: String?, artworkURL: URL?)
{ {
self.releaseID = releaseID
self.romID = romID
self.name = name self.name = name
self.identifier = identifier
self.artworkURL = artworkURL self.artworkURL = artworkURL
} }
} }
@ -27,13 +29,13 @@ class GameMetadata: NSObject
extension GameMetadata extension GameMetadata
{ {
override var hash: Int { override var hash: Int {
return self.identifier.hashValue return self.releaseID.hashValue ^ self.romID.hashValue
} }
override func isEqual(_ object: Any?) -> Bool override func isEqual(_ object: Any?) -> Bool
{ {
guard let metadata = object as? GameMetadata else { return false } guard let metadata = object as? GameMetadata else { return false }
return self.identifier == metadata.identifier return self.releaseID == metadata.releaseID && self.romID == metadata.romID
} }
} }

View File

@ -57,16 +57,26 @@ extension VirtualTable
extension GamesDatabase extension GamesDatabase
{ {
enum Error: Swift.Error enum Error: LocalizedError
{ {
case doesNotExist case doesNotExist
case connection(Swift.Error)
var errorDescription: String? {
switch self
{
case .doesNotExist:
return NSLocalizedString("The SQLite database could not be found.", comment: "")
}
}
} }
} }
class GamesDatabase class GamesDatabase
{ {
static let version = -1 static let version = 3
static var previousVersion: Int? {
return UserDefaults.standard.previousGamesDatabaseVersion
}
private let connection: Connection private let connection: Connection
@ -80,7 +90,7 @@ class GamesDatabase
} }
catch catch
{ {
throw Error.connection(error) throw error
} }
self.invalidateVirtualTableIfNeeded() self.invalidateVirtualTableIfNeeded()
@ -89,10 +99,11 @@ class GamesDatabase
func metadataResults(forGameName gameName: String) -> [GameMetadata] func metadataResults(forGameName gameName: String) -> [GameMetadata]
{ {
let releaseID = Expression<Any>.releaseID let releaseID = Expression<Any>.releaseID
let romID = Expression<Any>.romID
let name = Expression<Any>.name let name = Expression<Any>.name
let artworkAddress = Expression<Any>.artworkAddress let artworkAddress = Expression<Any>.artworkAddress
let query = VirtualTable.search.select(releaseID, name, artworkAddress).filter(name.match(gameName + "*")) let query = VirtualTable.search.select(releaseID, romID, name, artworkAddress).filter(name.match(gameName + "*"))
do do
{ {
@ -111,7 +122,7 @@ class GamesDatabase
} }
let metadata = GameMetadata(identifier: row[releaseID], name: row[name], artworkURL: artworkURL) let metadata = GameMetadata(releaseID: row[releaseID], romID: row[romID], name: row[name], artworkURL: artworkURL)
return metadata return metadata
} }
@ -145,7 +156,7 @@ class GamesDatabase
let romID = Expression<Any>.romID let romID = Expression<Any>.romID
let gameHash = game.identifier.uppercased() let gameHash = game.identifier.uppercased()
let query = Table.roms.select(releaseID, name, artworkAddress).filter(sha1Hash == gameHash).join(Table.releases, on: Table.roms[romID] == Table.releases[romID]) let query = Table.roms.select(releaseID, name, artworkAddress, Table.roms[romID]).filter(sha1Hash == gameHash).join(Table.releases, on: Table.roms[romID] == Table.releases[romID])
do do
{ {
@ -161,7 +172,7 @@ class GamesDatabase
artworkURL = nil artworkURL = nil
} }
let metadata = GameMetadata(identifier: row[releaseID], name: row[name], artworkURL: artworkURL) let metadata = GameMetadata(releaseID: row[releaseID], romID: row[Table.roms[romID]], name: row[name], artworkURL: artworkURL)
return metadata return metadata
} }
} }
@ -197,12 +208,13 @@ private extension GamesDatabase
let name = Expression<Any>.name let name = Expression<Any>.name
let artworkAddress = Expression<Any>.artworkAddress let artworkAddress = Expression<Any>.artworkAddress
let releaseID = Expression<Any>.releaseID let releaseID = Expression<Any>.releaseID
let romID = Expression<Any>.romID
do do
{ {
try self.connection.run(VirtualTable.search.create(.FTS4([releaseID, name, artworkAddress], tokenize: .Unicode61()))) try self.connection.run(VirtualTable.search.create(.FTS4([releaseID, romID, name, artworkAddress], tokenize: .Unicode61())))
let update = VirtualTable.search.insert(Table.releases.select(releaseID, name, artworkAddress)) let update = VirtualTable.search.insert(Table.releases.select(releaseID, romID, name, artworkAddress))
_ = try self.connection.run(update) _ = try self.connection.run(update)
} }
catch catch

View File

@ -15,6 +15,8 @@ extension UIActivity.ActivityType
class CopyDeepLinkActivity: UIActivity class CopyDeepLinkActivity: UIActivity
{ {
private var deepLink: URL?
override class var activityCategory: UIActivity.Category { override class var activityCategory: UIActivity.Category {
return .action return .action
} }
@ -28,7 +30,7 @@ class CopyDeepLinkActivity: UIActivity
} }
override var activityImage: UIImage? { override var activityImage: UIImage? {
return UIImage(named: "Link") return UIImage(symbolNameIfAvailable: "link") ?? UIImage(named: "Link")
} }
override func canPerform(withActivityItems activityItems: [Any]) -> Bool override func canPerform(withActivityItems activityItems: [Any]) -> Bool
@ -47,7 +49,19 @@ class CopyDeepLinkActivity: UIActivity
{ {
guard let game = activityItems.first(where: { $0 is Game }) as? Game else { return } guard let game = activityItems.first(where: { $0 is Game }) as? Game else { return }
let deepLink = URL(action: .launchGame(identifier: game.identifier)) self.deepLink = URL(action: .launchGame(identifier: game.identifier))
UIPasteboard.general.url = deepLink }
override func perform()
{
if let deepLink = self.deepLink
{
UIPasteboard.general.url = deepLink
self.activityDidFinish(true)
}
else
{
self.activityDidFinish(false)
}
} }
} }

View File

@ -23,8 +23,16 @@ extension UIViewController
struct DeepLinkController struct DeepLinkController
{ {
private var window: UIWindow? { private var window: UIWindow? {
guard let delegate = UIApplication.shared.delegate, let window = delegate.window else { return nil } if #available(iOS 13, *)
return window {
guard let delegate = UIApplication.shared.connectedScenes.lazy.compactMap({ $0.delegate as? UIWindowSceneDelegate }).first, let window = delegate.window else { return nil }
return window
}
else
{
guard let delegate = UIApplication.shared.delegate, let window = delegate.window else { return nil }
return window
}
} }
private var topViewController: UIViewController? { private var topViewController: UIViewController? {

View File

@ -10,11 +10,13 @@ import UIKit
import DeltaCore import DeltaCore
import GBADeltaCore import GBADeltaCore
import MelonDSDeltaCore
import Systems import Systems
import struct DSDeltaCore.DS import struct DSDeltaCore.DS
import Roxas import Roxas
import AltKit
private var kvoContext = 0 private var kvoContext = 0
@ -110,6 +112,7 @@ class GameViewController: DeltaCore.GameViewController
} }
self.updateControllers() self.updateControllers()
self.updateAudio()
self.presentedGyroAlert = false self.presentedGyroAlert = false
} }
@ -167,6 +170,8 @@ class GameViewController: DeltaCore.GameViewController
private var isGyroActive = false private var isGyroActive = false
private var presentedGyroAlert = false private var presentedGyroAlert = false
private var presentedJITAlert = false
override var shouldAutorotate: Bool { override var shouldAutorotate: Bool {
return !self.isGyroActive return !self.isGyroActive
} }
@ -205,6 +210,8 @@ class GameViewController: DeltaCore.GameViewController
NotificationCenter.default.addObserver(self, selector: #selector(GameViewController.didDeactivateGyro(with:)), name: GBA.didDeactivateGyroNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(GameViewController.didDeactivateGyro(with:)), name: GBA.didDeactivateGyroNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(GameViewController.emulationDidQuit(with:)), name: EmulatorCore.emulationDidQuitNotification, object: nil) NotificationCenter.default.addObserver(self, selector: #selector(GameViewController.emulationDidQuit(with:)), name: EmulatorCore.emulationDidQuitNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(GameViewController.didEnableJIT(with:)), name: ServerManager.didEnableJITNotification, object: nil)
} }
deinit deinit
@ -330,12 +337,18 @@ extension GameViewController
UserDefaults.standard.desmumeDeprecatedAlertCount += 1 UserDefaults.standard.desmumeDeprecatedAlertCount += 1
} }
else if self.emulatorCore?.deltaCore == MelonDS.core, ProcessInfo.processInfo.isJITAvailable
{
self.showJITEnabledAlert()
}
} }
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator) override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator)
{ {
super.viewWillTransition(to: size, with: coordinator) super.viewWillTransition(to: size, with: coordinator)
guard UIApplication.shared.applicationState != .background else { return }
coordinator.animate(alongsideTransition: { (context) in coordinator.animate(alongsideTransition: { (context) in
self.updateControllerSkin() self.updateControllerSkin()
}, completion: nil) }, completion: nil)
@ -474,6 +487,13 @@ extension GameViewController
} }
self._isLoadingSaveState = false self._isLoadingSaveState = false
if self.emulatorCore?.deltaCore == MelonDS.core, ProcessInfo.processInfo.isJITAvailable
{
self.transitionCoordinator?.animate(alongsideTransition: nil, completion: { (context) in
self.showJITEnabledAlert()
})
}
} }
case "unwindToGames": case "unwindToGames":
@ -646,12 +666,14 @@ private extension GameViewController
else if let controllerSkin = DeltaCore.ControllerSkin.standardControllerSkin(for: game.type), controllerSkin.hasTouchScreen(for: traits) else if let controllerSkin = DeltaCore.ControllerSkin.standardControllerSkin(for: game.type), controllerSkin.hasTouchScreen(for: traits)
{ {
var touchControllerSkin = TouchControllerSkin(controllerSkin: controllerSkin) var touchControllerSkin = TouchControllerSkin(controllerSkin: controllerSkin)
touchControllerSkin.layoutGuide = self.view.safeAreaLayoutGuide
switch traits.orientation if self.view.bounds.width > self.view.bounds.height
{ {
case .portrait: touchControllerSkin.screenLayoutAxis = .vertical touchControllerSkin.screenLayoutAxis = .horizontal
case .landscape: touchControllerSkin.screenLayoutAxis = .horizontal }
else
{
touchControllerSkin.screenLayoutAxis = .vertical
} }
self.controllerView.controllerSkin = touchControllerSkin self.controllerView.controllerSkin = touchControllerSkin
@ -914,6 +936,16 @@ extension GameViewController: CheatsViewControllerDelegate
} }
} }
//MARK: - Audio -
/// Audio
private extension GameViewController
{
func updateAudio()
{
self.emulatorCore?.audioManager.respectsSilentMode = Settings.respectSilentMode
}
}
//MARK: - Sustain Buttons - //MARK: - Sustain Buttons -
private extension GameViewController private extension GameViewController
{ {
@ -934,6 +966,8 @@ private extension GameViewController
UIView.animate(withDuration: 0.4) { UIView.animate(withDuration: 0.4) {
self.sustainButtonsBlurView.effect = blurEffect self.sustainButtonsBlurView.effect = blurEffect
self.sustainButtonsBackgroundView.alpha = 1.0 self.sustainButtonsBackgroundView.alpha = 1.0
} completion: { _ in
self.controllerView.becomeFirstResponder()
} }
} }
@ -1061,6 +1095,8 @@ extension GameViewController: GameViewControllerDelegate
else if self.presentedViewController == nil else if self.presentedViewController == nil
{ {
self.pauseEmulation() self.pauseEmulation()
self.controllerView.resignFirstResponder()
self.performSegue(withIdentifier: "pause", sender: gameController) self.performSegue(withIdentifier: "pause", sender: gameController)
} }
} }
@ -1085,6 +1121,48 @@ private extension GameViewController
toastView.presentationEdge = .top toastView.presentationEdge = .top
toastView.show(in: self.view, duration: duration) toastView.show(in: self.view, duration: duration)
} }
func showJITEnabledAlert()
{
guard !self.presentedJITAlert, self.presentedViewController == nil, self.game != nil else { return }
self.presentedJITAlert = true
func presentToastView()
{
let detailText: String?
let duration: TimeInterval
if UserDefaults.standard.jitEnabledAlertCount < 3
{
detailText = NSLocalizedString("You can now Fast Forward DS games up to 3x speed.", comment: "")
duration = 5.0
}
else
{
detailText = nil
duration = 2.0
}
let toastView = RSTToastView(text: NSLocalizedString("JIT Compilation Enabled", comment: ""), detailText: detailText)
toastView.edgeOffset.vertical = 8
self.show(toastView, duration: duration)
UserDefaults.standard.jitEnabledAlertCount += 1
}
DispatchQueue.main.async {
if let transitionCoordinator = self.transitionCoordinator
{
transitionCoordinator.animate(alongsideTransition: nil) { (context) in
presentToastView()
}
}
else
{
presentToastView()
}
}
}
} }
//MARK: - Notifications - //MARK: - Notifications -
@ -1127,9 +1205,13 @@ private extension GameViewController
self.updateControllerSkin() self.updateControllerSkin()
} }
case .translucentControllerSkinOpacity: self.controllerView.translucentControllerSkinOpacity = Settings.translucentControllerSkinOpacity case .translucentControllerSkinOpacity:
self.controllerView.translucentControllerSkinOpacity = Settings.translucentControllerSkinOpacity
case .syncingService: break case .respectSilentMode:
self.updateAudio()
case .syncingService, .isAltJITEnabled: break
} }
} }
@ -1207,6 +1289,60 @@ private extension GameViewController
self.isGyroActive = false self.isGyroActive = false
} }
@objc func didEnableJIT(with notification: Notification)
{
DispatchQueue.main.async {
self.showJITEnabledAlert()
}
DispatchQueue.global(qos: .utility).async {
guard let emulatorCore = self.emulatorCore, let emulatorBridge = emulatorCore.deltaCore.emulatorBridge as? MelonDSEmulatorBridge, !emulatorBridge.isJITEnabled
else { return }
guard emulatorCore.state != .stopped else {
// Emulator core is not running, which means we can set
// isJITEnabled to true without resetting the core.
emulatorBridge.isJITEnabled = true
return
}
let isVideoEnabled = emulatorCore.videoManager.isEnabled
emulatorCore.videoManager.isEnabled = false
let isRunning = (emulatorCore.state == .running)
if isRunning
{
self.pauseEmulation()
}
let temporaryFileURL = FileManager.default.uniqueTemporaryURL()
let saveState = emulatorCore.saveSaveState(to: temporaryFileURL)
emulatorCore.stop()
emulatorBridge.isJITEnabled = true
emulatorCore.start()
emulatorCore.pause()
do
{
try emulatorCore.load(saveState)
}
catch
{
print("Failed to load save state after enabling JIT.", error)
}
if isRunning
{
self.resumeEmulation()
}
emulatorCore.videoManager.isEnabled = isVideoEnabled
}
}
@objc func emulationDidQuit(with notification: Notification) @objc func emulationDidQuit(with notification: Notification)
{ {
DispatchQueue.main.async { DispatchQueue.main.async {
@ -1231,4 +1367,6 @@ private extension GameViewController
private extension UserDefaults private extension UserDefaults
{ {
@NSManaged var desmumeDeprecatedAlertCount: Int @NSManaged var desmumeDeprecatedAlertCount: Int
@NSManaged var jitEnabledAlertCount: Int
} }

View File

@ -0,0 +1,22 @@
//
// CharacterSet+Filename.swift
// Delta
//
// Created by Riley Testut on 4/28/22.
// Copyright © 2022 Riley Testut. All rights reserved.
//
import Foundation
extension CharacterSet
{
// Different than .urlPathAllowed
// Copied from https://stackoverflow.com/a/39443252
static var urlFilenameAllowed: CharacterSet {
var illegalCharacters = CharacterSet(charactersIn: ":/")
illegalCharacters.formUnion(.newlines)
illegalCharacters.formUnion(.illegalCharacters)
illegalCharacters.formUnion(.controlCharacters)
return illegalCharacters.inverted
}
}

View File

@ -0,0 +1,41 @@
//
// ProcessInfo+JIT.swift
// Delta
//
// Created by Riley Testut on 9/14/21.
// Copyright © 2021 Riley Testut. All rights reserved.
//
import UIKit
private let CS_OPS_STATUS: UInt32 = 0 /* OK */
private let CS_DEBUGGED: UInt32 = 0x10000000 /* Process is or has been attached to debugger. */
@_silgen_name("csops")
func csops(_ pid: pid_t, _ ops: UInt32, _ useraddr: UnsafeMutableRawPointer?, _ usersize: Int) -> Int
extension ProcessInfo
{
static var isJITDisabled = false
var isDebugging: Bool {
var flags: UInt32 = 0
let result = csops(getpid(), CS_OPS_STATUS, &flags, MemoryLayout<UInt32>.size)
let isDebugging = result == 0 && (flags & CS_DEBUGGED == CS_DEBUGGED)
return isDebugging
}
var isJITAvailable: Bool {
guard UIDevice.current.supportsJIT && !ProcessInfo.isJITDisabled else { return false }
let ios14_4 = OperatingSystemVersion(majorVersion: 14, minorVersion: 4, patchVersion: 0)
if #available(iOS 14.2, *), !ProcessInfo.processInfo.isOperatingSystemAtLeast(ios14_4)
{
// JIT is always available on supported devices running iOS 14.2 - 14.3.
return true
}
return self.isDebugging
}
}

View File

@ -0,0 +1,104 @@
//
// ServerManager+Delta.swift
// Delta
//
// Created by Riley Testut on 9/15/21.
// Copyright © 2021 Riley Testut. All rights reserved.
//
import AltKit
extension ServerManager
{
static let didEnableJITNotification = Notification.Name("didEnableJITNotification")
}
extension ServerManager
{
func prepare()
{
NotificationCenter.default.addObserver(self, selector: #selector(ServerManager.didChangeJITMode(_:)), name: .settingsDidChange, object: nil)
#if DEBUG
if ProcessInfo.processInfo.isDebugging
{
// Debugger is attached at app launch, so we assume
// we're connected to Xcode for debugging purposes.
// In that case, we manually treat JIT as unavailable
// until AltServer is discovered to simulate real-world use.
ProcessInfo.isJITDisabled = true
}
#endif
self.start()
}
}
private extension ServerManager
{
func start()
{
guard Settings.isAltJITEnabled && !ProcessInfo.processInfo.isJITAvailable else { return }
self.startDiscovering()
self.autoconnect()
}
func autoconnect()
{
self.autoconnect { result in
switch result
{
case .failure(let error):
print("Could not auto-connect to server.", error)
self.autoconnect()
case .success(let connection):
func finish(result: Result<Void, Error>)
{
switch result
{
case .failure(ALTServerError.unknownRequest), .failure(ALTServerError.deviceNotFound):
// Try connecting to a different server.
self.autoconnect()
case .failure(let error):
print("Could not enable JIT compilation.", error)
case .success:
print("Successfully enabled JIT compilation!")
NotificationCenter.default.post(name: ServerManager.didEnableJITNotification, object: nil)
self.stopDiscovering()
}
connection.disconnect()
}
if ProcessInfo.isJITDisabled
{
ProcessInfo.isJITDisabled = false
finish(result: .success(()))
}
else
{
connection.enableUnsignedCodeExecution(completion: finish)
}
}
}
}
@objc func didChangeJITMode(_ notification: Notification)
{
guard let name = notification.userInfo?[Settings.NotificationUserInfoKey.name] as? Settings.Name, name == Settings.Name.isAltJITEnabled else { return }
if Settings.isAltJITEnabled
{
self.start()
}
else
{
self.stopDiscovering()
}
}
}

View File

@ -26,12 +26,9 @@ extension UIDevice
} }
var supportsJIT: Bool { var supportsJIT: Bool {
// As of iOS 14.4 beta 2, JIT is no longer supported :( guard #available(iOS 14.0, *) else { return false }
// Hopefully this change is reversed before the public release...
let ios14_4 = OperatingSystemVersion(majorVersion: 14, minorVersion: 4, patchVersion: 0)
guard #available(iOS 14.2, *), !ProcessInfo.processInfo.isOperatingSystemAtLeast(ios14_4) else { return false }
// JIT is supported on devices with an A12 processor or better running iOS 14.2 or later. // JIT is supported on devices with an A12 processor or better running iOS 14.0 or later.
// ARKit 3 is only supported by devices with an A12 processor or better, according to the documentation. // ARKit 3 is only supported by devices with an A12 processor or better, according to the documentation.
return ARBodyTrackingConfiguration.isSupported return ARBodyTrackingConfiguration.isSupported
} }

View File

@ -66,6 +66,8 @@ class GameCollectionViewController: UICollectionViewController
private weak var _previewTransitionViewController: PreviewGameViewController? private weak var _previewTransitionViewController: PreviewGameViewController?
private weak var _previewTransitionDestinationViewController: UIViewController? private weak var _previewTransitionDestinationViewController: UIViewController?
private weak var _popoverSourceView: UIView?
private var _renameAction: UIAlertAction? private var _renameAction: UIAlertAction?
private var _changingArtworkGame: Game? private var _changingArtworkGame: Game?
private var _importingSaveFileGame: Game? private var _importingSaveFileGame: Game?
@ -93,10 +95,6 @@ extension GameCollectionViewController
self.collectionView?.prefetchDataSource = self.dataSource self.collectionView?.prefetchDataSource = self.dataSource
self.collectionView?.delegate = self self.collectionView?.delegate = self
let layout = self.collectionViewLayout as! GridCollectionViewLayout
layout.itemWidth = 90
layout.minimumInteritemSpacing = 12
if #available(iOS 13, *) {} if #available(iOS 13, *) {}
else else
{ {
@ -105,6 +103,8 @@ extension GameCollectionViewController
let longPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(GameCollectionViewController.handleLongPressGesture(_:))) let longPressGestureRecognizer = UILongPressGestureRecognizer(target: self, action: #selector(GameCollectionViewController.handleLongPressGesture(_:)))
self.collectionView?.addGestureRecognizer(longPressGestureRecognizer) self.collectionView?.addGestureRecognizer(longPressGestureRecognizer)
} }
self.update()
} }
override func viewWillDisappear(_ animated: Bool) override func viewWillDisappear(_ animated: Bool)
@ -131,6 +131,13 @@ extension GameCollectionViewController
super.didReceiveMemoryWarning() super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated. // Dispose of any resources that can be recreated.
} }
override func traitCollectionDidChange(_ previousTraitCollection: UITraitCollection?)
{
super.traitCollectionDidChange(previousTraitCollection)
self.update()
}
} }
//MARK: - Segues - //MARK: - Segues -
@ -180,7 +187,7 @@ extension GameCollectionViewController
emulatorBridge.systemType = .ds emulatorBridge.systemType = .ds
} }
emulatorBridge.isJITEnabled = UIDevice.current.supportsJIT emulatorBridge.isJITEnabled = ProcessInfo.processInfo.isJITAvailable
} }
if let saveState = self.activeSaveState if let saveState = self.activeSaveState
@ -224,6 +231,26 @@ extension GameCollectionViewController
//MARK: - Private Methods - //MARK: - Private Methods -
private extension GameCollectionViewController private extension GameCollectionViewController
{ {
func update()
{
let layout = self.collectionViewLayout as! GridCollectionViewLayout
switch self.traitCollection.horizontalSizeClass
{
case .regular:
layout.itemWidth = 150
layout.minimumInteritemSpacing = 25 // 30 == only 3 games per line for iPad mini 6 in portrait
case .unspecified, .compact:
layout.itemWidth = 90
layout.minimumInteritemSpacing = 12
@unknown default: break
}
self.collectionView.reloadData()
}
//MARK: - Data Source //MARK: - Data Source
func prepareDataSource() func prepareDataSource()
{ {
@ -284,7 +311,19 @@ private extension GameCollectionViewController
cell.imageView.image = #imageLiteral(resourceName: "BoxArt") cell.imageView.image = #imageLiteral(resourceName: "BoxArt")
cell.maximumImageSize = CGSize(width: 90, height: 90) if self.traitCollection.horizontalSizeClass == .regular
{
let fontDescriptor = UIFontDescriptor.preferredFontDescriptor(withTextStyle: .subheadline).withSymbolicTraits(.traitBold)!
cell.textLabel.font = UIFont(descriptor: fontDescriptor, size: 0)
}
else
{
cell.textLabel.font = UIFont.preferredFont(forTextStyle: .caption1)
}
let layout = self.collectionViewLayout as! GridCollectionViewLayout
cell.maximumImageSize = CGSize(width: layout.itemWidth, height: layout.itemWidth)
cell.textLabel.text = game.name cell.textLabel.text = game.name
cell.textLabel.textColor = UIColor.gray cell.textLabel.textColor = UIColor.gray
cell.tintColor = cell.textLabel.textColor cell.tintColor = cell.textLabel.textColor
@ -484,7 +523,9 @@ private extension GameCollectionViewController
func delete(_ game: Game) func delete(_ game: Game)
{ {
let confirmationAlertController = UIAlertController(title: NSLocalizedString("Are you sure you want to delete this game? All associated data, such as saves, save states, and cheat codes, will also be deleted.", comment: ""), message: nil, preferredStyle: .actionSheet) let confirmationAlertController = UIAlertController(title: NSLocalizedString("Are you sure you want to delete this game?", comment: ""),
message: NSLocalizedString("All associated data, such as saves, save states, and cheat codes, will also be deleted.", comment: ""),
preferredStyle: .alert)
confirmationAlertController.addAction(UIAlertAction(title: NSLocalizedString("Delete Game", comment: ""), style: .destructive, handler: { action in confirmationAlertController.addAction(UIAlertAction(title: NSLocalizedString("Delete Game", comment: ""), style: .destructive, handler: { action in
DatabaseManager.shared.performBackgroundTask { (context) in DatabaseManager.shared.performBackgroundTask { (context) in
@ -554,6 +595,7 @@ private extension GameCollectionViewController
let importController = ImportController(documentTypes: [kUTTypeImage as String]) let importController = ImportController(documentTypes: [kUTTypeImage as String])
importController.delegate = self importController.delegate = self
importController.importOptions = [clipboardImportOption, photoLibraryImportOption, gamesDatabaseImportOption] importController.importOptions = [clipboardImportOption, photoLibraryImportOption, gamesDatabaseImportOption]
importController.sourceView = self._popoverSourceView
self.present(importController, animated: true, completion: nil) self.present(importController, animated: true, completion: nil)
} }
@ -663,26 +705,36 @@ private extension GameCollectionViewController
func share(_ game: Game) func share(_ game: Game)
{ {
let temporaryDirectory = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString) let temporaryDirectory = FileManager.default.temporaryDirectory.appendingPathComponent(UUID().uuidString, isDirectory: true)
let symbolicURL = temporaryDirectory.appendingPathComponent(game.name + "." + game.fileURL.pathExtension)
let sanitizedName = game.name.components(separatedBy: .urlFilenameAllowed.inverted).joined()
let temporaryURL = temporaryDirectory.appendingPathComponent(sanitizedName + "." + game.fileURL.pathExtension, isDirectory: false)
do do
{ {
try FileManager.default.createDirectory(at: temporaryDirectory, withIntermediateDirectories: true, attributes: nil) try FileManager.default.createDirectory(at: temporaryDirectory, withIntermediateDirectories: true, attributes: nil)
// Create a symbolic link so we can control the file name used when sharing. // Make a temporary copy so we can control the filename used when sharing.
// Otherwise, if we just passed in game.fileURL to UIActivityViewController, the file name would be the game's SHA1 hash. // Otherwise, if we just passed in game.fileURL to UIActivityViewController, the file name would be the game's SHA1 hash.
try FileManager.default.createSymbolicLink(at: symbolicURL, withDestinationURL: game.fileURL) try FileManager.default.copyItem(at: game.fileURL, to: temporaryURL, shouldReplace: true)
} }
catch catch
{ {
print(error) let alertController = UIAlertController(title: NSLocalizedString("Could Not Share Game", comment: ""), error: error)
self.present(alertController, animated: true, completion: nil)
return
} }
let copyDeepLinkActivity = CopyDeepLinkActivity() let copyDeepLinkActivity = CopyDeepLinkActivity()
let activityViewController = UIActivityViewController(activityItems: [symbolicURL, game], applicationActivities: [copyDeepLinkActivity]) let activityViewController = UIActivityViewController(activityItems: [temporaryURL, game], applicationActivities: [copyDeepLinkActivity])
activityViewController.popoverPresentationController?.sourceView = self._popoverSourceView?.superview
activityViewController.popoverPresentationController?.sourceRect = self._popoverSourceView?.frame ?? .zero
activityViewController.completionWithItemsHandler = { (activityType, finished, returnedItems, error) in activityViewController.completionWithItemsHandler = { (activityType, finished, returnedItems, error) in
// Make sure the user either shared the game or cancelled before deleting temporaryDirectory.
guard finished || activityType == nil else { return }
do do
{ {
try FileManager.default.removeItem(at: temporaryDirectory) try FileManager.default.removeItem(at: temporaryDirectory)
@ -692,6 +744,7 @@ private extension GameCollectionViewController
print(error) print(error)
} }
} }
self.present(activityViewController, animated: true, completion: nil) self.present(activityViewController, animated: true, completion: nil)
} }
@ -747,8 +800,7 @@ private extension GameCollectionViewController
{ {
do do
{ {
let illegalCharacterSet = CharacterSet(charactersIn: "\"\\/?<>:*|") let sanitizedFilename = game.name.components(separatedBy: .urlFilenameAllowed.inverted).joined()
let sanitizedFilename = game.name.components(separatedBy: illegalCharacterSet).joined() + "." + game.gameSaveURL.pathExtension
let temporaryURL = FileManager.default.temporaryDirectory.appendingPathComponent(sanitizedFilename) let temporaryURL = FileManager.default.temporaryDirectory.appendingPathComponent(sanitizedFilename)
try FileManager.default.copyItem(at: game.gameSaveURL, to: temporaryURL, shouldReplace: true) try FileManager.default.copyItem(at: game.gameSaveURL, to: temporaryURL, shouldReplace: true)
@ -807,6 +859,9 @@ extension GameCollectionViewController: UIViewControllerPreviewingDelegate
previewingContext.sourceRect = layoutAttributes.frame previewingContext.sourceRect = layoutAttributes.frame
let cell = collectionView.cellForItem(at: indexPath)
self._popoverSourceView = cell
let game = self.dataSource.item(at: indexPath) let game = self.dataSource.item(at: indexPath)
let gameViewController = self.makePreviewGameViewController(for: game) let gameViewController = self.makePreviewGameViewController(for: game)
@ -843,7 +898,7 @@ extension GameCollectionViewController: UIViewControllerPreviewingDelegate
emulatorBridge.systemType = .ds emulatorBridge.systemType = .ds
} }
emulatorBridge.isJITEnabled = UIDevice.current.supportsJIT emulatorBridge.isJITEnabled = ProcessInfo.processInfo.isJITAvailable
} }
let actions = self.actions(for: game).previewActions let actions = self.actions(for: game).previewActions
@ -974,6 +1029,9 @@ extension GameCollectionViewController
let game = self.dataSource.item(at: indexPath) let game = self.dataSource.item(at: indexPath)
let actions = self.actions(for: game) let actions = self.actions(for: game)
let cell = self.collectionView.cellForItem(at: indexPath)
self._popoverSourceView = cell
return UIContextMenuConfiguration(identifier: indexPath as NSIndexPath, previewProvider: { [weak self] in return UIContextMenuConfiguration(identifier: indexPath as NSIndexPath, previewProvider: { [weak self] in
guard let self = self else { return nil } guard let self = self else { return nil }

View File

@ -47,6 +47,7 @@ class GamesViewController: UIViewController
private let fetchedResultsController: NSFetchedResultsController<NSFetchRequestResult> private let fetchedResultsController: NSFetchedResultsController<NSFetchRequestResult>
private var searchController: RSTSearchController? private var searchController: RSTSearchController?
private lazy var importController: ImportController = self.makeImportController()
private var syncingToastView: RSTToastView? { private var syncingToastView: RSTToastView? {
didSet { didSet {
@ -58,6 +59,8 @@ class GamesViewController: UIViewController
} }
private var syncingProgressObservation: NSKeyValueObservation? private var syncingProgressObservation: NSKeyValueObservation?
@IBOutlet private var importButton: UIBarButtonItem!
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) {
fatalError("initWithNibName: not implemented") fatalError("initWithNibName: not implemented")
} }
@ -114,10 +117,16 @@ extension GamesViewController
let navigationBarAppearance = navigationController.navigationBar.standardAppearance.copy() let navigationBarAppearance = navigationController.navigationBar.standardAppearance.copy()
navigationBarAppearance.backgroundEffect = UIBlurEffect(style: .dark) navigationBarAppearance.backgroundEffect = UIBlurEffect(style: .dark)
navigationController.navigationBar.standardAppearance = navigationBarAppearance navigationController.navigationBar.standardAppearance = navigationBarAppearance
navigationController.navigationBar.scrollEdgeAppearance = navigationBarAppearance
let toolbarAppearance = navigationController.toolbar.standardAppearance.copy() let toolbarAppearance = navigationController.toolbar.standardAppearance.copy()
toolbarAppearance.backgroundEffect = UIBlurEffect(style: .dark) toolbarAppearance.backgroundEffect = UIBlurEffect(style: .dark)
navigationController.toolbar.standardAppearance = toolbarAppearance navigationController.toolbar.standardAppearance = toolbarAppearance
if #available(iOS 15, *)
{
navigationController.toolbar.scrollEdgeAppearance = toolbarAppearance
}
} }
else else
{ {
@ -126,6 +135,22 @@ extension GamesViewController
} }
} }
if #available(iOS 14, *)
{
self.importController.presentingViewController = self
let importActions = self.importController.makeActions().menuActions
let importMenu = UIMenu(title: NSLocalizedString("Import From…", comment: ""), image: UIImage(systemName: "square.and.arrow.down"), children: importActions)
self.importButton.menu = importMenu
self.importButton.action = nil
self.importButton.target = nil
}
else
{
self.importController.barButtonItem = self.importButton
}
self.prepareSearchController() self.prepareSearchController()
self.updateTheme() self.updateTheme()
@ -352,8 +377,8 @@ private extension GamesViewController
/// Importing /// Importing
extension GamesViewController: ImportControllerDelegate extension GamesViewController: ImportControllerDelegate
{ {
@IBAction private func importFiles() private func makeImportController() -> ImportController
{ {
var documentTypes = Set(System.registeredSystems.map { $0.gameType.rawValue }) var documentTypes = Set(System.registeredSystems.map { $0.gameType.rawValue })
documentTypes.insert(kUTTypeZipArchive as String) documentTypes.insert(kUTTypeZipArchive as String)
documentTypes.insert("com.rileytestut.delta.skin") documentTypes.insert("com.rileytestut.delta.skin")
@ -373,7 +398,13 @@ extension GamesViewController: ImportControllerDelegate
let importController = ImportController(documentTypes: documentTypes) let importController = ImportController(documentTypes: documentTypes)
importController.delegate = self importController.delegate = self
importController.importOptions = [itunesImportOption] importController.importOptions = [itunesImportOption]
self.present(importController, animated: true, completion: nil)
return importController
}
@IBAction private func importFiles()
{
self.present(self.importController, animated: true, completion: nil)
} }
func importController(_ importController: ImportController, didImportItemsAt urls: Set<URL>, errors: [Error]) func importController(_ importController: ImportController, didImportItemsAt urls: Set<URL>, errors: [Error])

View File

@ -13,7 +13,7 @@ import DeltaCore
struct iTunesImportOption: ImportOption struct iTunesImportOption: ImportOption
{ {
let title = NSLocalizedString("iTunes", comment: "") let title = NSLocalizedString("iTunes", comment: "")
let image: UIImage? = nil let image: UIImage? = UIImage(symbolNameIfAvailable: "music.note")
private let presentingViewController: UIViewController private let presentingViewController: UIViewController

View File

@ -37,7 +37,10 @@ class ImportController: NSObject
var delegate: ImportControllerDelegate? var delegate: ImportControllerDelegate?
var importOptions: [ImportOption]? var importOptions: [ImportOption]?
private weak var presentingViewController: UIViewController? weak var presentingViewController: UIViewController?
weak var barButtonItem: UIBarButtonItem?
weak var sourceView: UIView?
// Store presentedViewController separately, since when we dismiss we don't know if it has already been dismissed. // Store presentedViewController separately, since when we dismiss we don't know if it has already been dismissed.
// Calling dismiss on presentingViewController in that case would dismiss presentingViewController, which is bad. // Calling dismiss on presentingViewController in that case would dismiss presentingViewController, which is bad.
@ -61,26 +64,54 @@ class ImportController: NSObject
super.init() super.init()
} }
func makeActions() -> [Action]
{
assert(self.presentingViewController != nil, "presentingViewController must be set before calling makeActions()")
var actions = (self.importOptions ?? []).map { (option) -> Action in
let action = Action(title: option.title, style: .default, image: option.image) { _ in
option.import { importedURLs in
self.finish(with: importedURLs, errors: [])
}
}
return action
}
let filesAction = Action(title: NSLocalizedString("Files", comment: ""), style: .default, image: UIImage(symbolNameIfAvailable: "doc")) { action in
self.presentDocumentBrowser()
}
actions.append(filesAction)
return actions
}
fileprivate func presentImportController(from presentingViewController: UIViewController, animated: Bool, completionHandler: (() -> Void)?) fileprivate func presentImportController(from presentingViewController: UIViewController, animated: Bool, completionHandler: (() -> Void)?)
{ {
self.presentingViewController = presentingViewController self.presentingViewController = presentingViewController
let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) let actions = self.makeActions()
alertController.addAction(UIAlertAction.cancel)
if let importOptions = self.importOptions if actions.count > 1
{ {
for importOption in importOptions let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
alertController.addAction(UIAlertAction.cancel)
let alertActions = actions.map { UIAlertAction($0) }
for action in alertActions
{ {
alertController.add(importOption) { [unowned self] (urls) in alertController.addAction(action)
self.finish(with: urls, errors: [])
}
} }
let filesAction = UIAlertAction(title: NSLocalizedString("Files", comment: ""), style: .default) { (action) in if let sourceView = self.sourceView
self.presentDocumentBrowser() {
alertController.popoverPresentationController?.sourceView = sourceView.superview
alertController.popoverPresentationController?.sourceRect = sourceView.frame
}
else
{
alertController.popoverPresentationController?.barButtonItem = self.barButtonItem
} }
alertController.addAction(filesAction)
self.presentedViewController = alertController self.presentedViewController = alertController
self.presentingViewController?.present(alertController, animated: true, completion: nil) self.presentingViewController?.present(alertController, animated: true, completion: nil)
@ -198,7 +229,7 @@ private var ImportControllerKey: UInt8 = 0
extension UIViewController extension UIViewController
{ {
fileprivate(set) var importController: ImportController? fileprivate var importController: ImportController?
{ {
set set
{ {

View File

@ -12,13 +12,26 @@ import DeltaCore
extension CheatValidator extension CheatValidator
{ {
enum Error: Swift.Error enum Error: LocalizedError
{ {
case invalidCode case invalidCode
case invalidName case invalidName
case invalidGame case invalidGame
case duplicateName case duplicateName
case duplicateCode case duplicateCode
case unknownCheatType
var errorDescription: String? {
switch self
{
case .invalidCode: return NSLocalizedString("The cheat code isn't in the correct format.", comment: "")
case .invalidName: return NSLocalizedString("The name of this cheat is invalid.", comment: "")
case .invalidGame: return NSLocalizedString("There is no associated game with this cheat.", comment: "")
case .duplicateName: return NSLocalizedString("A cheat already exists with this name.", comment: "")
case .duplicateCode: return NSLocalizedString("A cheat already exists with this code.", comment: "")
case .unknownCheatType: return NSLocalizedString("Delta does not support this cheat type.", comment: "")
}
}
} }
} }

View File

@ -8,8 +8,10 @@
import UIKit import UIKit
import CoreData import CoreData
import SwiftUI
import DeltaCore import DeltaCore
import MelonDSDeltaCore
import Roxas import Roxas
@ -30,6 +32,8 @@ class CheatsViewController: UITableViewController
weak var delegate: CheatsViewControllerDelegate? weak var delegate: CheatsViewControllerDelegate?
private let dataSource = RSTFetchedResultsTableViewDataSource<Cheat>(fetchedResultsController: NSFetchedResultsController()) private let dataSource = RSTFetchedResultsTableViewDataSource<Cheat>(fetchedResultsController: NSFetchedResultsController())
private var cheatBaseCheats: [CheatMetadata]?
} }
extension CheatsViewController extension CheatsViewController
@ -61,6 +65,21 @@ extension CheatsViewController
self.tableView.separatorEffect = vibrancyEffect self.tableView.separatorEffect = vibrancyEffect
self.registerForPreviewing(with: self, sourceView: self.tableView) self.registerForPreviewing(with: self, sourceView: self.tableView)
if #available(iOS 14, *)
{
self.updateAddCheatMenu()
}
}
override func viewWillAppear(_ animated: Bool)
{
super.viewWillAppear(animated)
if #available(iOS 14, *), self.cheatBaseCheats == nil
{
self.fetchCheatBaseCheats()
}
} }
override func didReceiveMemoryWarning() override func didReceiveMemoryWarning()
@ -91,6 +110,37 @@ private extension CheatsViewController
self.dataSource.fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: DatabaseManager.shared.viewContext, sectionNameKeyPath: nil, cacheName: nil) self.dataSource.fetchedResultsController = NSFetchedResultsController(fetchRequest: fetchRequest, managedObjectContext: DatabaseManager.shared.viewContext, sectionNameKeyPath: nil, cacheName: nil)
} }
@available(iOS 14, *) @MainActor
func updateAddCheatMenu()
{
// CheatBase only contains DS cheats for now, so hide option completely for other systems.
guard self.game.type == .ds else { return }
var searchCheatBaseTitle = NSLocalizedString("Search CheatBase", comment: "")
var attributes: UIMenuElement.Attributes = []
if let cheats = self.cheatBaseCheats, cheats.isEmpty
{
searchCheatBaseTitle = NSLocalizedString("No Cheats in CheatBase", comment: "")
attributes = [.disabled]
}
let addCheatMenu = UIMenu(children: [
UIAction(title: NSLocalizedString("New Cheat Code", comment: ""), image: UIImage(systemName: "square.and.pencil")) { [weak self] _ in
self?.addCheat()
},
UIAction(title: searchCheatBaseTitle, image: UIImage(systemName: "magnifyingglass"), attributes: attributes) { [weak self] _ in
self?.searchCheatBase()
},
])
self.navigationItem.rightBarButtonItem?.target = nil
self.navigationItem.rightBarButtonItem?.action = nil
self.navigationItem.rightBarButtonItem?.menu = addCheatMenu
}
} }
//MARK: - Managing Cheats - //MARK: - Managing Cheats -
@ -103,6 +153,78 @@ private extension CheatsViewController
editCheatViewController.presentWithPresentingViewController(self) editCheatViewController.presentWithPresentingViewController(self)
} }
@available(iOS 14, *)
func fetchCheatBaseCheats()
{
Task {
do
{
let cheatBase = try CheatBase()
let cheats = try await cheatBase.cheats(for: self.game) ?? []
self.cheatBaseCheats = cheats
self.updateAddCheatMenu()
}
catch
{
print("[RSTLog] Failed to prefetch cheats from CheatBase:", error)
}
}
}
@available(iOS 14, *)
func searchCheatBase()
{
var rootView = CheatBaseView(game: self.game, cheats: self.cheatBaseCheats)
rootView.cancellationHandler = { [weak self] in
self?.presentedViewController?.dismiss(animated: true)
}
rootView.selectionHandler = { [weak self] cheatMetadata in
self?.saveCheatMetadata(cheatMetadata)
self?.presentedViewController?.dismiss(animated: true)
}
let hostingController = UIHostingController(rootView: rootView)
self.present(hostingController, animated: true, completion: nil)
}
func saveCheatMetadata(_ cheatMetadata: CheatMetadata)
{
DatabaseManager.shared.performBackgroundTask { context in
do
{
guard let cheatType = cheatMetadata.device.cheatType, let cheatFormat = cheatMetadata.device.cheatFormat else { throw CheatValidator.Error.unknownCheatType }
let cheat = Cheat(context: context)
cheat.name = cheatMetadata.name
cheat.type = cheatType
cheat.isEnabled = true
let sanitizedCode = cheatMetadata.code.components(separatedBy: .whitespacesAndNewlines).joined()
let formattedCode = sanitizedCode.formatted(with: cheatFormat)
cheat.code = formattedCode
let game = context.object(with: self.game.objectID) as! Game
cheat.game = game
let validator = CheatValidator(format: cheatFormat, managedObjectContext: context)
try validator.validate(cheat)
self.delegate?.cheatsViewController(self, activateCheat: cheat)
try context.save()
}
catch
{
DispatchQueue.main.async {
let alertController = UIAlertController(title: NSLocalizedString("Unable to Add Cheat", comment: ""), error: error)
self.present(alertController, animated: true, completion: nil)
}
}
}
}
func deleteCheat(_ cheat: Cheat) func deleteCheat(_ cheat: Cheat)
{ {
self.delegate?.cheatsViewController(self, deactivateCheat: cheat) self.delegate?.cheatsViewController(self, deactivateCheat: cheat)

View File

@ -93,14 +93,6 @@ extension SaveStatesViewController
self.collectionView?.dataSource = self.dataSource self.collectionView?.dataSource = self.dataSource
self.collectionView?.prefetchDataSource = self.dataSource self.collectionView?.prefetchDataSource = self.dataSource
let collectionViewLayout = self.collectionViewLayout as! GridCollectionViewLayout
let averageHorizontalInset = (collectionViewLayout.sectionInset.left + collectionViewLayout.sectionInset.right) / 2
let portraitScreenWidth = UIScreen.main.coordinateSpace.convert(UIScreen.main.bounds, to: UIScreen.main.fixedCoordinateSpace).width
// Use dimensions that allow two cells to fill the screen horizontally with padding in portrait mode
// We'll keep the same size for landscape orientation, which will allow more to fit
collectionViewLayout.itemWidth = floor((portraitScreenWidth - (averageHorizontalInset * 3)) / 2)
switch self.mode switch self.mode
{ {
case .saving: case .saving:
@ -113,8 +105,7 @@ extension SaveStatesViewController
self.navigationItem.rightBarButtonItems?.removeFirst() self.navigationItem.rightBarButtonItems?.removeFirst()
} }
// Manually update prototype cell properties self.prototypeCellWidthConstraint = self.prototypeCell.contentView.widthAnchor.constraint(equalToConstant: 0)
self.prototypeCellWidthConstraint = self.prototypeCell.contentView.widthAnchor.constraint(equalToConstant: collectionViewLayout.itemWidth)
self.prototypeCellWidthConstraint.isActive = true self.prototypeCellWidthConstraint.isActive = true
self.prepareEmulatorCoreSaveState() self.prepareEmulatorCoreSaveState()
@ -238,6 +229,26 @@ private extension SaveStatesViewController
} }
self.sortButton.transform = CGAffineTransform.identity.rotated(by: Settings.sortSaveStatesByOldestFirst ? 0 : .pi) self.sortButton.transform = CGAffineTransform.identity.rotated(by: Settings.sortSaveStatesByOldestFirst ? 0 : .pi)
let collectionViewLayout = self.collectionViewLayout as! GridCollectionViewLayout
if self.traitCollection.horizontalSizeClass == .regular
{
collectionViewLayout.itemWidth = 180
collectionViewLayout.minimumInteritemSpacing = 30
}
else
{
let averageHorizontalInset = (collectionViewLayout.sectionInset.left + collectionViewLayout.sectionInset.right) / 2
let portraitScreenWidth = UIScreen.main.coordinateSpace.convert(UIScreen.main.bounds, to: UIScreen.main.fixedCoordinateSpace).width
// Use dimensions that allow two cells to fill the screen horizontally with padding in portrait mode
// We'll keep the same size for landscape orientation, which will allow more to fit
collectionViewLayout.itemWidth = floor((portraitScreenWidth - (averageHorizontalInset * 3)) / 2)
}
// Manually update prototype cell properties
self.prototypeCellWidthConstraint.constant = collectionViewLayout.itemWidth
} }
//MARK: - Configure Views - //MARK: - Configure Views -

190
Delta/SceneDelegate.swift Normal file
View File

@ -0,0 +1,190 @@
//
// SceneDelegate.swift
// Delta
//
// Created by Riley Testut on 6/6/22.
// Copyright © 2022 Riley Testut. All rights reserved.
//
import UIKit
import DeltaCore
import Harmony
@objc(SceneDelegate) @available(iOS 13, *)
class SceneDelegate: UIResponder, UIWindowSceneDelegate
{
var window: UIWindow? {
get {
if _window == nil
{
_window = GameWindow()
}
return _window
}
set {
_window = newValue as? GameWindow
}
}
private var _window: GameWindow?
private let deepLinkController = DeepLinkController()
func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions)
{
// Use this method to optionally configure and attach the UIWindow `window` to the provided UIWindowScene `scene`.
// If using a storyboard, the `window` property will automatically be initialized and attached to the scene.
// This delegate does not imply the connecting scene or session are new (see `application:configurationForConnectingSceneSession` instead).
self.window?.tintColor = .deltaPurple
if let context = connectionOptions.urlContexts.first
{
self.handle(.url(context.url))
}
if let shortcutItem = connectionOptions.shortcutItem
{
self.handle(.shortcut(shortcutItem))
}
self.window?.makeKeyAndVisible()
}
func sceneDidDisconnect(_ scene: UIScene)
{
// Called as the scene is being released by the system.
// This occurs shortly after the scene enters the background, or when its session is discarded.
// Release any resources associated with this scene that can be re-created the next time the scene connects.
// The scene may re-connect later, as its session was not necessarily discarded (see `application:didDiscardSceneSessions` instead).
}
func sceneDidBecomeActive(_ scene: UIScene)
{
// Called when the scene has moved from an inactive state to an active state.
// Use this method to restart any tasks that were paused (or not yet started) when the scene was inactive.
}
func sceneWillResignActive(_ scene: UIScene)
{
// Called when the scene will move from an active state to an inactive state.
// This may occur due to temporary interruptions (ex. an incoming phone call).
}
func sceneWillEnterForeground(_ scene: UIScene)
{
// Called as the scene transitions from the background to the foreground.
// Use this method to undo the changes made on entering the background.
}
func sceneDidEnterBackground(_ scene: UIScene)
{
// Called as the scene transitions from the foreground to the background.
// Use this method to save data, release shared resources, and store enough scene-specific state information
// to restore the scene back to its current state.
}
}
@available(iOS 13, *)
extension SceneDelegate
{
func scene(_ scene: UIScene, openURLContexts URLContexts: Set<UIOpenURLContext>)
{
guard let context = URLContexts.first else { return }
self.handle(.url(context.url))
}
func windowScene(_ windowScene: UIWindowScene, performActionFor shortcutItem: UIApplicationShortcutItem, completionHandler: @escaping (Bool) -> Void)
{
self.handle(.shortcut(shortcutItem))
completionHandler(true)
}
}
@available(iOS 13, *)
private extension SceneDelegate
{
func handle(_ deepLink: DeepLink)
{
guard DatabaseManager.shared.isStarted else {
// Wait until DatabaseManager is ready before handling deep link.
// NotificationCenter.default.notifications requires iOS 15 or later :(
// _ = await NotificationCenter.default.notifications(named: DatabaseManager.didStartNotification).first(where: { _ in true })
var observer: NSObjectProtocol?
observer = NotificationCenter.default.addObserver(forName: DatabaseManager.didStartNotification, object: DatabaseManager.shared, queue: .main) { [weak observer] _ in
observer.map { NotificationCenter.default.removeObserver($0) }
self.handle(deepLink)
}
return
}
DispatchQueue.main.async {
// DeepLinkController expects to be called from main thread.
switch deepLink
{
case .shortcut:
_ = self.deepLinkController.handle(deepLink)
case .url(let url):
if url.isFileURL
{
if GameType(fileExtension: url.pathExtension) != nil || url.pathExtension.lowercased() == "zip"
{
self.importGame(at: url)
}
else if url.pathExtension.lowercased() == "deltaskin"
{
self.importControllerSkin(at: url)
}
}
else if url.scheme?.hasPrefix("db-") == true
{
_ = DropboxService.shared.handleDropboxURL(url)
}
else if url.scheme?.lowercased() == "delta"
{
_ = self.deepLinkController.handle(deepLink)
}
}
}
}
func importGame(at url: URL)
{
DatabaseManager.shared.importGames(at: [url]) { (games, errors) in
if errors.count > 0
{
let alertController = UIAlertController.alertController(for: .games, with: errors)
self.present(alertController)
}
}
}
func importControllerSkin(at url: URL)
{
DatabaseManager.shared.importControllerSkins(at: [url]) { (games, errors) in
if errors.count > 0
{
let alertController = UIAlertController.alertController(for: .controllerSkins, with: errors)
self.present(alertController)
}
}
}
func present(_ alertController: UIAlertController)
{
var rootViewController = self.window?.rootViewController
while rootViewController?.presentedViewController != nil
{
rootViewController = rootViewController?.presentedViewController
}
rootViewController?.present(alertController, animated: true, completion: nil)
}
}

View File

@ -14,7 +14,7 @@ import DeltaCore
import Roxas import Roxas
@objc(SwitchTableViewCell) @objc(SwitchTableViewCell)
private class SwitchTableViewCell: UITableViewCell class SwitchTableViewCell: UITableViewCell
{ {
@IBOutlet var switchView: UISwitch! @IBOutlet var switchView: UISwitch!
} }

View File

@ -0,0 +1,45 @@
//
// Contributor.swift
// Delta
//
// Created by Riley Testut on 2/3/23.
// Copyright © 2023 Riley Testut. All rights reserved.
//
import Foundation
struct Contributor: Identifiable, Decodable
{
var name: String
var id: String {
// Use names as identifiers for now.
return self.name
}
var url: URL? {
guard let link = self.link, let url = URL(string: link) else { return nil }
return url
}
private var link: String?
var linkName: String?
var contributions: [Contribution]
}
struct Contribution: Identifiable, Decodable
{
var name: String
var id: String {
// Use names as identifiers for now.
return self.name
}
var url: URL? {
guard let link = self.link, let url = URL(string: link) else { return nil }
return url
}
private var link: String?
}

View File

@ -0,0 +1,200 @@
//
// ContributionsView.swift
// Delta
//
// Created by Riley Testut on 2/2/23.
// Copyright © 2023 Riley Testut. All rights reserved.
//
import SwiftUI
import SafariServices
@available(iOS 14, *)
private extension NavigationLink where Label == EmptyView, Destination == EmptyView
{
// Copied from https://stackoverflow.com/a/66891173
static var empty: NavigationLink {
self.init(destination: EmptyView(), label: { EmptyView() })
}
}
@available(iOS 14, *)
extension ContributorsView
{
fileprivate class ViewModel: ObservableObject
{
@Published
var contributors: [Contributor]?
@Published
var error: Error?
@Published
var webViewURL: URL?
weak var hostingController: UIViewController?
func loadContributors()
{
guard self.contributors == nil else { return }
do
{
let fileURL = Bundle.main.url(forResource: "Contributors", withExtension: "plist")!
let data = try Data(contentsOf: fileURL)
let contributors = try PropertyListDecoder().decode([Contributor].self, from: data)
self.contributors = contributors
}
catch
{
self.error = error
}
}
}
static func makeViewController() -> UIHostingController<some View>
{
let viewModel = ViewModel()
let contributorsView = ContributorsView(viewModel: viewModel)
let hostingController = UIHostingController(rootView: contributorsView)
hostingController.title = NSLocalizedString("Contributors", comment: "")
viewModel.hostingController = hostingController
return hostingController
}
}
@available(iOS 14, *)
struct ContributorsView: View
{
@StateObject
private var viewModel: ViewModel
@State
private var showErrorAlert: Bool = false
var body: some View {
List {
Section(content: {}, footer: {
Text("These individuals have contributed to the open-source Delta project on GitHub.\n\nThank you to all our contributors, your help is much appreciated 💜")
.font(.subheadline)
})
ForEach(viewModel.contributors ?? []) { contributor in
Section {
// First row = contributor
ContributionCell(name: Text(contributor.name).bold(), url: contributor.url, linkName: contributor.linkName) { webViewURL in
viewModel.webViewURL = webViewURL
}
// Remaining rows = contributions
ForEach(contributor.contributions) { contribution in
ContributionCell(name: Text(contribution.name), url: contribution.url) { webViewURL in
viewModel.webViewURL = webViewURL
}
}
}
}
}
.listStyle(.grouped) // TODO: Change to .insetGrouped once we drop iOS 13 support.
.environmentObject(viewModel)
.alert(isPresented: $showErrorAlert) {
Alert(title: Text("Unable to Load Contributors"), message: Text(viewModel.error?.localizedDescription ?? ""), dismissButton: .default(Text("OK")) {
guard let hostingController = viewModel.hostingController else { return }
hostingController.navigationController?.popViewController(animated: true)
})
}
.onReceive(viewModel.$error) { error in
guard error != nil else { return }
showErrorAlert = true
}
.onReceive(viewModel.$webViewURL) { webViewURL in
guard let webViewURL else { return }
openURL(webViewURL)
}
.onAppear {
viewModel.loadContributors()
}
}
fileprivate init(contributors: [Contributor]? = nil, viewModel: ViewModel = ViewModel())
{
if let contributors
{
// Don't overwrite passed-in viewModel.contributors if contributors is nil.
viewModel.contributors = contributors
}
self._viewModel = StateObject(wrappedValue: viewModel)
}
}
@available(iOS 14, *)
struct ContributionCell: View
{
var name: Text
var url: URL?
var linkName: String?
var action: (URL) -> Void
var body: some View {
let body = Button {
guard let url else { return }
Task { @MainActor in
// Dispatch Task to avoid "Publishing changes from within view updates is not allowed, this will cause undefined behavior." runtime error on iOS 16.
self.action(url)
}
} label: {
HStack {
self.name
.font(.system(size: 17)) // Match Settings screen
Spacer()
if let linkName
{
Text(linkName)
.font(.system(size: 17)) // Match Settings screen
.foregroundColor(.gray)
}
if url != nil
{
NavigationLink.empty
.fixedSize()
}
}
}
.accentColor(.primary)
if url != nil
{
body
}
else
{
// No URL to open, so disable cell highlighting.
body.buttonStyle(.plain)
}
}
}
@available(iOS 14, *)
private extension ContributorsView
{
func openURL(_ url: URL)
{
guard let hostingController = viewModel.hostingController else { return }
let safariViewController = SFSafariViewController(url: url)
safariViewController.preferredControlTintColor = .deltaPurple
hostingController.present(safariViewController, animated: true)
}
}

View File

@ -40,6 +40,8 @@ class ControllerInputsViewController: UIViewController
private var activeCalloutView: InputCalloutView? private var activeCalloutView: InputCalloutView?
private var _didLayoutSubviews = false
@IBOutlet private var actionsMenuViewControllerHeightConstraint: NSLayoutConstraint! @IBOutlet private var actionsMenuViewControllerHeightConstraint: NSLayoutConstraint!
@IBOutlet private var cancelTapGestureRecognizer: UITapGestureRecognizer! @IBOutlet private var cancelTapGestureRecognizer: UITapGestureRecognizer!
@ -65,7 +67,15 @@ class ControllerInputsViewController: UIViewController
self.gameViewController.controllerView.addReceiver(self) self.gameViewController.controllerView.addReceiver(self)
self.navigationController?.navigationBar.barStyle = .black if let navigationController = self.navigationController, #available(iOS 13, *)
{
navigationController.overrideUserInterfaceStyle = .dark
navigationController.navigationBar.scrollEdgeAppearance = navigationController.navigationBar.standardAppearance // Fixes invisible navigation bar on iPad.
}
else
{
self.navigationController?.navigationBar.barStyle = .black
}
NSLayoutConstraint.activate([self.gameViewController.gameView.centerYAnchor.constraint(equalTo: self.actionsMenuViewController.view.centerYAnchor)]) NSLayoutConstraint.activate([self.gameViewController.gameView.centerYAnchor.constraint(equalTo: self.actionsMenuViewController.view.centerYAnchor)])
@ -81,6 +91,23 @@ class ControllerInputsViewController: UIViewController
{ {
self.actionsMenuViewControllerHeightConstraint.constant = self.actionsMenuViewController.preferredContentSize.height self.actionsMenuViewControllerHeightConstraint.constant = self.actionsMenuViewController.preferredContentSize.height
} }
if let window = self.view.window, !_didLayoutSubviews
{
var traits = DeltaCore.ControllerSkin.Traits.defaults(for: window)
traits.orientation = .portrait
if traits.device == .ipad
{
// Use standard iPhone skins instead of iPad skins.
traits.device = .iphone
traits.displayType = .standard
}
self.gameViewController.controllerView.overrideControllerSkinTraits = traits
_didLayoutSubviews = true
}
} }
override func viewDidAppear(_ animated: Bool) override func viewDidAppear(_ animated: Bool)
@ -91,6 +118,9 @@ class ControllerInputsViewController: UIViewController
{ {
self.prepareCallouts() self.prepareCallouts()
} }
// controllerView must be first responder to receive keyboard presses.
self.gameViewController.controllerView.becomeFirstResponder()
} }
} }
@ -183,6 +213,10 @@ private extension ControllerInputsViewController
listMenuViewController.title = NSLocalizedString("Game System", comment: "") listMenuViewController.title = NSLocalizedString("Game System", comment: "")
let navigationController = UINavigationController(rootViewController: listMenuViewController) let navigationController = UINavigationController(rootViewController: listMenuViewController)
if #available(iOS 13, *)
{
navigationController.navigationBar.scrollEdgeAppearance = navigationController.navigationBar.standardAppearance
}
let popoverMenuController = PopoverMenuController(popoverViewController: navigationController) let popoverMenuController = PopoverMenuController(popoverViewController: navigationController)
self.navigationItem.popoverMenuController = popoverMenuController self.navigationItem.popoverMenuController = popoverMenuController
@ -403,6 +437,7 @@ private extension ControllerInputsViewController
} }
let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet) let alertController = UIAlertController(title: nil, message: nil, preferredStyle: .actionSheet)
alertController.popoverPresentationController?.barButtonItem = sender
alertController.addAction(.cancel) alertController.addAction(.cancel)
alertController.addAction(UIAlertAction(title: NSLocalizedString("Reset Controls to Defaults", comment: ""), style: .destructive, handler: { (action) in alertController.addAction(UIAlertAction(title: NSLocalizedString("Reset Controls to Defaults", comment: ""), style: .destructive, handler: { (action) in
reset() reset()
@ -418,6 +453,12 @@ extension ControllerInputsViewController: UIGestureRecognizerDelegate
return self.activeCalloutView != nil return self.activeCalloutView != nil
} }
func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool
{
// Necessary to prevent other gestures (e.g. GameViewController's resumeEmulationIfNeeded() tap gesture) from cancelling tap.
return true
}
@IBAction private func handleTapGesture(_ tapGestureRecognizer: UITapGestureRecognizer) @IBAction private func handleTapGesture(_ tapGestureRecognizer: UITapGestureRecognizer)
{ {
self.updateActiveCalloutView(with: nil) self.updateActiveCalloutView(with: nil)
@ -532,13 +573,19 @@ extension ControllerInputsViewController: GameControllerReceiver
{ {
func gameController(_ gameController: GameController, didActivate controllerInput: DeltaCore.Input, value: Double) func gameController(_ gameController: GameController, didActivate controllerInput: DeltaCore.Input, value: Double)
{ {
guard self.isViewLoaded else { return } guard self.isViewLoaded, value > 0.9 else { return }
switch gameController switch gameController
{ {
case self.gameViewController.controllerView: case self.gameViewController.controllerView:
if let calloutView = self.calloutViews[AnyInput(controllerInput)] if let calloutView = self.calloutViews[AnyInput(controllerInput)]
{ {
if controllerInput.isContinuous
{
// Make sure we only toggle calloutView once in a single gesture.
guard calloutView.state == .normal else { break }
}
self.toggle(calloutView) self.toggle(calloutView)
} }
@ -562,3 +609,15 @@ extension ControllerInputsViewController: SMCalloutViewDelegate
self.toggle(calloutView) self.toggle(calloutView)
} }
} }
extension ControllerInputsViewController: UIAdaptivePresentationControllerDelegate
{
func adaptivePresentationStyle(for controller: UIPresentationController, traitCollection: UITraitCollection) -> UIModalPresentationStyle
{
switch (traitCollection.horizontalSizeClass, traitCollection.verticalSizeClass)
{
case (.regular, .regular): return .formSheet // Regular width and height, so display as form sheet
default: return .fullScreen // Compact width and/or height, so display full screen
}
}
}

View File

@ -108,9 +108,18 @@ extension ControllersSettingsViewController
switch identifier switch identifier
{ {
case "controllerInputsSegue": case "controllerInputsSegue":
let controllerInputsViewController = (segue.destination as! UINavigationController).topViewController as! ControllerInputsViewController let navigationController = segue.destination as! UINavigationController
let controllerInputsViewController = navigationController.topViewController as! ControllerInputsViewController
controllerInputsViewController.gameController = self.gameController controllerInputsViewController.gameController = self.gameController
if self.view.traitCollection.userInterfaceIdiom == .pad
{
// For now, only iPads can display ControllerInputsViewController as a form sheet.
navigationController.modalPresentationStyle = .formSheet
navigationController.presentationController?.delegate = controllerInputsViewController
}
default: break default: break
} }
@ -296,6 +305,8 @@ extension ControllersSettingsViewController
{ {
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{ {
let previousGameController = self.gameController
switch Section(rawValue: indexPath.section)! switch Section(rawValue: indexPath.section)!
{ {
case .localDevice: self.gameController = self.localDeviceController case .localDevice: self.gameController = self.localDeviceController
@ -310,7 +321,7 @@ extension ControllersSettingsViewController
let previousIndexPath: IndexPath? let previousIndexPath: IndexPath?
if let gameController = self.gameController if let gameController = previousGameController
{ {
if gameController == self.localDeviceController if gameController == self.localDeviceController
{ {

View File

@ -23,18 +23,18 @@ private extension MelonDSCoreSettingsViewController
enum Section: Int enum Section: Int
{ {
case general case general
case performance
case dsBIOS case dsBIOS
case dsiBIOS case dsiBIOS
case changeCore case changeCore
} }
@available(iOS 13, *)
enum BIOSError: LocalizedError enum BIOSError: LocalizedError
{ {
case unknownSize(URL) case unknownSize(URL)
case incorrectHash(URL, hash: String, expectedHash: String) case incorrectHash(URL, hash: String, expectedHash: String)
case unsupportedHash(URL, hash: String) case unsupportedHash(URL, hash: String)
@available(iOS 13, *)
case incorrectSize(URL, size: Int, validSizes: Set<ClosedRange<Measurement<UnitInformationStorage>>>) case incorrectSize(URL, size: Int, validSizes: Set<ClosedRange<Measurement<UnitInformationStorage>>>)
private static let byteFormatter: ByteCountFormatter = { private static let byteFormatter: ByteCountFormatter = {
@ -150,6 +150,13 @@ private extension MelonDSCoreSettingsViewController
switch section switch section
{ {
case .performance:
// Hide AltJIT section for public builds.
guard isBeta else { return true }
guard Settings.preferredCore(for: .ds) == MelonDS.core else { return true }
return !UIDevice.current.supportsJIT
case .dsBIOS where Settings.preferredCore(for: .ds) == DS.core: case .dsBIOS where Settings.preferredCore(for: .ds) == DS.core:
// Using DeSmuME core, which doesn't require BIOS. // Using DeSmuME core, which doesn't require BIOS.
return true return true
@ -253,6 +260,11 @@ private extension MelonDSCoreSettingsViewController
} }
} }
@IBAction func toggleAltJITEnabled(_ sender: UISwitch)
{
Settings.isAltJITEnabled = sender.isOn
}
@objc func willEnterForeground(_ notification: Notification) @objc func willEnterForeground(_ notification: Notification)
{ {
self.tableView.reloadData() self.tableView.reloadData()
@ -301,6 +313,10 @@ extension MelonDSCoreSettingsViewController
cell.contentView.isHidden = (item == nil) cell.contentView.isHidden = (item == nil)
case .performance:
let cell = cell as! SwitchTableViewCell
cell.switchView.isOn = Settings.isAltJITEnabled
case .dsBIOS: case .dsBIOS:
let bios = DSBIOS.allCases[indexPath.row] let bios = DSBIOS.allCases[indexPath.row]
@ -379,6 +395,8 @@ extension MelonDSCoreSettingsViewController
case .changeCore: case .changeCore:
self.changeCore() self.changeCore()
case .performance: break
} }
} }

View File

@ -38,6 +38,8 @@ extension Settings
case syncingService case syncingService
case isButtonHapticFeedbackEnabled case isButtonHapticFeedbackEnabled
case isThumbstickHapticFeedbackEnabled case isThumbstickHapticFeedbackEnabled
case isAltJITEnabled
case respectSilentMode
} }
} }
@ -60,8 +62,18 @@ struct Settings
#keyPath(UserDefaults.isThumbstickHapticFeedbackEnabled): true, #keyPath(UserDefaults.isThumbstickHapticFeedbackEnabled): true,
#keyPath(UserDefaults.sortSaveStatesByOldestFirst): true, #keyPath(UserDefaults.sortSaveStatesByOldestFirst): true,
#keyPath(UserDefaults.isPreviewsEnabled): true, #keyPath(UserDefaults.isPreviewsEnabled): true,
#keyPath(UserDefaults.isAltJITEnabled): false,
#keyPath(UserDefaults.respectSilentMode): true,
Settings.preferredCoreSettingsKey(for: .ds): MelonDS.core.identifier] as [String : Any] Settings.preferredCoreSettingsKey(for: .ds): MelonDS.core.identifier] as [String : Any]
UserDefaults.standard.register(defaults: defaults) UserDefaults.standard.register(defaults: defaults)
#if !BETA
// Manually set MelonDS as preferred DS core in case DeSmuME is cached from a previous version.
UserDefaults.standard.set(MelonDS.core.identifier, forKey: Settings.preferredCoreSettingsKey(for: .ds))
// Manually disable AltJIT for public builds.
UserDefaults.standard.isAltJITEnabled = false
#endif
} }
} }
@ -190,6 +202,28 @@ extension Settings
} }
} }
static var isAltJITEnabled: Bool {
get {
let isAltJITEnabled = UserDefaults.standard.isAltJITEnabled
return isAltJITEnabled
}
set {
UserDefaults.standard.isAltJITEnabled = newValue
NotificationCenter.default.post(name: .settingsDidChange, object: nil, userInfo: [NotificationUserInfoKey.name: Name.isAltJITEnabled])
}
}
static var respectSilentMode: Bool {
get {
let respectSilentMode = UserDefaults.standard.respectSilentMode
return respectSilentMode
}
set {
UserDefaults.standard.respectSilentMode = newValue
NotificationCenter.default.post(name: .settingsDidChange, object: nil, userInfo: [NotificationUserInfoKey.name: Name.respectSilentMode])
}
}
static func preferredCore(for gameType: GameType) -> DeltaCoreProtocol? static func preferredCore(for gameType: GameType) -> DeltaCoreProtocol?
{ {
let key = self.preferredCoreSettingsKey(for: gameType) let key = self.preferredCoreSettingsKey(for: gameType)
@ -385,4 +419,8 @@ private extension UserDefaults
@NSManaged var sortSaveStatesByOldestFirst: Bool @NSManaged var sortSaveStatesByOldestFirst: Bool
@NSManaged var isPreviewsEnabled: Bool @NSManaged var isPreviewsEnabled: Bool
@NSManaged var isAltJITEnabled: Bool
@NSManaged var respectSilentMode: Bool
} }

View File

@ -20,6 +20,7 @@ private extension SettingsViewController
case controllers case controllers
case controllerSkins case controllerSkins
case controllerOpacity case controllerOpacity
case gameAudio
case hapticFeedback case hapticFeedback
case syncing case syncing
case hapticTouch case hapticTouch
@ -44,9 +45,11 @@ private extension SettingsViewController
enum CreditsRow: Int, CaseIterable enum CreditsRow: Int, CaseIterable
{ {
case riley case riley
case shane
case caroline case caroline
case grant case grant
case litRitt case litRitt
case contributors
case softwareLicenses case softwareLicenses
} }
} }
@ -56,6 +59,7 @@ class SettingsViewController: UITableViewController
@IBOutlet private var controllerOpacityLabel: UILabel! @IBOutlet private var controllerOpacityLabel: UILabel!
@IBOutlet private var controllerOpacitySlider: UISlider! @IBOutlet private var controllerOpacitySlider: UISlider!
@IBOutlet private var respectSilentModeSwitch: UISwitch!
@IBOutlet private var buttonHapticFeedbackEnabledSwitch: UISwitch! @IBOutlet private var buttonHapticFeedbackEnabledSwitch: UISwitch!
@IBOutlet private var thumbstickHapticFeedbackEnabledSwitch: UISwitch! @IBOutlet private var thumbstickHapticFeedbackEnabledSwitch: UISwitch!
@IBOutlet private var previewsEnabledSwitch: UISwitch! @IBOutlet private var previewsEnabledSwitch: UISwitch!
@ -160,6 +164,8 @@ private extension SettingsViewController
self.controllerOpacitySlider.value = Float(Settings.translucentControllerSkinOpacity) self.controllerOpacitySlider.value = Float(Settings.translucentControllerSkinOpacity)
self.updateControllerOpacityLabel() self.updateControllerOpacityLabel()
self.respectSilentModeSwitch.isOn = Settings.respectSilentMode
self.syncingServiceLabel.text = Settings.syncingService?.localizedName self.syncingServiceLabel.text = Settings.syncingService?.localizedName
do do
@ -248,6 +254,11 @@ private extension SettingsViewController
Settings.isPreviewsEnabled = sender.isOn Settings.isPreviewsEnabled = sender.isOn
} }
@IBAction func toggleRespectSilentMode(_ sender: UISwitch)
{
Settings.respectSilentMode = sender.isOn
}
func openTwitter(username: String) func openTwitter(username: String)
{ {
let twitterAppURL = URL(string: "twitter://user?screen_name=" + username)! let twitterAppURL = URL(string: "twitter://user?screen_name=" + username)!
@ -269,6 +280,13 @@ private extension SettingsViewController
} }
} }
} }
@available(iOS 14, *)
func showContributors()
{
let hostingController = ContributorsView.makeViewController()
self.navigationController?.pushViewController(hostingController, animated: true)
}
} }
private extension SettingsViewController private extension SettingsViewController
@ -290,7 +308,7 @@ private extension SettingsViewController
self.tableView.selectRow(at: selectedIndexPath, animated: true, scrollPosition: .none) self.tableView.selectRow(at: selectedIndexPath, animated: true, scrollPosition: .none)
} }
case .localControllerPlayerIndex, .preferredControllerSkin, .translucentControllerSkinOpacity, .isButtonHapticFeedbackEnabled, .isThumbstickHapticFeedbackEnabled: break case .localControllerPlayerIndex, .preferredControllerSkin, .translucentControllerSkinOpacity, .respectSilentMode, .isButtonHapticFeedbackEnabled, .isThumbstickHapticFeedbackEnabled, .isAltJITEnabled: break
} }
} }
@ -367,7 +385,7 @@ extension SettingsViewController
let preferredCore = Settings.preferredCore(for: .ds) let preferredCore = Settings.preferredCore(for: .ds)
cell.detailTextLabel?.text = preferredCore?.metadata?.name.value ?? preferredCore?.name ?? NSLocalizedString("Unknown", comment: "") cell.detailTextLabel?.text = preferredCore?.metadata?.name.value ?? preferredCore?.name ?? NSLocalizedString("Unknown", comment: "")
case .controllerOpacity, .hapticFeedback, .hapticTouch, .patreon, .credits: break case .controllerOpacity, .gameAudio, .hapticFeedback, .hapticTouch, .patreon, .credits: break
} }
return cell return cell
@ -383,7 +401,7 @@ extension SettingsViewController
case .controllers: self.performSegue(withIdentifier: Segue.controllers.rawValue, sender: cell) case .controllers: self.performSegue(withIdentifier: Segue.controllers.rawValue, sender: cell)
case .controllerSkins: self.performSegue(withIdentifier: Segue.controllerSkins.rawValue, sender: cell) case .controllerSkins: self.performSegue(withIdentifier: Segue.controllerSkins.rawValue, sender: cell)
case .cores: self.performSegue(withIdentifier: Segue.dsSettings.rawValue, sender: cell) case .cores: self.performSegue(withIdentifier: Segue.dsSettings.rawValue, sender: cell)
case .controllerOpacity, .hapticFeedback, .hapticTouch, .syncing: break case .controllerOpacity, .gameAudio, .hapticFeedback, .hapticTouch, .syncing: break
case .patreon: case .patreon:
let patreonURL = URL(string: "altstore://patreon")! let patreonURL = URL(string: "altstore://patreon")!
@ -404,9 +422,14 @@ extension SettingsViewController
switch row switch row
{ {
case .riley: self.openTwitter(username: "rileytestut") case .riley: self.openTwitter(username: "rileytestut")
case .shane: self.openTwitter(username: "shanegillio")
case .caroline: self.openTwitter(username: "1carolinemoore") case .caroline: self.openTwitter(username: "1carolinemoore")
case .grant: self.openTwitter(username: "grantgliner") case .grant: self.openTwitter(username: "grantgliner")
case .litRitt: self.openTwitter(username: "litritt_z") case .litRitt: self.openTwitter(username: "lit_ritt")
case .contributors:
guard #available(iOS 14, *) else { return }
self.showContributors()
case .softwareLicenses: break case .softwareLicenses: break
} }
} }
@ -414,13 +437,35 @@ extension SettingsViewController
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{ {
primary:
switch Section(rawValue: indexPath.section)! switch Section(rawValue: indexPath.section)!
{ {
#if !BETA case .credits:
case .credits where indexPath.row == CreditsRow.litRitt.rawValue: return 0.0 let row = CreditsRow(rawValue: indexPath.row)!
#endif switch row
default: return super.tableView(tableView, heightForRowAt: indexPath) {
case .grant:
// Hide row on iOS 14 and above
guard #available(iOS 14, *) else { break primary }
return 0.0
case .litRitt:
// Hide row on iOS 14 and above
guard #available(iOS 14, *) else { break primary }
return 0.0
case .contributors:
// Hide row on iOS 13 and below
guard #unavailable(iOS 14) else { break primary }
return 0.0
default: break
}
default: break
} }
return super.tableView(tableView, heightForRowAt: indexPath)
} }
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String?

View File

@ -203,6 +203,27 @@
<string>Delta uses your microphone to emulate the Nintendo DS microphone.</string> <string>Delta uses your microphone to emulate the Nintendo DS microphone.</string>
<key>NSPhotoLibraryUsageDescription</key> <key>NSPhotoLibraryUsageDescription</key>
<string>Press "OK" to allow Delta to use images from your Photo Library as game artwork.</string> <string>Press "OK" to allow Delta to use images from your Photo Library as game artwork.</string>
<key>UIApplicationSceneManifest</key>
<dict>
<key>UIApplicationSupportsMultipleScenes</key>
<false/>
<key>UISceneConfigurations</key>
<dict>
<key>UIWindowSceneSessionRoleApplication</key>
<array>
<dict>
<key>UILaunchStoryboardName</key>
<string>LaunchScreen</string>
<key>UISceneConfigurationName</key>
<string>Main</string>
<key>UISceneDelegateClassName</key>
<string>SceneDelegate</string>
<key>UISceneStoryboardFile</key>
<string>Main</string>
</dict>
</array>
</dict>
</dict>
<key>UIBackgroundModes</key> <key>UIBackgroundModes</key>
<array/> <array/>
<key>UIFileSharingEnabled</key> <key>UIFileSharingEnabled</key>
@ -215,6 +236,8 @@
<array> <array>
<string>armv7</string> <string>armv7</string>
</array> </array>
<key>UIRequiresFullScreen</key>
<false/>
<key>UIStatusBarStyle</key> <key>UIStatusBarStyle</key>
<string>UIStatusBarStyleLightContent</string> <string>UIStatusBarStyleLightContent</string>
<key>UISupportedInterfaceOrientations</key> <key>UISupportedInterfaceOrientations</key>
@ -223,6 +246,13 @@
<string>UIInterfaceOrientationLandscapeLeft</string> <string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string> <string>UIInterfaceOrientationLandscapeRight</string>
</array> </array>
<key>UISupportedInterfaceOrientations~ipad</key>
<array>
<string>UIInterfaceOrientationPortrait</string>
<string>UIInterfaceOrientationPortraitUpsideDown</string>
<string>UIInterfaceOrientationLandscapeLeft</string>
<string>UIInterfaceOrientationLandscapeRight</string>
</array>
<key>UISupportsDocumentBrowser</key> <key>UISupportsDocumentBrowser</key>
<true/> <true/>
<key>UTExportedTypeDeclarations</key> <key>UTExportedTypeDeclarations</key>
@ -400,5 +430,13 @@
</dict> </dict>
</dict> </dict>
</array> </array>
<key>NSBonjourServices</key>
<array>
<string>_altserver._tcp</string>
</array>
<key>ALTDeviceID</key>
<string>00008110-000A68390A82801E</string>
<key>NSLocalNetworkUsageDescription</key>
<string>Delta uses the local network to communicate with AltServer and enable JIT.</string>
</dict> </dict>
</plist> </plist>

View File

@ -72,7 +72,7 @@ extension DeltaCoreProtocol
case GBA.core: return 3 case GBA.core: return 3
case N64.core where UIDevice.current.hasA11ProcessorOrBetter: return 3 case N64.core where UIDevice.current.hasA11ProcessorOrBetter: return 3
case N64.core where UIDevice.current.hasA9ProcessorOrBetter: return 1.5 case N64.core where UIDevice.current.hasA9ProcessorOrBetter: return 1.5
case MelonDS.core where UIDevice.current.supportsJIT: return 3 case MelonDS.core where ProcessInfo.processInfo.isJITAvailable: return 3
case MelonDS.core where UIDevice.current.hasA11ProcessorOrBetter: return 1.5 case MelonDS.core where UIDevice.current.hasA11ProcessorOrBetter: return 1.5
case GPGX.core: return 4 case GPGX.core: return 4
default: return 1 default: return 1

1
External/CheatBase vendored Submodule

@ -0,0 +1 @@
Subproject commit df52576e6fd1185747f41b022d9664ad0593608a

2
External/Harmony vendored

@ -1 +1 @@
Subproject commit db5fbd829ac5aa6e7e249eb9fabf07bbb75fabd9 Subproject commit 7234d6626a49e56ddceaaec0c04cc4f4f43b572c

View File

@ -138,7 +138,7 @@ SPEC CHECKSUMS:
GTMSessionFetcher: b3503b20a988c4e20cc189aa798fd18220133f52 GTMSessionFetcher: b3503b20a988c4e20cc189aa798fd18220133f52
Harmony: cea514db17c41c22f78f54b17d2135935b5e9b96 Harmony: cea514db17c41c22f78f54b17d2135935b5e9b96
MelonDSDeltaCore: 3de2a2e2ebcd630a6dd756818b5a26dde7afa726 MelonDSDeltaCore: 3de2a2e2ebcd630a6dd756818b5a26dde7afa726
N64DeltaCore: 6b0f07f2078193a15d736f153ce701661853fa36 N64DeltaCore: c513f36f88d421e79fda3cd7963040db84d3ab51
NESDeltaCore: 41ab438dd78d51d4636aacb7d9a7336ea3d4728c NESDeltaCore: 41ab438dd78d51d4636aacb7d9a7336ea3d4728c
Roxas: 1990039f843f5dc284918dc82375feb80020ef62 Roxas: 1990039f843f5dc284918dc82375feb80020ef62
SDWebImage: a72e880a8fe0f7fc31efe15aaed443c074d2a80c SDWebImage: a72e880a8fe0f7fc31efe15aaed443c074d2a80c
@ -148,6 +148,6 @@ SPEC CHECKSUMS:
SwiftyDropbox: 378b4425a2e8d0cb24c7b0f2e3af72bfbaaf1e73 SwiftyDropbox: 378b4425a2e8d0cb24c7b0f2e3af72bfbaaf1e73
ZIPFoundation: b1f0de4eed33e74a676f76e12559ab6b75990197 ZIPFoundation: b1f0de4eed33e74a676f76e12559ab6b75990197
PODFILE CHECKSUM: 2f9219b1db18479e650fc2159f58160b4cc13aad PODFILE CHECKSUM: 68bb9968a91dd904a9f75286dfb3c2536917eb87
COCOAPODS: 1.10.1 COCOAPODS: 1.11.2

View File

@ -51,6 +51,11 @@
"CLANG_ENABLE_MODULES": "NO", "CLANG_ENABLE_MODULES": "NO",
"GCC_PREPROCESSOR_DEFINITIONS": "STATIC_LIBRARY=1" "GCC_PREPROCESSOR_DEFINITIONS": "STATIC_LIBRARY=1"
}, },
"script_phases": {
"name": "Get GlideN64 Revision.h",
"script": "\"${PODS_TARGET_SRCROOT}/Mupen64Plus/GLideN64/src/getRevision.sh\"",
"execution_position": "before_compile"
},
"dependencies": { "dependencies": {
"DeltaCore": [ "DeltaCore": [

6
Pods/Manifest.lock generated
View File

@ -138,7 +138,7 @@ SPEC CHECKSUMS:
GTMSessionFetcher: b3503b20a988c4e20cc189aa798fd18220133f52 GTMSessionFetcher: b3503b20a988c4e20cc189aa798fd18220133f52
Harmony: cea514db17c41c22f78f54b17d2135935b5e9b96 Harmony: cea514db17c41c22f78f54b17d2135935b5e9b96
MelonDSDeltaCore: 3de2a2e2ebcd630a6dd756818b5a26dde7afa726 MelonDSDeltaCore: 3de2a2e2ebcd630a6dd756818b5a26dde7afa726
N64DeltaCore: 6b0f07f2078193a15d736f153ce701661853fa36 N64DeltaCore: c513f36f88d421e79fda3cd7963040db84d3ab51
NESDeltaCore: 41ab438dd78d51d4636aacb7d9a7336ea3d4728c NESDeltaCore: 41ab438dd78d51d4636aacb7d9a7336ea3d4728c
Roxas: 1990039f843f5dc284918dc82375feb80020ef62 Roxas: 1990039f843f5dc284918dc82375feb80020ef62
SDWebImage: a72e880a8fe0f7fc31efe15aaed443c074d2a80c SDWebImage: a72e880a8fe0f7fc31efe15aaed443c074d2a80c
@ -148,6 +148,6 @@ SPEC CHECKSUMS:
SwiftyDropbox: 378b4425a2e8d0cb24c7b0f2e3af72bfbaaf1e73 SwiftyDropbox: 378b4425a2e8d0cb24c7b0f2e3af72bfbaaf1e73
ZIPFoundation: b1f0de4eed33e74a676f76e12559ab6b75990197 ZIPFoundation: b1f0de4eed33e74a676f76e12559ab6b75990197
PODFILE CHECKSUM: 2f9219b1db18479e650fc2159f58160b4cc13aad PODFILE CHECKSUM: 68bb9968a91dd904a9f75286dfb3c2536917eb87
COCOAPODS: 1.10.1 COCOAPODS: 1.11.2

File diff suppressed because it is too large Load Diff

View File

@ -1,10 +0,0 @@
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Crashlytics
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Crashlytics/iOS" "${PODS_ROOT}/Fabric/iOS"
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_ROOT = ${SRCROOT}
PODS_TARGET_SRCROOT = ${PODS_ROOT}/Crashlytics
PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
SKIP_INSTALL = YES
USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES

View File

@ -1,10 +0,0 @@
CONFIGURATION_BUILD_DIR = ${PODS_CONFIGURATION_BUILD_DIR}/Fabric
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Fabric/iOS"
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1
PODS_BUILD_DIR = ${BUILD_DIR}
PODS_CONFIGURATION_BUILD_DIR = ${PODS_BUILD_DIR}/$(CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME)
PODS_ROOT = ${SRCROOT}
PODS_TARGET_SRCROOT = ${PODS_ROOT}/Fabric
PRODUCT_BUNDLE_IDENTIFIER = org.cocoapods.${PRODUCT_NAME:rfc1034identifier}
SKIP_INSTALL = YES
USE_RECURSIVE_SCRIPT_INPUTS_IN_SCRIPT_PHASES = YES

View File

@ -4,7 +4,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Crashlytics/iOS" "${PODS_ROOT}/Fabric/iOS" "${PODS_ROOT}/GoogleSignIn/Frameworks" FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Crashlytics/iOS" "${PODS_ROOT}/Fabric/iOS" "${PODS_ROOT}/GoogleSignIn/Frameworks"
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 STATIC_LIBRARY=1 STATIC_LIBRARY=1 JIT_ENABLED=1 STATIC_LIBRARY=1 MUPENPLUSAPI TXFILTER_LIB OS_IOS GLESX GL_ERROR_DEBUG GL_DEBUG GLESX PNG_ARM_NEON_OPT=0 GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 STATIC_LIBRARY=1 STATIC_LIBRARY=1 JIT_ENABLED=1 STATIC_LIBRARY=1 MUPENPLUSAPI TXFILTER_LIB OS_IOS GLESX GL_ERROR_DEBUG GL_DEBUG GLESX PNG_ARM_NEON_OPT=0
HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/DSDeltaCore" "${PODS_ROOT}/Headers/Public/DeltaCore" "${PODS_ROOT}/Headers/Public/GBADeltaCore" "${PODS_ROOT}/Headers/Public/GBCDeltaCore" "${PODS_ROOT}/Headers/Public/GTMSessionFetcher" "${PODS_ROOT}/Headers/Public/GoogleAPIClientForREST" "${PODS_ROOT}/Headers/Public/GoogleToolboxForMac" "${PODS_ROOT}/Headers/Public/Harmony" "${PODS_ROOT}/Headers/Public/MelonDSDeltaCore" "${PODS_ROOT}/Headers/Public/N64DeltaCore" "${PODS_ROOT}/Headers/Public/NESDeltaCore" "${PODS_ROOT}/Headers/Public/Roxas" "${PODS_ROOT}/Headers/Public/SDWebImage" "${PODS_ROOT}/Headers/Public/SMCalloutView" "${PODS_ROOT}/Headers/Public/SNESDeltaCore" "${PODS_ROOT}/Headers/Public/SQLite.swift" "${PODS_ROOT}/Headers/Public/SwiftyDropbox" "${PODS_CONFIGURATION_BUILD_DIR}" "$(PODS_ROOT)/Headers/Private/DSDeltaCore/desmume/desmume/src/libretro-common/include" "${PODS_CONFIGURATION_BUILD_DIR}" "$(PODS_ROOT)/Headers/Private/GBADeltaCore/SFML/include" "$(PODS_ROOT)/Headers/Private/GBADeltaCore/SFML/src" "${PODS_CONFIGURATION_BUILD_DIR}" "${PODS_CONFIGURATION_BUILD_DIR}" "$(PODS_ROOT)/Headers/Private/MelonDSDeltaCore/melonDS/src" "${PODS_CONFIGURATION_BUILD_DIR}" "$(PODS_ROOT)/Headers/Private/N64DeltaCore/Mupen64Plus/mupen64plus-core/subprojects/**" "$(PODS_ROOT)/Headers/Private/N64DeltaCore/libMupen64Plus/SDL" "${PODS_CONFIGURATION_BUILD_DIR}" "$(PODS_ROOT)/Headers/Private/N64DeltaCore/Mupen64Plus/mupen64plus-core/subprojects/**" "$(PODS_ROOT)/Headers/Private/N64DeltaCore/libMupen64Plus/SDL" "$(PODS_ROOT)/Headers/Private/N64DeltaCore/Mupen64Plus/GLideN64/src" "$(PODS_ROOT)/Headers/Private/N64DeltaCore/Mupen64Plus/GLideN64/src/inc" "$(PODS_ROOT)/Headers/Private/N64DeltaCore/Mupen64Plus/GLideN64/src" "$(PODS_ROOT)/Headers/Private/N64DeltaCore/Mupen64Plus/GLideN64/src/osal" "$(PODS_ROOT)/Headers/Private/N64DeltaCore/Mupen64Plus/libpng" HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/DSDeltaCore" "${PODS_ROOT}/Headers/Public/DeltaCore" "${PODS_ROOT}/Headers/Public/GBADeltaCore" "${PODS_ROOT}/Headers/Public/GBCDeltaCore" "${PODS_ROOT}/Headers/Public/GTMSessionFetcher" "${PODS_ROOT}/Headers/Public/GoogleAPIClientForREST" "${PODS_ROOT}/Headers/Public/GoogleToolboxForMac" "${PODS_ROOT}/Headers/Public/Harmony" "${PODS_ROOT}/Headers/Public/MelonDSDeltaCore" "${PODS_ROOT}/Headers/Public/N64DeltaCore" "${PODS_ROOT}/Headers/Public/NESDeltaCore" "${PODS_ROOT}/Headers/Public/Roxas" "${PODS_ROOT}/Headers/Public/SDWebImage" "${PODS_ROOT}/Headers/Public/SMCalloutView" "${PODS_ROOT}/Headers/Public/SNESDeltaCore" "${PODS_ROOT}/Headers/Public/SQLite.swift" "${PODS_ROOT}/Headers/Public/SwiftyDropbox" "${PODS_CONFIGURATION_BUILD_DIR}" "$(PODS_ROOT)/Headers/Private/DSDeltaCore/desmume/desmume/src/libretro-common/include" "${PODS_CONFIGURATION_BUILD_DIR}" "$(PODS_ROOT)/Headers/Private/GBADeltaCore/SFML/include" "$(PODS_ROOT)/Headers/Private/GBADeltaCore/SFML/src" "${PODS_CONFIGURATION_BUILD_DIR}" "${PODS_CONFIGURATION_BUILD_DIR}" "$(PODS_ROOT)/Headers/Private/MelonDSDeltaCore/melonDS/src" "${PODS_CONFIGURATION_BUILD_DIR}" "$(PODS_ROOT)/Headers/Private/N64DeltaCore/Mupen64Plus/mupen64plus-core/subprojects/**" "$(PODS_ROOT)/Headers/Private/N64DeltaCore/libMupen64Plus/SDL" "${PODS_CONFIGURATION_BUILD_DIR}" "$(PODS_ROOT)/Headers/Private/N64DeltaCore/Mupen64Plus/mupen64plus-core/subprojects/**" "$(PODS_ROOT)/Headers/Private/N64DeltaCore/libMupen64Plus/SDL" "$(PODS_ROOT)/Headers/Private/N64DeltaCore/Mupen64Plus/GLideN64/src" "$(PODS_ROOT)/Headers/Private/N64DeltaCore/Mupen64Plus/GLideN64/src/inc" "$(PODS_ROOT)/Headers/Private/N64DeltaCore/Mupen64Plus/GLideN64/src" "$(PODS_ROOT)/Headers/Private/N64DeltaCore/Mupen64Plus/GLideN64/src/osal" "$(PODS_ROOT)/Headers/Private/N64DeltaCore/Mupen64Plus/libpng"
LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire" "${PODS_CONFIGURATION_BUILD_DIR}/DSDeltaCore" "${PODS_CONFIGURATION_BUILD_DIR}/DeltaCore" "${PODS_CONFIGURATION_BUILD_DIR}/GBADeltaCore" "${PODS_CONFIGURATION_BUILD_DIR}/GBCDeltaCore" "${PODS_CONFIGURATION_BUILD_DIR}/GTMSessionFetcher" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleAPIClientForREST" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleToolboxForMac" "${PODS_CONFIGURATION_BUILD_DIR}/Harmony" "${PODS_CONFIGURATION_BUILD_DIR}/MelonDSDeltaCore" "${PODS_CONFIGURATION_BUILD_DIR}/N64DeltaCore" "${PODS_CONFIGURATION_BUILD_DIR}/NESDeltaCore" "${PODS_CONFIGURATION_BUILD_DIR}/Roxas" "${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage" "${PODS_CONFIGURATION_BUILD_DIR}/SMCalloutView" "${PODS_CONFIGURATION_BUILD_DIR}/SNESDeltaCore" "${PODS_CONFIGURATION_BUILD_DIR}/SQLite.swift" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyDropbox" "${PODS_CONFIGURATION_BUILD_DIR}/ZIPFoundation" LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire" "${PODS_CONFIGURATION_BUILD_DIR}/DSDeltaCore" "${PODS_CONFIGURATION_BUILD_DIR}/DeltaCore" "${PODS_CONFIGURATION_BUILD_DIR}/GBADeltaCore" "${PODS_CONFIGURATION_BUILD_DIR}/GBCDeltaCore" "${PODS_CONFIGURATION_BUILD_DIR}/GTMSessionFetcher" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleAPIClientForREST" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleToolboxForMac" "${PODS_CONFIGURATION_BUILD_DIR}/Harmony" "${PODS_CONFIGURATION_BUILD_DIR}/MelonDSDeltaCore" "${PODS_CONFIGURATION_BUILD_DIR}/N64DeltaCore" "${PODS_CONFIGURATION_BUILD_DIR}/NESDeltaCore" "${PODS_CONFIGURATION_BUILD_DIR}/Roxas" "${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage" "${PODS_CONFIGURATION_BUILD_DIR}/SMCalloutView" "${PODS_CONFIGURATION_BUILD_DIR}/SNESDeltaCore" "${PODS_CONFIGURATION_BUILD_DIR}/SQLite.swift" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyDropbox" "${PODS_CONFIGURATION_BUILD_DIR}/ZIPFoundation" /usr/lib/swift
OTHER_CFLAGS = $(inherited) -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/Alamofire/Alamofire.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/DSDeltaCore/DSDeltaCore.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/DeltaCore/DeltaCore.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/GBADeltaCore/GBADeltaCore.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/GBCDeltaCore/GBCDeltaCore.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/Harmony/Harmony.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/MelonDSDeltaCore/MelonDSDeltaCore.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/N64DeltaCore/N64DeltaCore.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/NESDeltaCore/NESDeltaCore.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/SNESDeltaCore/SNESDeltaCore.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/SQLite.swift/SQLite.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/SwiftyDropbox/SwiftyDropbox.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/ZIPFoundation/ZIPFoundation.modulemap" -fmodule-map-file="${PODS_ROOT}/Headers/Public/GTMSessionFetcher/GTMSessionFetcher.modulemap" -fmodule-map-file="${PODS_ROOT}/Headers/Public/GoogleAPIClientForREST/GoogleAPIClientForREST.modulemap" -fmodule-map-file="${PODS_ROOT}/Headers/Public/GoogleToolboxForMac/GoogleToolboxForMac.modulemap" -fmodule-map-file="${PODS_ROOT}/Headers/Public/Roxas/Roxas.modulemap" -fmodule-map-file="${PODS_ROOT}/Headers/Public/SDWebImage/SDWebImage.modulemap" -fmodule-map-file="${PODS_ROOT}/Headers/Public/SMCalloutView/SMCalloutView.modulemap" -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/DSDeltaCore" -isystem "${PODS_ROOT}/Headers/Public/GBADeltaCore" -isystem "${PODS_ROOT}/Headers/Public/GBCDeltaCore" -isystem "${PODS_ROOT}/Headers/Public/Harmony" -isystem "${PODS_ROOT}/Headers/Public/MelonDSDeltaCore" -isystem "${PODS_ROOT}/Headers/Public/N64DeltaCore" -isystem "${PODS_ROOT}/Headers/Public/NESDeltaCore" -isystem "${PODS_ROOT}/Headers/Public/SNESDeltaCore" -iframework "${PODS_ROOT}/Crashlytics/iOS" -iframework "${PODS_ROOT}/Fabric/iOS" -iframework "${PODS_ROOT}/GoogleSignIn/Frameworks" -DHOST_DARWIN -DDESMUME_COCOA -DHAVE_OPENGL -DHAVE_LIBZ -DANDROID -fexceptions -ftree-vectorize -DCOMPRESS_MT -DIOS -DOBJ_C -marm -fvisibility=hidden -DSTATIC_LIBRARY=1 -DSTATIC_LIBRARY -DHAVE_CSTDINT -fno-strict-aliasing -DGCC -pthread -fPIC -D__unix__ -ffast-math -fno-strict-aliasing -DGCC -pthread -fPIC -D__unix__ -ffast-math -D__VEC4_OPT -fvisibility=hidden -funsigned-char -ffast-math -finline -fno-builtin -fno-common -fomit-frame-pointer -funroll-loops -fstrict-aliasing -DHAVE_STDINT_H -DARM -DSTATIC_LIBRARY=1 OTHER_CFLAGS = $(inherited) -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/Alamofire/Alamofire.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/DSDeltaCore/DSDeltaCore.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/DeltaCore/DeltaCore.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/GBADeltaCore/GBADeltaCore.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/GBCDeltaCore/GBCDeltaCore.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/Harmony/Harmony.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/MelonDSDeltaCore/MelonDSDeltaCore.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/N64DeltaCore/N64DeltaCore.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/NESDeltaCore/NESDeltaCore.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/SNESDeltaCore/SNESDeltaCore.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/SQLite.swift/SQLite.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/SwiftyDropbox/SwiftyDropbox.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/ZIPFoundation/ZIPFoundation.modulemap" -fmodule-map-file="${PODS_ROOT}/Headers/Public/GTMSessionFetcher/GTMSessionFetcher.modulemap" -fmodule-map-file="${PODS_ROOT}/Headers/Public/GoogleAPIClientForREST/GoogleAPIClientForREST.modulemap" -fmodule-map-file="${PODS_ROOT}/Headers/Public/GoogleToolboxForMac/GoogleToolboxForMac.modulemap" -fmodule-map-file="${PODS_ROOT}/Headers/Public/Roxas/Roxas.modulemap" -fmodule-map-file="${PODS_ROOT}/Headers/Public/SDWebImage/SDWebImage.modulemap" -fmodule-map-file="${PODS_ROOT}/Headers/Public/SMCalloutView/SMCalloutView.modulemap" -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/DSDeltaCore" -isystem "${PODS_ROOT}/Headers/Public/GBADeltaCore" -isystem "${PODS_ROOT}/Headers/Public/GBCDeltaCore" -isystem "${PODS_ROOT}/Headers/Public/Harmony" -isystem "${PODS_ROOT}/Headers/Public/MelonDSDeltaCore" -isystem "${PODS_ROOT}/Headers/Public/N64DeltaCore" -isystem "${PODS_ROOT}/Headers/Public/NESDeltaCore" -isystem "${PODS_ROOT}/Headers/Public/SNESDeltaCore" -iframework "${PODS_ROOT}/Crashlytics/iOS" -iframework "${PODS_ROOT}/Fabric/iOS" -iframework "${PODS_ROOT}/GoogleSignIn/Frameworks" -DHOST_DARWIN -DDESMUME_COCOA -DHAVE_OPENGL -DHAVE_LIBZ -DANDROID -fexceptions -ftree-vectorize -DCOMPRESS_MT -DIOS -DOBJ_C -marm -fvisibility=hidden -DSTATIC_LIBRARY=1 -DSTATIC_LIBRARY -DHAVE_CSTDINT -fno-strict-aliasing -DGCC -pthread -fPIC -D__unix__ -ffast-math -fno-strict-aliasing -DGCC -pthread -fPIC -D__unix__ -ffast-math -D__VEC4_OPT -fvisibility=hidden -funsigned-char -ffast-math -finline -fno-builtin -fno-common -fomit-frame-pointer -funroll-loops -fstrict-aliasing -DHAVE_STDINT_H -DARM -DSTATIC_LIBRARY=1
OTHER_LDFLAGS = $(inherited) -ObjC -Wl,-exported_symbol,_Video_PluginStartup,-exported_symbol,_Video_PluginShutdown,-exported_symbol,_Video_PluginGetVersion,-exported_symbol,_Video_RomOpen,-exported_symbol,_Video_RomClosed,-exported_symbol,_ConfigGetSharedDataFilepath,-exported_symbol,_ConfigGetUserConfigPath,-exported_symbol,_ConfigGetUserCachePath,-exported_symbol,_ConfigGetUserDataPath,-exported_symbol,_ConfigOpenSection,-exported_symbol,_ConfigDeleteSection,-exported_symbol,_ConfigSaveSection,-exported_symbol,_ConfigSaveFile,-exported_symbol,_ConfigSetDefaultInt,-exported_symbol,_ConfigSetDefaultFloat,-exported_symbol,_ConfigSetDefaultBool,-exported_symbol,_ConfigSetDefaultString,-exported_symbol,_ConfigGetParamInt,-exported_symbol,_ConfigGetParamFloat,-exported_symbol,_ConfigGetParamBool,-exported_symbol,_ConfigGetParamString,-exported_symbol,_ConfigExternalGetParameter,-exported_symbol,_ConfigExternalOpen,-exported_symbol,_ConfigExternalClose,-exported_symbol,_VidExt_Init,-exported_symbol,_VidExt_Quit,-exported_symbol,_VidExt_ListFullscreenModes,-exported_symbol,_VidExt_SetVideoMode,-exported_symbol,_VidExt_SetCaption,-exported_symbol,_VidExt_ToggleFullScreen,-exported_symbol,_VidExt_ResizeWindow,-exported_symbol,_VidExt_GL_GetProcAddress,-exported_symbol,_VidExt_GL_SetAttribute,-exported_symbol,_VidExt_GL_GetAttribute,-exported_symbol,_VidExt_GL_SwapBuffers,-exported_symbol,_ChangeWindow,-exported_symbol,_InitiateGFX,-exported_symbol,_MoveScreen,-exported_symbol,_ProcessDList,-exported_symbol,_ProcessRDPList,-exported_symbol,_ShowCFB,-exported_symbol,_UpdateScreen,-exported_symbol,_ViStatusChanged,-exported_symbol,_ViWidthChanged,-exported_symbol,_ReadScreen2,-exported_symbol,_SetRenderingCallback,-exported_symbol,_FBRead,-exported_symbol,_FBWrite,-exported_symbol,_FBGetFrameBufferInfo,-exported_symbol,_ResizeVideoOutput,-exported_symbol,_RSP_PluginStartup,-exported_symbol,_RSP_PluginShutdown,-exported_symbol,_RSP_PluginGetVersion,-exported_symbol,_DoRspCycles,-exported_symbol,_InitiateRSP,-exported_symbol,_RSP_RomClosed,-exported_symbol,_CoreGetAPIVersions,-exported_symbol,_ConfigGetParameter,-exported_symbol,_ConfigSetParameter,-exported_symbol,_CoreDoCommand -l"Alamofire" -l"DSDeltaCore" -l"GBADeltaCore" -l"GBCDeltaCore" -l"GTMSessionFetcher" -l"GoogleAPIClientForREST" -l"GoogleToolboxForMac" -l"Harmony" -l"MelonDSDeltaCore" -l"N64DeltaCore" -l"NESDeltaCore" -l"Roxas" -l"SDWebImage" -l"SMCalloutView" -l"SNESDeltaCore" -l"SQLite.swift" -l"SwiftyDropbox" -l"ZIPFoundation" -l"c++" -l"sqlite3" -l"z" -framework "CoreGraphics" -framework "CoreText" -framework "Crashlytics" -framework "Fabric" -framework "Foundation" -framework "GoogleSignIn" -framework "ImageIO" -framework "LocalAuthentication" -framework "SafariServices" -framework "Security" -framework "SystemConfiguration" -framework "UIKit" -framework "WebKit" OTHER_LDFLAGS = $(inherited) -ObjC -Wl,-exported_symbol,_Video_PluginStartup,-exported_symbol,_Video_PluginShutdown,-exported_symbol,_Video_PluginGetVersion,-exported_symbol,_Video_RomOpen,-exported_symbol,_Video_RomClosed,-exported_symbol,_ConfigGetSharedDataFilepath,-exported_symbol,_ConfigGetUserConfigPath,-exported_symbol,_ConfigGetUserCachePath,-exported_symbol,_ConfigGetUserDataPath,-exported_symbol,_ConfigOpenSection,-exported_symbol,_ConfigDeleteSection,-exported_symbol,_ConfigSaveSection,-exported_symbol,_ConfigSaveFile,-exported_symbol,_ConfigSetDefaultInt,-exported_symbol,_ConfigSetDefaultFloat,-exported_symbol,_ConfigSetDefaultBool,-exported_symbol,_ConfigSetDefaultString,-exported_symbol,_ConfigGetParamInt,-exported_symbol,_ConfigGetParamFloat,-exported_symbol,_ConfigGetParamBool,-exported_symbol,_ConfigGetParamString,-exported_symbol,_ConfigExternalGetParameter,-exported_symbol,_ConfigExternalOpen,-exported_symbol,_ConfigExternalClose,-exported_symbol,_VidExt_Init,-exported_symbol,_VidExt_Quit,-exported_symbol,_VidExt_ListFullscreenModes,-exported_symbol,_VidExt_SetVideoMode,-exported_symbol,_VidExt_SetCaption,-exported_symbol,_VidExt_ToggleFullScreen,-exported_symbol,_VidExt_ResizeWindow,-exported_symbol,_VidExt_GL_GetProcAddress,-exported_symbol,_VidExt_GL_SetAttribute,-exported_symbol,_VidExt_GL_GetAttribute,-exported_symbol,_VidExt_GL_SwapBuffers,-exported_symbol,_ChangeWindow,-exported_symbol,_InitiateGFX,-exported_symbol,_MoveScreen,-exported_symbol,_ProcessDList,-exported_symbol,_ProcessRDPList,-exported_symbol,_ShowCFB,-exported_symbol,_UpdateScreen,-exported_symbol,_ViStatusChanged,-exported_symbol,_ViWidthChanged,-exported_symbol,_ReadScreen2,-exported_symbol,_SetRenderingCallback,-exported_symbol,_FBRead,-exported_symbol,_FBWrite,-exported_symbol,_FBGetFrameBufferInfo,-exported_symbol,_ResizeVideoOutput,-exported_symbol,_RSP_PluginStartup,-exported_symbol,_RSP_PluginShutdown,-exported_symbol,_RSP_PluginGetVersion,-exported_symbol,_DoRspCycles,-exported_symbol,_InitiateRSP,-exported_symbol,_RSP_RomClosed,-exported_symbol,_CoreGetAPIVersions,-exported_symbol,_ConfigGetParameter,-exported_symbol,_ConfigSetParameter,-exported_symbol,_CoreDoCommand -l"Alamofire" -l"DSDeltaCore" -l"GBADeltaCore" -l"GBCDeltaCore" -l"GTMSessionFetcher" -l"GoogleAPIClientForREST" -l"GoogleToolboxForMac" -l"Harmony" -l"MelonDSDeltaCore" -l"N64DeltaCore" -l"NESDeltaCore" -l"Roxas" -l"SDWebImage" -l"SMCalloutView" -l"SNESDeltaCore" -l"SQLite.swift" -l"SwiftyDropbox" -l"ZIPFoundation" -l"c++" -l"sqlite3" -l"z" -framework "CoreGraphics" -framework "CoreText" -framework "Crashlytics" -framework "Fabric" -framework "Foundation" -framework "GoogleSignIn" -framework "ImageIO" -framework "LocalAuthentication" -framework "SafariServices" -framework "Security" -framework "SystemConfiguration" -framework "UIKit" -framework "WebKit"
OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/Alamofire/Alamofire.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/DSDeltaCore/DSDeltaCore.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/DeltaCore/DeltaCore.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/GBADeltaCore/GBADeltaCore.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/GBCDeltaCore/GBCDeltaCore.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/Harmony/Harmony.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/MelonDSDeltaCore/MelonDSDeltaCore.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/N64DeltaCore/N64DeltaCore.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/NESDeltaCore/NESDeltaCore.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/SNESDeltaCore/SNESDeltaCore.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/SQLite.swift/SQLite.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/SwiftyDropbox/SwiftyDropbox.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/ZIPFoundation/ZIPFoundation.modulemap" -Xcc -fmodule-map-file="${PODS_ROOT}/Headers/Public/GTMSessionFetcher/GTMSessionFetcher.modulemap" -Xcc -fmodule-map-file="${PODS_ROOT}/Headers/Public/GoogleAPIClientForREST/GoogleAPIClientForREST.modulemap" -Xcc -fmodule-map-file="${PODS_ROOT}/Headers/Public/GoogleToolboxForMac/GoogleToolboxForMac.modulemap" -Xcc -fmodule-map-file="${PODS_ROOT}/Headers/Public/Roxas/Roxas.modulemap" -Xcc -fmodule-map-file="${PODS_ROOT}/Headers/Public/SDWebImage/SDWebImage.modulemap" -Xcc -fmodule-map-file="${PODS_ROOT}/Headers/Public/SMCalloutView/SMCalloutView.modulemap" OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/Alamofire/Alamofire.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/DSDeltaCore/DSDeltaCore.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/DeltaCore/DeltaCore.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/GBADeltaCore/GBADeltaCore.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/GBCDeltaCore/GBCDeltaCore.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/Harmony/Harmony.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/MelonDSDeltaCore/MelonDSDeltaCore.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/N64DeltaCore/N64DeltaCore.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/NESDeltaCore/NESDeltaCore.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/SNESDeltaCore/SNESDeltaCore.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/SQLite.swift/SQLite.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/SwiftyDropbox/SwiftyDropbox.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/ZIPFoundation/ZIPFoundation.modulemap" -Xcc -fmodule-map-file="${PODS_ROOT}/Headers/Public/GTMSessionFetcher/GTMSessionFetcher.modulemap" -Xcc -fmodule-map-file="${PODS_ROOT}/Headers/Public/GoogleAPIClientForREST/GoogleAPIClientForREST.modulemap" -Xcc -fmodule-map-file="${PODS_ROOT}/Headers/Public/GoogleToolboxForMac/GoogleToolboxForMac.modulemap" -Xcc -fmodule-map-file="${PODS_ROOT}/Headers/Public/Roxas/Roxas.modulemap" -Xcc -fmodule-map-file="${PODS_ROOT}/Headers/Public/SDWebImage/SDWebImage.modulemap" -Xcc -fmodule-map-file="${PODS_ROOT}/Headers/Public/SMCalloutView/SMCalloutView.modulemap"

View File

@ -4,7 +4,7 @@ CLANG_WARN_QUOTED_INCLUDE_IN_FRAMEWORK_HEADER = NO
FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Crashlytics/iOS" "${PODS_ROOT}/Fabric/iOS" "${PODS_ROOT}/GoogleSignIn/Frameworks" FRAMEWORK_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Crashlytics/iOS" "${PODS_ROOT}/Fabric/iOS" "${PODS_ROOT}/GoogleSignIn/Frameworks"
GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 STATIC_LIBRARY=1 STATIC_LIBRARY=1 JIT_ENABLED=1 STATIC_LIBRARY=1 MUPENPLUSAPI TXFILTER_LIB OS_IOS GLESX GL_ERROR_DEBUG GL_DEBUG GLESX PNG_ARM_NEON_OPT=0 GCC_PREPROCESSOR_DEFINITIONS = $(inherited) COCOAPODS=1 STATIC_LIBRARY=1 STATIC_LIBRARY=1 JIT_ENABLED=1 STATIC_LIBRARY=1 MUPENPLUSAPI TXFILTER_LIB OS_IOS GLESX GL_ERROR_DEBUG GL_DEBUG GLESX PNG_ARM_NEON_OPT=0
HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/DSDeltaCore" "${PODS_ROOT}/Headers/Public/DeltaCore" "${PODS_ROOT}/Headers/Public/GBADeltaCore" "${PODS_ROOT}/Headers/Public/GBCDeltaCore" "${PODS_ROOT}/Headers/Public/GTMSessionFetcher" "${PODS_ROOT}/Headers/Public/GoogleAPIClientForREST" "${PODS_ROOT}/Headers/Public/GoogleToolboxForMac" "${PODS_ROOT}/Headers/Public/Harmony" "${PODS_ROOT}/Headers/Public/MelonDSDeltaCore" "${PODS_ROOT}/Headers/Public/N64DeltaCore" "${PODS_ROOT}/Headers/Public/NESDeltaCore" "${PODS_ROOT}/Headers/Public/Roxas" "${PODS_ROOT}/Headers/Public/SDWebImage" "${PODS_ROOT}/Headers/Public/SMCalloutView" "${PODS_ROOT}/Headers/Public/SNESDeltaCore" "${PODS_ROOT}/Headers/Public/SQLite.swift" "${PODS_ROOT}/Headers/Public/SwiftyDropbox" "${PODS_CONFIGURATION_BUILD_DIR}" "$(PODS_ROOT)/Headers/Private/DSDeltaCore/desmume/desmume/src/libretro-common/include" "${PODS_CONFIGURATION_BUILD_DIR}" "$(PODS_ROOT)/Headers/Private/GBADeltaCore/SFML/include" "$(PODS_ROOT)/Headers/Private/GBADeltaCore/SFML/src" "${PODS_CONFIGURATION_BUILD_DIR}" "${PODS_CONFIGURATION_BUILD_DIR}" "$(PODS_ROOT)/Headers/Private/MelonDSDeltaCore/melonDS/src" "${PODS_CONFIGURATION_BUILD_DIR}" "$(PODS_ROOT)/Headers/Private/N64DeltaCore/Mupen64Plus/mupen64plus-core/subprojects/**" "$(PODS_ROOT)/Headers/Private/N64DeltaCore/libMupen64Plus/SDL" "${PODS_CONFIGURATION_BUILD_DIR}" "$(PODS_ROOT)/Headers/Private/N64DeltaCore/Mupen64Plus/mupen64plus-core/subprojects/**" "$(PODS_ROOT)/Headers/Private/N64DeltaCore/libMupen64Plus/SDL" "$(PODS_ROOT)/Headers/Private/N64DeltaCore/Mupen64Plus/GLideN64/src" "$(PODS_ROOT)/Headers/Private/N64DeltaCore/Mupen64Plus/GLideN64/src/inc" "$(PODS_ROOT)/Headers/Private/N64DeltaCore/Mupen64Plus/GLideN64/src" "$(PODS_ROOT)/Headers/Private/N64DeltaCore/Mupen64Plus/GLideN64/src/osal" "$(PODS_ROOT)/Headers/Private/N64DeltaCore/Mupen64Plus/libpng" HEADER_SEARCH_PATHS = $(inherited) "${PODS_ROOT}/Headers/Public" "${PODS_ROOT}/Headers/Public/DSDeltaCore" "${PODS_ROOT}/Headers/Public/DeltaCore" "${PODS_ROOT}/Headers/Public/GBADeltaCore" "${PODS_ROOT}/Headers/Public/GBCDeltaCore" "${PODS_ROOT}/Headers/Public/GTMSessionFetcher" "${PODS_ROOT}/Headers/Public/GoogleAPIClientForREST" "${PODS_ROOT}/Headers/Public/GoogleToolboxForMac" "${PODS_ROOT}/Headers/Public/Harmony" "${PODS_ROOT}/Headers/Public/MelonDSDeltaCore" "${PODS_ROOT}/Headers/Public/N64DeltaCore" "${PODS_ROOT}/Headers/Public/NESDeltaCore" "${PODS_ROOT}/Headers/Public/Roxas" "${PODS_ROOT}/Headers/Public/SDWebImage" "${PODS_ROOT}/Headers/Public/SMCalloutView" "${PODS_ROOT}/Headers/Public/SNESDeltaCore" "${PODS_ROOT}/Headers/Public/SQLite.swift" "${PODS_ROOT}/Headers/Public/SwiftyDropbox" "${PODS_CONFIGURATION_BUILD_DIR}" "$(PODS_ROOT)/Headers/Private/DSDeltaCore/desmume/desmume/src/libretro-common/include" "${PODS_CONFIGURATION_BUILD_DIR}" "$(PODS_ROOT)/Headers/Private/GBADeltaCore/SFML/include" "$(PODS_ROOT)/Headers/Private/GBADeltaCore/SFML/src" "${PODS_CONFIGURATION_BUILD_DIR}" "${PODS_CONFIGURATION_BUILD_DIR}" "$(PODS_ROOT)/Headers/Private/MelonDSDeltaCore/melonDS/src" "${PODS_CONFIGURATION_BUILD_DIR}" "$(PODS_ROOT)/Headers/Private/N64DeltaCore/Mupen64Plus/mupen64plus-core/subprojects/**" "$(PODS_ROOT)/Headers/Private/N64DeltaCore/libMupen64Plus/SDL" "${PODS_CONFIGURATION_BUILD_DIR}" "$(PODS_ROOT)/Headers/Private/N64DeltaCore/Mupen64Plus/mupen64plus-core/subprojects/**" "$(PODS_ROOT)/Headers/Private/N64DeltaCore/libMupen64Plus/SDL" "$(PODS_ROOT)/Headers/Private/N64DeltaCore/Mupen64Plus/GLideN64/src" "$(PODS_ROOT)/Headers/Private/N64DeltaCore/Mupen64Plus/GLideN64/src/inc" "$(PODS_ROOT)/Headers/Private/N64DeltaCore/Mupen64Plus/GLideN64/src" "$(PODS_ROOT)/Headers/Private/N64DeltaCore/Mupen64Plus/GLideN64/src/osal" "$(PODS_ROOT)/Headers/Private/N64DeltaCore/Mupen64Plus/libpng"
LIBRARY_SEARCH_PATHS = $(inherited) "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire" "${PODS_CONFIGURATION_BUILD_DIR}/DSDeltaCore" "${PODS_CONFIGURATION_BUILD_DIR}/DeltaCore" "${PODS_CONFIGURATION_BUILD_DIR}/GBADeltaCore" "${PODS_CONFIGURATION_BUILD_DIR}/GBCDeltaCore" "${PODS_CONFIGURATION_BUILD_DIR}/GTMSessionFetcher" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleAPIClientForREST" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleToolboxForMac" "${PODS_CONFIGURATION_BUILD_DIR}/Harmony" "${PODS_CONFIGURATION_BUILD_DIR}/MelonDSDeltaCore" "${PODS_CONFIGURATION_BUILD_DIR}/N64DeltaCore" "${PODS_CONFIGURATION_BUILD_DIR}/NESDeltaCore" "${PODS_CONFIGURATION_BUILD_DIR}/Roxas" "${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage" "${PODS_CONFIGURATION_BUILD_DIR}/SMCalloutView" "${PODS_CONFIGURATION_BUILD_DIR}/SNESDeltaCore" "${PODS_CONFIGURATION_BUILD_DIR}/SQLite.swift" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyDropbox" "${PODS_CONFIGURATION_BUILD_DIR}/ZIPFoundation" LIBRARY_SEARCH_PATHS = $(inherited) "${DT_TOOLCHAIN_DIR}/usr/lib/swift/${PLATFORM_NAME}" "${PODS_CONFIGURATION_BUILD_DIR}/Alamofire" "${PODS_CONFIGURATION_BUILD_DIR}/DSDeltaCore" "${PODS_CONFIGURATION_BUILD_DIR}/DeltaCore" "${PODS_CONFIGURATION_BUILD_DIR}/GBADeltaCore" "${PODS_CONFIGURATION_BUILD_DIR}/GBCDeltaCore" "${PODS_CONFIGURATION_BUILD_DIR}/GTMSessionFetcher" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleAPIClientForREST" "${PODS_CONFIGURATION_BUILD_DIR}/GoogleToolboxForMac" "${PODS_CONFIGURATION_BUILD_DIR}/Harmony" "${PODS_CONFIGURATION_BUILD_DIR}/MelonDSDeltaCore" "${PODS_CONFIGURATION_BUILD_DIR}/N64DeltaCore" "${PODS_CONFIGURATION_BUILD_DIR}/NESDeltaCore" "${PODS_CONFIGURATION_BUILD_DIR}/Roxas" "${PODS_CONFIGURATION_BUILD_DIR}/SDWebImage" "${PODS_CONFIGURATION_BUILD_DIR}/SMCalloutView" "${PODS_CONFIGURATION_BUILD_DIR}/SNESDeltaCore" "${PODS_CONFIGURATION_BUILD_DIR}/SQLite.swift" "${PODS_CONFIGURATION_BUILD_DIR}/SwiftyDropbox" "${PODS_CONFIGURATION_BUILD_DIR}/ZIPFoundation" /usr/lib/swift
OTHER_CFLAGS = $(inherited) -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/Alamofire/Alamofire.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/DSDeltaCore/DSDeltaCore.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/DeltaCore/DeltaCore.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/GBADeltaCore/GBADeltaCore.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/GBCDeltaCore/GBCDeltaCore.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/Harmony/Harmony.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/MelonDSDeltaCore/MelonDSDeltaCore.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/N64DeltaCore/N64DeltaCore.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/NESDeltaCore/NESDeltaCore.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/SNESDeltaCore/SNESDeltaCore.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/SQLite.swift/SQLite.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/SwiftyDropbox/SwiftyDropbox.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/ZIPFoundation/ZIPFoundation.modulemap" -fmodule-map-file="${PODS_ROOT}/Headers/Public/GTMSessionFetcher/GTMSessionFetcher.modulemap" -fmodule-map-file="${PODS_ROOT}/Headers/Public/GoogleAPIClientForREST/GoogleAPIClientForREST.modulemap" -fmodule-map-file="${PODS_ROOT}/Headers/Public/GoogleToolboxForMac/GoogleToolboxForMac.modulemap" -fmodule-map-file="${PODS_ROOT}/Headers/Public/Roxas/Roxas.modulemap" -fmodule-map-file="${PODS_ROOT}/Headers/Public/SDWebImage/SDWebImage.modulemap" -fmodule-map-file="${PODS_ROOT}/Headers/Public/SMCalloutView/SMCalloutView.modulemap" -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/DSDeltaCore" -isystem "${PODS_ROOT}/Headers/Public/GBADeltaCore" -isystem "${PODS_ROOT}/Headers/Public/GBCDeltaCore" -isystem "${PODS_ROOT}/Headers/Public/Harmony" -isystem "${PODS_ROOT}/Headers/Public/MelonDSDeltaCore" -isystem "${PODS_ROOT}/Headers/Public/N64DeltaCore" -isystem "${PODS_ROOT}/Headers/Public/NESDeltaCore" -isystem "${PODS_ROOT}/Headers/Public/SNESDeltaCore" -iframework "${PODS_ROOT}/Crashlytics/iOS" -iframework "${PODS_ROOT}/Fabric/iOS" -iframework "${PODS_ROOT}/GoogleSignIn/Frameworks" -DHOST_DARWIN -DDESMUME_COCOA -DHAVE_OPENGL -DHAVE_LIBZ -DANDROID -fexceptions -ftree-vectorize -DCOMPRESS_MT -DIOS -DOBJ_C -marm -fvisibility=hidden -DSTATIC_LIBRARY=1 -DSTATIC_LIBRARY -DHAVE_CSTDINT -fno-strict-aliasing -DGCC -pthread -fPIC -D__unix__ -ffast-math -fno-strict-aliasing -DGCC -pthread -fPIC -D__unix__ -ffast-math -D__VEC4_OPT -fvisibility=hidden -funsigned-char -ffast-math -finline -fno-builtin -fno-common -fomit-frame-pointer -funroll-loops -fstrict-aliasing -DHAVE_STDINT_H -DARM -DSTATIC_LIBRARY=1 OTHER_CFLAGS = $(inherited) -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/Alamofire/Alamofire.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/DSDeltaCore/DSDeltaCore.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/DeltaCore/DeltaCore.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/GBADeltaCore/GBADeltaCore.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/GBCDeltaCore/GBCDeltaCore.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/Harmony/Harmony.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/MelonDSDeltaCore/MelonDSDeltaCore.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/N64DeltaCore/N64DeltaCore.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/NESDeltaCore/NESDeltaCore.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/SNESDeltaCore/SNESDeltaCore.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/SQLite.swift/SQLite.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/SwiftyDropbox/SwiftyDropbox.modulemap" -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/ZIPFoundation/ZIPFoundation.modulemap" -fmodule-map-file="${PODS_ROOT}/Headers/Public/GTMSessionFetcher/GTMSessionFetcher.modulemap" -fmodule-map-file="${PODS_ROOT}/Headers/Public/GoogleAPIClientForREST/GoogleAPIClientForREST.modulemap" -fmodule-map-file="${PODS_ROOT}/Headers/Public/GoogleToolboxForMac/GoogleToolboxForMac.modulemap" -fmodule-map-file="${PODS_ROOT}/Headers/Public/Roxas/Roxas.modulemap" -fmodule-map-file="${PODS_ROOT}/Headers/Public/SDWebImage/SDWebImage.modulemap" -fmodule-map-file="${PODS_ROOT}/Headers/Public/SMCalloutView/SMCalloutView.modulemap" -isystem "${PODS_ROOT}/Headers/Public" -isystem "${PODS_ROOT}/Headers/Public/DSDeltaCore" -isystem "${PODS_ROOT}/Headers/Public/GBADeltaCore" -isystem "${PODS_ROOT}/Headers/Public/GBCDeltaCore" -isystem "${PODS_ROOT}/Headers/Public/Harmony" -isystem "${PODS_ROOT}/Headers/Public/MelonDSDeltaCore" -isystem "${PODS_ROOT}/Headers/Public/N64DeltaCore" -isystem "${PODS_ROOT}/Headers/Public/NESDeltaCore" -isystem "${PODS_ROOT}/Headers/Public/SNESDeltaCore" -iframework "${PODS_ROOT}/Crashlytics/iOS" -iframework "${PODS_ROOT}/Fabric/iOS" -iframework "${PODS_ROOT}/GoogleSignIn/Frameworks" -DHOST_DARWIN -DDESMUME_COCOA -DHAVE_OPENGL -DHAVE_LIBZ -DANDROID -fexceptions -ftree-vectorize -DCOMPRESS_MT -DIOS -DOBJ_C -marm -fvisibility=hidden -DSTATIC_LIBRARY=1 -DSTATIC_LIBRARY -DHAVE_CSTDINT -fno-strict-aliasing -DGCC -pthread -fPIC -D__unix__ -ffast-math -fno-strict-aliasing -DGCC -pthread -fPIC -D__unix__ -ffast-math -D__VEC4_OPT -fvisibility=hidden -funsigned-char -ffast-math -finline -fno-builtin -fno-common -fomit-frame-pointer -funroll-loops -fstrict-aliasing -DHAVE_STDINT_H -DARM -DSTATIC_LIBRARY=1
OTHER_LDFLAGS = $(inherited) -ObjC -Wl,-exported_symbol,_Video_PluginStartup,-exported_symbol,_Video_PluginShutdown,-exported_symbol,_Video_PluginGetVersion,-exported_symbol,_Video_RomOpen,-exported_symbol,_Video_RomClosed,-exported_symbol,_ConfigGetSharedDataFilepath,-exported_symbol,_ConfigGetUserConfigPath,-exported_symbol,_ConfigGetUserCachePath,-exported_symbol,_ConfigGetUserDataPath,-exported_symbol,_ConfigOpenSection,-exported_symbol,_ConfigDeleteSection,-exported_symbol,_ConfigSaveSection,-exported_symbol,_ConfigSaveFile,-exported_symbol,_ConfigSetDefaultInt,-exported_symbol,_ConfigSetDefaultFloat,-exported_symbol,_ConfigSetDefaultBool,-exported_symbol,_ConfigSetDefaultString,-exported_symbol,_ConfigGetParamInt,-exported_symbol,_ConfigGetParamFloat,-exported_symbol,_ConfigGetParamBool,-exported_symbol,_ConfigGetParamString,-exported_symbol,_ConfigExternalGetParameter,-exported_symbol,_ConfigExternalOpen,-exported_symbol,_ConfigExternalClose,-exported_symbol,_VidExt_Init,-exported_symbol,_VidExt_Quit,-exported_symbol,_VidExt_ListFullscreenModes,-exported_symbol,_VidExt_SetVideoMode,-exported_symbol,_VidExt_SetCaption,-exported_symbol,_VidExt_ToggleFullScreen,-exported_symbol,_VidExt_ResizeWindow,-exported_symbol,_VidExt_GL_GetProcAddress,-exported_symbol,_VidExt_GL_SetAttribute,-exported_symbol,_VidExt_GL_GetAttribute,-exported_symbol,_VidExt_GL_SwapBuffers,-exported_symbol,_ChangeWindow,-exported_symbol,_InitiateGFX,-exported_symbol,_MoveScreen,-exported_symbol,_ProcessDList,-exported_symbol,_ProcessRDPList,-exported_symbol,_ShowCFB,-exported_symbol,_UpdateScreen,-exported_symbol,_ViStatusChanged,-exported_symbol,_ViWidthChanged,-exported_symbol,_ReadScreen2,-exported_symbol,_SetRenderingCallback,-exported_symbol,_FBRead,-exported_symbol,_FBWrite,-exported_symbol,_FBGetFrameBufferInfo,-exported_symbol,_ResizeVideoOutput,-exported_symbol,_RSP_PluginStartup,-exported_symbol,_RSP_PluginShutdown,-exported_symbol,_RSP_PluginGetVersion,-exported_symbol,_DoRspCycles,-exported_symbol,_InitiateRSP,-exported_symbol,_RSP_RomClosed,-exported_symbol,_CoreGetAPIVersions,-exported_symbol,_ConfigGetParameter,-exported_symbol,_ConfigSetParameter,-exported_symbol,_CoreDoCommand -l"Alamofire" -l"DSDeltaCore" -l"GBADeltaCore" -l"GBCDeltaCore" -l"GTMSessionFetcher" -l"GoogleAPIClientForREST" -l"GoogleToolboxForMac" -l"Harmony" -l"MelonDSDeltaCore" -l"N64DeltaCore" -l"NESDeltaCore" -l"Roxas" -l"SDWebImage" -l"SMCalloutView" -l"SNESDeltaCore" -l"SQLite.swift" -l"SwiftyDropbox" -l"ZIPFoundation" -l"c++" -l"sqlite3" -l"z" -framework "CoreGraphics" -framework "CoreText" -framework "Crashlytics" -framework "Fabric" -framework "Foundation" -framework "GoogleSignIn" -framework "ImageIO" -framework "LocalAuthentication" -framework "SafariServices" -framework "Security" -framework "SystemConfiguration" -framework "UIKit" -framework "WebKit" OTHER_LDFLAGS = $(inherited) -ObjC -Wl,-exported_symbol,_Video_PluginStartup,-exported_symbol,_Video_PluginShutdown,-exported_symbol,_Video_PluginGetVersion,-exported_symbol,_Video_RomOpen,-exported_symbol,_Video_RomClosed,-exported_symbol,_ConfigGetSharedDataFilepath,-exported_symbol,_ConfigGetUserConfigPath,-exported_symbol,_ConfigGetUserCachePath,-exported_symbol,_ConfigGetUserDataPath,-exported_symbol,_ConfigOpenSection,-exported_symbol,_ConfigDeleteSection,-exported_symbol,_ConfigSaveSection,-exported_symbol,_ConfigSaveFile,-exported_symbol,_ConfigSetDefaultInt,-exported_symbol,_ConfigSetDefaultFloat,-exported_symbol,_ConfigSetDefaultBool,-exported_symbol,_ConfigSetDefaultString,-exported_symbol,_ConfigGetParamInt,-exported_symbol,_ConfigGetParamFloat,-exported_symbol,_ConfigGetParamBool,-exported_symbol,_ConfigGetParamString,-exported_symbol,_ConfigExternalGetParameter,-exported_symbol,_ConfigExternalOpen,-exported_symbol,_ConfigExternalClose,-exported_symbol,_VidExt_Init,-exported_symbol,_VidExt_Quit,-exported_symbol,_VidExt_ListFullscreenModes,-exported_symbol,_VidExt_SetVideoMode,-exported_symbol,_VidExt_SetCaption,-exported_symbol,_VidExt_ToggleFullScreen,-exported_symbol,_VidExt_ResizeWindow,-exported_symbol,_VidExt_GL_GetProcAddress,-exported_symbol,_VidExt_GL_SetAttribute,-exported_symbol,_VidExt_GL_GetAttribute,-exported_symbol,_VidExt_GL_SwapBuffers,-exported_symbol,_ChangeWindow,-exported_symbol,_InitiateGFX,-exported_symbol,_MoveScreen,-exported_symbol,_ProcessDList,-exported_symbol,_ProcessRDPList,-exported_symbol,_ShowCFB,-exported_symbol,_UpdateScreen,-exported_symbol,_ViStatusChanged,-exported_symbol,_ViWidthChanged,-exported_symbol,_ReadScreen2,-exported_symbol,_SetRenderingCallback,-exported_symbol,_FBRead,-exported_symbol,_FBWrite,-exported_symbol,_FBGetFrameBufferInfo,-exported_symbol,_ResizeVideoOutput,-exported_symbol,_RSP_PluginStartup,-exported_symbol,_RSP_PluginShutdown,-exported_symbol,_RSP_PluginGetVersion,-exported_symbol,_DoRspCycles,-exported_symbol,_InitiateRSP,-exported_symbol,_RSP_RomClosed,-exported_symbol,_CoreGetAPIVersions,-exported_symbol,_ConfigGetParameter,-exported_symbol,_ConfigSetParameter,-exported_symbol,_CoreDoCommand -l"Alamofire" -l"DSDeltaCore" -l"GBADeltaCore" -l"GBCDeltaCore" -l"GTMSessionFetcher" -l"GoogleAPIClientForREST" -l"GoogleToolboxForMac" -l"Harmony" -l"MelonDSDeltaCore" -l"N64DeltaCore" -l"NESDeltaCore" -l"Roxas" -l"SDWebImage" -l"SMCalloutView" -l"SNESDeltaCore" -l"SQLite.swift" -l"SwiftyDropbox" -l"ZIPFoundation" -l"c++" -l"sqlite3" -l"z" -framework "CoreGraphics" -framework "CoreText" -framework "Crashlytics" -framework "Fabric" -framework "Foundation" -framework "GoogleSignIn" -framework "ImageIO" -framework "LocalAuthentication" -framework "SafariServices" -framework "Security" -framework "SystemConfiguration" -framework "UIKit" -framework "WebKit"
OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/Alamofire/Alamofire.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/DSDeltaCore/DSDeltaCore.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/DeltaCore/DeltaCore.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/GBADeltaCore/GBADeltaCore.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/GBCDeltaCore/GBCDeltaCore.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/Harmony/Harmony.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/MelonDSDeltaCore/MelonDSDeltaCore.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/N64DeltaCore/N64DeltaCore.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/NESDeltaCore/NESDeltaCore.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/SNESDeltaCore/SNESDeltaCore.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/SQLite.swift/SQLite.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/SwiftyDropbox/SwiftyDropbox.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/ZIPFoundation/ZIPFoundation.modulemap" -Xcc -fmodule-map-file="${PODS_ROOT}/Headers/Public/GTMSessionFetcher/GTMSessionFetcher.modulemap" -Xcc -fmodule-map-file="${PODS_ROOT}/Headers/Public/GoogleAPIClientForREST/GoogleAPIClientForREST.modulemap" -Xcc -fmodule-map-file="${PODS_ROOT}/Headers/Public/GoogleToolboxForMac/GoogleToolboxForMac.modulemap" -Xcc -fmodule-map-file="${PODS_ROOT}/Headers/Public/Roxas/Roxas.modulemap" -Xcc -fmodule-map-file="${PODS_ROOT}/Headers/Public/SDWebImage/SDWebImage.modulemap" -Xcc -fmodule-map-file="${PODS_ROOT}/Headers/Public/SMCalloutView/SMCalloutView.modulemap" OTHER_SWIFT_FLAGS = $(inherited) -D COCOAPODS -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/Alamofire/Alamofire.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/DSDeltaCore/DSDeltaCore.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/DeltaCore/DeltaCore.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/GBADeltaCore/GBADeltaCore.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/GBCDeltaCore/GBCDeltaCore.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/Harmony/Harmony.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/MelonDSDeltaCore/MelonDSDeltaCore.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/N64DeltaCore/N64DeltaCore.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/NESDeltaCore/NESDeltaCore.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/SNESDeltaCore/SNESDeltaCore.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/SQLite.swift/SQLite.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/SwiftyDropbox/SwiftyDropbox.modulemap" -Xcc -fmodule-map-file="${PODS_CONFIGURATION_BUILD_DIR}/ZIPFoundation/ZIPFoundation.modulemap" -Xcc -fmodule-map-file="${PODS_ROOT}/Headers/Public/GTMSessionFetcher/GTMSessionFetcher.modulemap" -Xcc -fmodule-map-file="${PODS_ROOT}/Headers/Public/GoogleAPIClientForREST/GoogleAPIClientForREST.modulemap" -Xcc -fmodule-map-file="${PODS_ROOT}/Headers/Public/GoogleToolboxForMac/GoogleToolboxForMac.modulemap" -Xcc -fmodule-map-file="${PODS_ROOT}/Headers/Public/Roxas/Roxas.modulemap" -Xcc -fmodule-map-file="${PODS_ROOT}/Headers/Public/SDWebImage/SDWebImage.modulemap" -Xcc -fmodule-map-file="${PODS_ROOT}/Headers/Public/SMCalloutView/SMCalloutView.modulemap"

View File

@ -0,0 +1,70 @@
<?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">
<array>
<dict>
<key>name</key>
<string>Grant Gliner</string>
<key>link</key>
<string>https://twitter.com/GrantGliner</string>
<key>linkName</key>
<string>@GrantGliner</string>
<key>contributions</key>
<array>
<dict>
<key>name</key>
<string>Pause Menu Icons</string>
</dict>
</array>
</dict>
<dict>
<key>name</key>
<string>Eric Lewis</string>
<key>link</key>
<string>https://github.com/ericlewis</string>
<key>linkName</key>
<string>github.com/ericlewis</string>
<key>contributions</key>
<array>
<dict>
<key>name</key>
<string>Dark Mode</string>
<key>link</key>
<string>https://github.com/rileytestut/Delta/pull/82</string>
</dict>
</array>
</dict>
<dict>
<key>name</key>
<string>Chris Rittenhouse</string>
<key>link</key>
<string>https://www.litritt.com</string>
<key>linkName</key>
<string>litritt.com</string>
<key>contributions</key>
<array>
<dict>
<key>name</key>
<string>Genesis Skin</string>
</dict>
</array>
</dict>
<dict>
<key>name</key>
<string>Noah Keck</string>
<key>link</key>
<string>https://github.com/noah978</string>
<key>linkName</key>
<string>github.com/noah978</string>
<key>contributions</key>
<array>
<dict>
<key>name</key>
<string>CheatBase</string>
<key>link</key>
<string>https://github.com/CheatBase/CheatBase</string>
</dict>
</array>
</dict>
</array>
</plist>

BIN
Resources/cheatbase.zip Normal file

Binary file not shown.

BIN
Resources/openvgdb.sqlite Executable file → Normal file

Binary file not shown.