Adds DS settings UI to import melonDS BIOS + switch DS cores

This commit is contained in:
Riley Testut 2020-04-23 17:12:07 -07:00
parent 35fe306c12
commit 6f336a82a5
12 changed files with 883 additions and 53 deletions

View File

@ -133,6 +133,7 @@
BFE56E1923EB7BE00014FECD /* UIImage+SymbolFallback.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFE56E1823EB7BE00014FECD /* UIImage+SymbolFallback.swift */; };
BFE593CA21F3F8B7003412A6 /* GameSave.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFE593C921F3F8B7003412A6 /* GameSave.swift */; };
BFE593CC21F3F8C2003412A6 /* _GameSave.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFE593CB21F3F8C2003412A6 /* _GameSave.swift */; };
BFE9908024451E15006409A7 /* MelonDSCoreSettingsViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFE9907F24451E15006409A7 /* MelonDSCoreSettingsViewController.swift */; };
BFEE943D23F2180200CDA07D /* Delta4ToDelta5.xcmappingmodel in Sources */ = {isa = PBXBuildFile; fileRef = BFEE943C23F2180200CDA07D /* Delta4ToDelta5.xcmappingmodel */; };
BFEF24F31F7DD4FD00454C62 /* SaveStateMigrationPolicy.swift in Sources */ = {isa = PBXBuildFile; fileRef = BFEF24F21F7DD4FB00454C62 /* SaveStateMigrationPolicy.swift */; };
BFF6452E1F7CC5060056533E /* GameControllerInputMappingTransformer.swift in Sources */ = {isa = PBXBuildFile; fileRef = BF6B82A41F7CC2A300042BFB /* GameControllerInputMappingTransformer.swift */; };
@ -293,6 +294,7 @@
BFE56E1823EB7BE00014FECD /* UIImage+SymbolFallback.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = "UIImage+SymbolFallback.swift"; sourceTree = "<group>"; };
BFE593C921F3F8B7003412A6 /* GameSave.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = GameSave.swift; sourceTree = "<group>"; };
BFE593CB21F3F8C2003412A6 /* _GameSave.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = _GameSave.swift; sourceTree = "<group>"; };
BFE9907F24451E15006409A7 /* MelonDSCoreSettingsViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = MelonDSCoreSettingsViewController.swift; sourceTree = "<group>"; };
BFEC732C1AAECC4A00650035 /* Roxas.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = Roxas.framework; sourceTree = BUILT_PRODUCTS_DIR; };
BFEE943C23F2180200CDA07D /* Delta4ToDelta5.xcmappingmodel */ = {isa = PBXFileReference; lastKnownFileType = wrapper.xcmappingmodel; path = Delta4ToDelta5.xcmappingmodel; sourceTree = "<group>"; };
BFEF24F21F7DD4FB00454C62 /* SaveStateMigrationPolicy.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SaveStateMigrationPolicy.swift; sourceTree = "<group>"; };
@ -348,7 +350,6 @@
BF5942901E09BD1A0051894B /* NSFetchedResultsController+Conveniences.m */,
BF5942911E09BD1A0051894B /* NSManagedObject+Conveniences.swift */,
BF5942921E09BD1A0051894B /* NSManagedObjectContext+Conveniences.swift */,
BFBAB2E21EB685A2004E0B0E /* DeltaCoreProtocol+Delta.swift */,
BF18B61E1E2985F900F70067 /* UIAlertController+Importing.swift */,
BFC6F7B71F435BC500221B96 /* Input+Display.swift */,
BF6424841F5CBDC900D6AB44 /* UIView+ParentViewController.swift */,
@ -606,6 +607,7 @@
isa = PBXGroup;
children = (
BF4828851F9028F500028B97 /* System.swift */,
BFBAB2E21EB685A2004E0B0E /* DeltaCoreProtocol+Delta.swift */,
);
path = Systems;
sourceTree = "<group>";
@ -666,6 +668,7 @@
BF5E7F451B9A652600AE44F8 /* Settings.storyboard */,
BF5E7F431B9A650B00AE44F8 /* SettingsViewController.swift */,
BFB3645723245A6000CD0EB1 /* LicensesViewController.swift */,
BFE9907E24451DE6006409A7 /* Cores */,
BF71CF851FE8FFF1001F1613 /* App Icon Shortcuts */,
BF11734E1DA32CEC00047DF8 /* Controllers */,
BF1DAD5B1D9F574900E752A7 /* Controller Skins */,
@ -706,6 +709,14 @@
path = "Popover Menu";
sourceTree = "<group>";
};
BFE9907E24451DE6006409A7 /* Cores */ = {
isa = PBXGroup;
children = (
BFE9907F24451E15006409A7 /* MelonDSCoreSettingsViewController.swift */,
);
path = Cores;
sourceTree = "<group>";
};
BFEC732F1AAECCBD00650035 /* Resources */ = {
isa = PBXGroup;
children = (
@ -1110,6 +1121,7 @@
BF1173501DA32CF600047DF8 /* ControllersSettingsViewController.swift in Sources */,
BFFC461E1D59823500AF2CC6 /* GamesPresentationController.swift in Sources */,
BF99A5971DC2F9C400468E9E /* ControllerSkinTableViewCell.swift in Sources */,
BFE9908024451E15006409A7 /* MelonDSCoreSettingsViewController.swift in Sources */,
BF5942861E09BC8B0051894B /* _Cheat.swift in Sources */,
BF5E7F441B9A650B00AE44F8 /* SettingsViewController.swift in Sources */,
BF8CA9361F5F651900499FDD /* PopoverMenuController.swift in Sources */,

View File

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15705" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="SPq-Bk-fQl">
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="16096" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="SPq-Bk-fQl">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15706"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16086"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
</dependencies>
<scenes>
@ -84,6 +84,7 @@
<segue destination="X2o-q6-XD5" kind="unwind" identifier="unwindFromGames" unwindAction="unwindFromGamesViewControllerWith:" id="k8C-Xn-maU"/>
<segue destination="MPk-bF-nkj" kind="presentation" identifier="saveStates" customClass="SaveStatesStoryboardSegue" customModule="Delta" customModuleProvider="target" id="1Xp-2J-0cq"/>
<segue destination="qdE-gb-V2e" kind="presentation" identifier="preferredControllerSkins" id="i6y-cP-3WM"/>
<segue destination="V2x-v0-jWm" kind="presentation" identifier="showDSSettings" id="kuV-tY-Y0B"/>
</connections>
</collectionViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="bW1-t8-idm" userLabel="First Responder" sceneMemberID="firstResponder"/>
@ -265,11 +266,37 @@
</objects>
<point key="canvasLocation" x="2652" y="2394"/>
</scene>
<!--Navigation Controller-->
<scene sceneID="OW2-zT-pbF">
<objects>
<navigationController id="V2x-v0-jWm" sceneMemberID="viewController">
<navigationBar key="navigationBar" contentMode="scaleToFill" insetsLayoutMarginsFromSafeArea="NO" id="pjb-4I-yar">
<rect key="frame" x="0.0" y="0.0" width="375" height="56"/>
<autoresizingMask key="autoresizingMask"/>
</navigationBar>
<connections>
<segue destination="cFV-KV-B18" kind="relationship" relationship="rootViewController" id="VBP-fg-oNH"/>
</connections>
</navigationController>
<placeholder placeholderIdentifier="IBFirstResponder" id="Jo9-gl-p5p" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2652" y="3085"/>
</scene>
<!--dsSettingsViewController-->
<scene sceneID="anM-Cb-BaB">
<objects>
<viewControllerPlaceholder storyboardName="Settings" referencedIdentifier="dsSettingsViewController" id="cFV-KV-B18" sceneMemberID="viewController">
<navigationItem key="navigationItem" id="Dkm-Hm-sQa"/>
</viewControllerPlaceholder>
<placeholder placeholderIdentifier="IBFirstResponder" id="IS2-hO-HBN" userLabel="First Responder" customClass="UIResponder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="3258" y="3084"/>
</scene>
</scenes>
<resources>
<image name="SettingsButton" width="22" height="22"/>
</resources>
<inferredMetricsTieBreakers>
<segue reference="Tey-6Z-UHp"/>
</inferredMetricsTieBreakers>
<resources>
<image name="SettingsButton" width="22" height="22"/>
</resources>
</document>

View File

@ -1,9 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="15705" 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="16096" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" useTraitCollections="YES" colorMatched="YES" initialViewController="ssH-mM-uG6">
<device id="retina4_7" orientation="portrait" appearance="light"/>
<dependencies>
<deployment identifier="iOS"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="15706"/>
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="16087"/>
<capability name="Named colors" minToolsVersion="9.0"/>
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
@ -18,7 +18,7 @@
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" red="0.93725490199999995" green="0.93725490199999995" blue="0.95686274510000002" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<label key="tableFooterView" opaque="NO" userInteractionEnabled="NO" contentMode="left" horizontalHuggingPriority="251" verticalHuggingPriority="251" text="Delta 0.6.0" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Str-BY-agW">
<rect key="frame" x="0.0" y="1376.5" width="375" height="44"/>
<rect key="frame" x="0.0" y="1455.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="0.5" alpha="1" colorSpace="calibratedWhite"/>
@ -411,10 +411,38 @@
</tableViewCell>
</cells>
</tableViewSection>
<tableViewSection headerTitle="Core Settings" footerTitle="Manage settings for individual emulation cores." id="1eN-id-M8c">
<cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="Cell" textLabel="zeg-kj-CMN" detailTextLabel="CFd-fn-r0t" style="IBUITableViewCellStyleValue1" id="lxX-Hz-sXl">
<rect key="frame" x="0.0" y="1209.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="lxX-Hz-sXl" id="OWw-OH-9F5">
<rect key="frame" x="0.0" y="0.0" width="356" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Nintendo DS" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="zeg-kj-CMN">
<rect key="frame" x="15" y="12" width="97" height="20.5"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" red="0.0" green="0.0" blue="0.0" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="melonDS" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="CFd-fn-r0t">
<rect key="frame" x="278.5" y="12" width="69.5" height="20.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="0.5" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</tableViewCellContentView>
</tableViewCell>
</cells>
</tableViewSection>
<tableViewSection headerTitle="Patreon" footerTitle="Receive early access to new features and more by becoming a patron." id="QvT-Yt-oP1">
<cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="Cell" textLabel="faT-qa-JP0" style="IBUITableViewCellStyleDefault" id="4it-3L-j8P">
<rect key="frame" x="0.0" y="1209.5" width="375" height="44"/>
<rect key="frame" x="0.0" y="1329" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="4it-3L-j8P" id="7dE-36-hzp">
<rect key="frame" x="0.0" y="0.0" width="356" height="44"/>
@ -435,7 +463,7 @@
<tableViewSection headerTitle="Credits" id="foh-L9-g6W">
<cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="DetailCell" textLabel="Pum-dL-hGn" detailTextLabel="WQ6-m7-zhh" style="IBUITableViewCellStyleValue1" id="BU4-ee-DGz">
<rect key="frame" x="0.0" y="1337.5" width="375" height="44"/>
<rect key="frame" x="0.0" y="1457" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="BU4-ee-DGz" id="fWf-gm-1sf">
<rect key="frame" x="0.0" y="0.0" width="356" height="44"/>
@ -459,7 +487,7 @@
</tableViewCellContentView>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="DetailCell" textLabel="gWx-Xn-5Nf" detailTextLabel="09x-GX-cpy" style="IBUITableViewCellStyleValue1" id="8qc-0t-Nte">
<rect key="frame" x="0.0" y="1381.5" width="375" height="44"/>
<rect key="frame" x="0.0" y="1501" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="8qc-0t-Nte" id="jUL-fL-i0n">
<rect key="frame" x="0.0" y="0.0" width="356" height="44"/>
@ -483,7 +511,7 @@
</tableViewCellContentView>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="default" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="DetailCell" textLabel="zro-BX-EY9" detailTextLabel="e45-FD-ug2" style="IBUITableViewCellStyleValue1" id="Zh9-JJ-jEQ">
<rect key="frame" x="0.0" y="1425.5" width="375" height="44"/>
<rect key="frame" x="0.0" y="1545" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="Zh9-JJ-jEQ" id="VCc-oJ-ODB">
<rect key="frame" x="0.0" y="0.0" width="356" height="44"/>
@ -507,7 +535,7 @@
</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">
<rect key="frame" x="0.0" y="1469.5" width="375" height="44"/>
<rect key="frame" x="0.0" y="1589" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="j7p-ZK-mHq" id="BqT-yP-OpS">
<rect key="frame" x="0.0" y="0.0" width="356" height="44"/>
@ -550,6 +578,7 @@
<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="56e-ul-z6v" kind="show" identifier="controllerSkinsSegue" id="GNM-Gt-YFf"/>
<segue destination="OwL-4c-EEA" kind="show" identifier="dsSettingsSegue" id="HCa-Ti-ENb"/>
</connections>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="19F-9T-esM" userLabel="First Responder" sceneMemberID="firstResponder"/>
@ -1247,7 +1276,7 @@
<rect key="frame" x="0.0" y="0.0" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" ambiguous="YES" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="K0v-VD-uUj">
<switch opaque="NO" contentMode="scaleToFill" horizontalHuggingPriority="750" verticalHuggingPriority="750" contentHorizontalAlignment="center" contentVerticalAlignment="center" on="YES" translatesAutoresizingMaskIntoConstraints="NO" id="K0v-VD-uUj">
<rect key="frame" x="163" y="6" width="49" height="31"/>
<autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/>
<color key="onTintColor" name="Purple"/>
@ -1661,7 +1690,232 @@ Delta uses OpenVGDB to provide automatic artwork for imported games.</string>
</viewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="DdV-4s-jQT" userLabel="First Responder" sceneMemberID="firstResponder"/>
</objects>
<point key="canvasLocation" x="2513" y="2606"/>
<point key="canvasLocation" x="2513" y="3400"/>
</scene>
<!--DS Settings-->
<scene sceneID="rRC-R2-Ico">
<objects>
<tableViewController storyboardIdentifier="dsSettingsViewController" title="DS Settings" id="OwL-4c-EEA" customClass="MelonDSCoreSettingsViewController" customModule="Delta" customModuleProvider="target" sceneMemberID="viewController">
<tableView key="view" clipsSubviews="YES" contentMode="scaleToFill" alwaysBounceVertical="YES" dataMode="static" style="grouped" separatorStyle="default" rowHeight="44" sectionHeaderHeight="18" sectionFooterHeight="18" id="ops-m1-tlV">
<rect key="frame" x="0.0" y="0.0" width="375" height="667"/>
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
<color key="backgroundColor" cocoaTouchSystemColor="groupTableViewBackgroundColor"/>
<sections>
<tableViewSection headerTitle="Core Info" footerTitle="" id="ozc-x3-LhT">
<cells>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="gray" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="Cell" textLabel="kYg-4f-oTo" detailTextLabel="yak-dZ-uPc" style="IBUITableViewCellStyleValue1" id="pis-Uj-SZd">
<rect key="frame" x="0.0" y="55.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="pis-Uj-SZd" id="yvW-Vf-otU">
<rect key="frame" x="0.0" y="0.0" width="348" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Name" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="kYg-4f-oTo">
<rect key="frame" x="16" y="12" width="45" height="20.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="melonDS" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="yak-dZ-uPc">
<rect key="frame" x="270.5" y="12" width="69.5" height="20.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="0.5" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</tableViewCellContentView>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="gray" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="Cell" textLabel="h6M-Uh-TBA" detailTextLabel="ERw-hy-cF5" style="IBUITableViewCellStyleValue1" id="zQu-CI-OZo">
<rect key="frame" x="0.0" y="99.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="zQu-CI-OZo" id="iOw-oN-hbu">
<rect key="frame" x="0.0" y="0.0" width="348" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Developer" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="h6M-Uh-TBA">
<rect key="frame" x="16" y="12" width="78" height="20.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Arisotura" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="ERw-hy-cF5">
<rect key="frame" x="270" y="12" width="70" height="20.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="0.5" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</tableViewCellContentView>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="gray" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="Cell" textLabel="Uvd-Lt-Ckx" detailTextLabel="kHA-YX-Ah9" style="IBUITableViewCellStyleValue1" id="DkF-3y-vuz">
<rect key="frame" x="0.0" y="143.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="DkF-3y-vuz" id="eKc-NV-XhA">
<rect key="frame" x="0.0" y="0.0" width="348" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Source" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Uvd-Lt-Ckx">
<rect key="frame" x="16" y="12" width="54" height="20.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="GitHub" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="kHA-YX-Ah9">
<rect key="frame" x="286" y="12" width="54" height="20.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="0.5" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</tableViewCellContentView>
</tableViewCell>
<tableViewCell clipsSubviews="YES" contentMode="scaleToFill" selectionStyle="gray" accessoryType="disclosureIndicator" indentationWidth="10" reuseIdentifier="Cell" textLabel="6JV-NA-R4y" detailTextLabel="TXn-bD-NB8" style="IBUITableViewCellStyleValue1" id="IOM-Yq-92K">
<rect key="frame" x="0.0" y="187.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<tableViewCellContentView key="contentView" opaque="NO" clipsSubviews="YES" multipleTouchEnabled="YES" contentMode="center" tableViewCell="IOM-Yq-92K" id="yt9-X5-w9G">
<rect key="frame" x="0.0" y="0.0" width="348" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Donate" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="6JV-NA-R4y">
<rect key="frame" x="16" y="12" width="55.5" height="20.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Patreon" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="TXn-bD-NB8">
<rect key="frame" x="280.5" y="12" width="59.5" height="20.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" white="0.5" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</tableViewCellContentView>
</tableViewCell>
</cells>
</tableViewSection>
<tableViewSection headerTitle="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>
<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="299" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<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="348" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="bios7.bin" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Bfp-iA-wWE">
<rect key="frame" x="16" y="12" width="67" height="20.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Required" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Xpe-sd-GRy">
<rect key="frame" x="271.5" y="12" width="68.5" height="20.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" systemColor="systemRedColor" red="1" green="0.23137254900000001" blue="0.18823529410000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</tableViewCellContentView>
</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">
<rect key="frame" x="0.0" y="343" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<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="348" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="bios9.bin" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="fgD-y0-55T">
<rect key="frame" x="16" y="12" width="70" height="20.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Required" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="b8s-cx-IgW">
<rect key="frame" x="271.5" y="12" width="68.5" height="20.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" systemColor="systemRedColor" red="1" green="0.23137254900000001" blue="0.18823529410000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</tableViewCellContentView>
</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">
<rect key="frame" x="0.0" y="387" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<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="348" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="firmware.bin" textAlignment="natural" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="SIu-zD-qfE">
<rect key="frame" x="16" y="12" width="94.5" height="20.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" cocoaTouchSystemColor="darkTextColor"/>
<nil key="highlightedColor"/>
</label>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" insetsLayoutMarginsFromSafeArea="NO" text="Required" textAlignment="right" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="CW8-h0-YST">
<rect key="frame" x="271.5" y="12" width="68.5" height="20.5"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" systemColor="systemRedColor" red="1" green="0.23137254900000001" blue="0.18823529410000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</tableViewCellContentView>
</tableViewCell>
</cells>
</tableViewSection>
<tableViewSection headerTitle="" footerTitle="Changing cores may improve performance at the cost of additional features." id="hbM-mL-bIr">
<cells>
<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="506.5" width="375" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<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"/>
<autoresizingMask key="autoresizingMask"/>
<subviews>
<label opaque="NO" multipleTouchEnabled="YES" contentMode="left" text="Change Core" textAlignment="center" lineBreakMode="tailTruncation" baselineAdjustment="alignBaselines" adjustsFontSizeToFit="NO" id="Jmx-Jw-278">
<rect key="frame" x="16" y="0.0" width="343" height="44"/>
<autoresizingMask key="autoresizingMask"/>
<fontDescription key="fontDescription" type="system" pointSize="17"/>
<color key="textColor" systemColor="systemRedColor" red="1" green="0.23137254900000001" blue="0.18823529410000001" alpha="1" colorSpace="custom" customColorSpace="sRGB"/>
<nil key="highlightedColor"/>
</label>
</subviews>
</tableViewCellContentView>
</tableViewCell>
</cells>
</tableViewSection>
</sections>
<connections>
<outlet property="dataSource" destination="OwL-4c-EEA" id="b1y-6m-QaJ"/>
<outlet property="delegate" destination="OwL-4c-EEA" id="0J0-nD-H0y"/>
</connections>
</tableView>
<navigationItem key="navigationItem" title="Nintendo DS" id="7dF-4c-IZh">
<barButtonItem key="rightBarButtonItem" style="done" systemItem="done" id="5LJ-CC-74Q">
<connections>
<segue destination="fCP-Vh-l72" kind="unwind" unwindAction="unwindToGameCollectionViewController:" id="o4i-NP-axs"/>
</connections>
</barButtonItem>
</navigationItem>
</tableViewController>
<placeholder placeholderIdentifier="IBFirstResponder" id="Sor-YZ-h3B" userLabel="First Responder" sceneMemberID="firstResponder"/>
<exit id="fCP-Vh-l72" userLabel="Exit" sceneMemberID="exit"/>
</objects>
<point key="canvasLocation" x="2513" y="2680"/>
</scene>
</scenes>
<resources>

View File

@ -11,6 +11,8 @@ import UIKit
import DeltaCore
import GBADeltaCore
import struct DSDeltaCore.DS
import Roxas
private var kvoContext = 0
@ -309,6 +311,19 @@ extension GameViewController
self.updateControllers()
}
override func viewDidAppear(_ animated: Bool)
{
super.viewDidAppear(animated)
if self.emulatorCore?.deltaCore == DS.core, UserDefaults.standard.desmumeDeprecatedAlertCount < 3
{
let toastView = RSTToastView(text: NSLocalizedString("DeSmuME Core Deprecated", comment: ""), detailText: NSLocalizedString("Switch to the melonDS core in Settings for latest improvements.", comment: ""))
self.show(toastView, duration: 5.0)
UserDefaults.standard.desmumeDeprecatedAlertCount += 1
}
}
override func viewWillTransition(to size: CGSize, with coordinator: UIViewControllerTransitionCoordinator)
{
super.viewWillTransition(to: size, with: coordinator)
@ -1023,6 +1038,16 @@ extension GameViewController: GameViewControllerDelegate
}
}
private extension GameViewController
{
func show(_ toastView: RSTToastView, duration: TimeInterval = 3.0)
{
toastView.textLabel.textAlignment = .center
toastView.presentationEdge = .top
toastView.show(in: self.view, duration: duration)
}
}
//MARK: - Notifications -
private extension GameViewController
{
@ -1121,16 +1146,7 @@ private extension GameViewController
func presentToastView()
{
let toastView = RSTToastView(text: NSLocalizedString("Autorotation Disabled", comment: ""), detailText: NSLocalizedString("Pause game to change orientation.", comment: ""))
toastView.textLabel.textAlignment = .center
toastView.presentationEdge = .bottom
if let traits = self.controllerView.controllerSkinTraits, traits.orientation == .landscape, self.controllerView?.controllerSkin?.gameScreenFrame(for: traits) == nil
{
// Only change landscape vertical offset if there is no custom game screen frame for the current controller skin.
toastView.edgeOffset.vertical = 30
}
toastView.show(in: self.gameView, duration: 3.0)
self.show(toastView)
}
DispatchQueue.main.async {
@ -1172,4 +1188,8 @@ private extension GameViewController
}
}
}
private extension UserDefaults
{
@NSManaged var desmumeDeprecatedAlertCount: Int
}

View File

@ -1,26 +0,0 @@
//
// DeltaCoreProtocol+Delta.swift
// Delta
//
// Created by Riley Testut on 4/30/17.
// Copyright © 2017 Riley Testut. All rights reserved.
//
import DeltaCore
extension DeltaCoreProtocol
{
var supportedRates: ClosedRange<Double> {
guard let system = System(gameType: self.gameType) else { return 1...1 }
switch system
{
case .nes: return 1...4
case .snes: return 1...4
case .gbc: return 1...4
case .gba: return 1...3
case .n64: return 1...3
case .ds: return 1...1
}
}
}

View File

@ -11,6 +11,7 @@ import MobileCoreServices
import AVFoundation
import DeltaCore
import MelonDSDeltaCore
import Roxas
import Harmony
@ -23,6 +24,7 @@ extension GameCollectionViewController
{
case alreadyRunning
case downloadingGameSave
case biosNotFound
}
}
@ -328,6 +330,16 @@ private extension GameCollectionViewController
alertController.addAction(.ok)
self.present(alertController, animated: true, completion: nil)
}
catch LaunchError.biosNotFound
{
let alertController = UIAlertController(title: NSLocalizedString("Missing Required DS Files", comment: ""), message: NSLocalizedString("Delta requires certain files to play Nintendo DS games. Please import them to launch this game.", comment: ""), preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: NSLocalizedString("Import Files", comment: ""), style: .default) { _ in
self.performSegue(withIdentifier: "showDSSettings", sender: nil)
})
alertController.addAction(.cancel)
self.present(alertController, animated: true, completion: nil)
}
catch
{
let alertController = UIAlertController(title: NSLocalizedString("Unable to Launch Game", comment: ""), error: error)
@ -378,6 +390,15 @@ private extension GameCollectionViewController
}
}
}
if game.type == .ds && Settings.preferredCore(for: .ds) == MelonDS.core
{
guard
FileManager.default.fileExists(atPath: MelonDSEmulatorBridge.shared.bios7URL.path) &&
FileManager.default.fileExists(atPath: MelonDSEmulatorBridge.shared.bios9URL.path) &&
FileManager.default.fileExists(atPath: MelonDSEmulatorBridge.shared.firmwareURL.path)
else { throw LaunchError.biosNotFound }
}
}
}

View File

@ -75,6 +75,7 @@ class GamesViewController: UIViewController
NotificationCenter.default.addObserver(self, selector: #selector(GamesViewController.syncingDidStart(_:)), name: SyncCoordinator.didStartSyncingNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(GamesViewController.syncingDidFinish(_:)), name: SyncCoordinator.didFinishSyncingNotification, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(GamesViewController.settingsDidChange(_:)), name: .settingsDidChange, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(GamesViewController.emulationDidQuit(_:)), name: EmulatorCore.emulationDidQuitNotification, object: nil)
}
}
@ -529,6 +530,22 @@ private extension GamesViewController
{
self.quitEmulation()
}
@objc func settingsDidChange(_ notification: Notification)
{
guard let emulatorCore = self.activeEmulatorCore else { return }
guard let game = emulatorCore.game as? Game else { return }
game.managedObjectContext?.performAndWait {
guard
let name = notification.userInfo?[Settings.NotificationUserInfoKey.name] as? String, name == Settings.preferredCoreSettingsKey(for: emulatorCore.game.type),
let core = notification.userInfo?[Settings.NotificationUserInfoKey.core] as? DeltaCoreProtocol, core != emulatorCore.deltaCore
else { return }
emulatorCore.stop()
self.quitEmulation()
}
}
}
//MARK: - UIPageViewController -

View File

@ -0,0 +1,362 @@
//
// MelonDSCoreSettingsViewController.swift
// Delta
//
// Created by Riley Testut on 4/13/20.
// Copyright © 2020 Riley Testut. All rights reserved.
//
import UIKit
import SafariServices
import MobileCoreServices
import DeltaCore
import MelonDSDeltaCore
import struct DSDeltaCore.DS
import Roxas
private extension MelonDSCoreSettingsViewController
{
enum Section: Int
{
case general
case bios
case changeCore
}
enum BIOS: Int
{
case bios7
case bios9
case firmware
var fileURL: URL {
switch self
{
case .bios7: return MelonDSEmulatorBridge.shared.bios7URL
case .bios9: return MelonDSEmulatorBridge.shared.bios9URL
case .firmware: return MelonDSEmulatorBridge.shared.firmwareURL
}
}
}
}
class MelonDSCoreSettingsViewController: UITableViewController
{
private var importDestinationURL: URL?
override func viewDidLoad()
{
super.viewDidLoad()
if let navigationController = self.navigationController, navigationController.viewControllers.first != self
{
self.navigationItem.rightBarButtonItem = nil
}
NotificationCenter.default.addObserver(self, selector: #selector(MelonDSCoreSettingsViewController.willEnterForeground(_:)), name: UIApplication.willEnterForegroundNotification, object: nil)
}
override func viewWillAppear(_ animated: Bool)
{
super.viewWillAppear(animated)
self.tableView.reloadData()
}
override func viewDidDisappear(_ animated: Bool)
{
super.viewDidDisappear(animated)
if let core = Delta.registeredCores[.ds]
{
DatabaseManager.shared.performBackgroundTask { (context) in
// Prepare database in case we changed/updated cores.
DatabaseManager.shared.prepare(core, in: context)
context.saveWithErrorLogging()
}
}
}
}
private extension MelonDSCoreSettingsViewController
{
func openMetadataURL(for key: DeltaCoreMetadata.Key)
{
guard let metadata = Settings.preferredCore(for: .ds)?.metadata else { return }
let item = metadata[key]
guard let url = item?.url else {
if let indexPath = self.tableView.indexPathForSelectedRow
{
self.tableView.deselectRow(at: indexPath, animated: true)
}
return
}
let safariViewController = SFSafariViewController(url: url)
safariViewController.preferredControlTintColor = .deltaPurple
self.present(safariViewController, animated: true, completion: nil)
}
func locate(_ bios: BIOS)
{
self.importDestinationURL = bios.fileURL
var supportedTypes = [kUTTypeItem as String, kUTTypeContent as String, "com.apple.macbinary-archive" /* System UTI for .bin */]
// Explicitly support files with .bin and .rom extensions.
if let binTypes = UTTypeCreateAllIdentifiersForTag(kUTTagClassFilenameExtension, "bin" as CFString, nil)?.takeRetainedValue()
{
let types = (binTypes as NSArray).map { $0 as! String }
supportedTypes.append(contentsOf: types)
}
if let romTypes = UTTypeCreateAllIdentifiersForTag(kUTTagClassFilenameExtension, "rom" as CFString, nil)?.takeRetainedValue()
{
let types = (romTypes as NSArray).map { $0 as! String }
supportedTypes.append(contentsOf: types)
}
let documentPicker = UIDocumentPickerViewController(documentTypes: supportedTypes, in: .import)
documentPicker.delegate = self
if #available(iOS 13.0, *)
{
documentPicker.overrideUserInterfaceStyle = .dark
}
self.present(documentPicker, animated: true, completion: nil)
}
func changeCore()
{
let alertController = UIAlertController(title: NSLocalizedString("Change Emulator Core", comment: ""), message: NSLocalizedString("Save states are not compatible between different emulator cores. Make sure to use in-game saves in order to keep using your save data.\n\nYour existing save states will not be deleted and will be available whenever you switch cores again.", comment: ""), preferredStyle: .actionSheet)
var desmumeActionTitle = DS.core.metadata?.name.value ?? DS.core.name
var melonDSActionTitle = MelonDS.core.metadata?.name.value ?? MelonDS.core.name
if Settings.preferredCore(for: .ds) == DS.core
{
desmumeActionTitle += ""
}
else
{
melonDSActionTitle += ""
}
alertController.addAction(UIAlertAction(title: desmumeActionTitle, style: .default, handler: { (action) in
Settings.setPreferredCore(DS.core, for: .ds)
self.tableView.reloadData()
}))
alertController.addAction(UIAlertAction(title: melonDSActionTitle, style: .default, handler: { (action) in
Settings.setPreferredCore(MelonDS.core, for: .ds)
self.tableView.reloadData()
}))
alertController.addAction(.cancel)
self.present(alertController, animated: true, completion: nil)
if let indexPath = self.tableView.indexPathForSelectedRow
{
self.tableView.deselectRow(at: indexPath, animated: true)
}
}
@objc func willEnterForeground(_ notification: Notification)
{
self.tableView.reloadData()
}
}
extension MelonDSCoreSettingsViewController
{
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell = super.tableView(tableView, cellForRowAt: indexPath)
switch Section(rawValue: indexPath.section)!
{
case .general:
let key = DeltaCoreMetadata.Key.allCases[indexPath.row]
let item = Settings.preferredCore(for: .ds)?.metadata?[key]
cell.detailTextLabel?.text = item?.value ?? NSLocalizedString("-", comment: "")
cell.detailTextLabel?.textColor = .gray
if item?.url != nil
{
cell.accessoryType = .disclosureIndicator
cell.selectionStyle = .default
}
else
{
cell.accessoryType = .none
cell.selectionStyle = .none
}
cell.contentView.isHidden = (item == nil)
case .bios:
let bios = BIOS(rawValue: indexPath.row)!
if FileManager.default.fileExists(atPath: bios.fileURL.path)
{
cell.accessoryType = .checkmark
cell.detailTextLabel?.text = nil
cell.detailTextLabel?.textColor = .gray
}
else
{
cell.accessoryType = .disclosureIndicator
cell.detailTextLabel?.text = NSLocalizedString("Required", comment: "")
cell.detailTextLabel?.textColor = .red
}
cell.selectionStyle = .default
case .changeCore: break
}
return cell
}
override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath)
{
guard let core = Settings.preferredCore(for: .ds) else { return }
let key = DeltaCoreMetadata.Key.allCases[indexPath.row]
let lastKey = DeltaCoreMetadata.Key.allCases.reversed().first { core.metadata?[$0] != nil }
if key == lastKey
{
// Hide separator for last visible row in case we've hidden additional rows.
cell.separatorInset.left = 0
}
else
{
cell.separatorInset.left = self.view.layoutMargins.left
}
}
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
switch Section(rawValue: indexPath.section)!
{
case .general:
let key = DeltaCoreMetadata.Key.allCases[indexPath.row]
self.openMetadataURL(for: key)
case .bios:
let bios = BIOS(rawValue: indexPath.row)!
self.locate(bios)
case .changeCore:
self.changeCore()
}
}
override func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String?
{
switch Section(rawValue: section)!
{
case .bios:
guard Settings.preferredCore(for: .ds) == MelonDS.core else { return nil }
default: break
}
return super.tableView(tableView, titleForHeaderInSection: section)
}
override func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String?
{
switch Section(rawValue: section)!
{
case .bios:
guard Settings.preferredCore(for: .ds) == MelonDS.core else { return nil }
default: break
}
return super.tableView(tableView, titleForFooterInSection: section)
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat
{
switch Section(rawValue: indexPath.section)!
{
case .general:
let key = DeltaCoreMetadata.Key.allCases[indexPath.row]
guard Settings.preferredCore(for: .ds)?.metadata?[key] != nil else { return 0 }
case .bios:
guard Settings.preferredCore(for: .ds) == MelonDS.core else { return 0 }
default: break
}
return super.tableView(tableView, heightForRowAt: indexPath)
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat
{
switch Section(rawValue: section)!
{
case .bios:
guard Settings.preferredCore(for: .ds) == MelonDS.core else { return 1 }
default: break
}
return super.tableView(tableView, heightForHeaderInSection: section)
}
override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat
{
switch Section(rawValue: section)!
{
case .bios:
guard Settings.preferredCore(for: .ds) == MelonDS.core else { return 1 }
default: break
}
return super.tableView(tableView, heightForFooterInSection: section)
}
}
extension MelonDSCoreSettingsViewController: UIDocumentPickerDelegate
{
func documentPickerWasCancelled(_ controller: UIDocumentPickerViewController)
{
self.importDestinationURL = nil
self.tableView.reloadData() // Reloading index path causes cell to disappear...
}
func documentPicker(_ controller: UIDocumentPickerViewController, didPickDocumentsAt urls: [URL])
{
defer {
self.importDestinationURL = nil
self.tableView.reloadData() // Reloading index path causes cell to disappear...
}
guard let fileURL = urls.first, let destinationURL = self.importDestinationURL else { return }
do
{
try FileManager.default.copyItem(at: fileURL, to: destinationURL, shouldReplace: true)
}
catch
{
let title = String(format: NSLocalizedString("Could not import %@.", comment: ""), fileURL.lastPathComponent)
let alertController = UIAlertController(title: title, message: error.localizedDescription, preferredStyle: .alert)
alertController.addAction(.ok)
self.present(alertController, animated: true, completion: nil)
}
}
}

View File

@ -10,6 +10,8 @@ import Foundation
import DeltaCore
import struct DSDeltaCore.DS
import Roxas
extension Notification.Name
@ -25,6 +27,8 @@ extension Settings
case system
case traits
case core
}
enum Name: String
@ -55,7 +59,8 @@ struct Settings
#keyPath(UserDefaults.gameShortcutsMode): GameShortcutsMode.recent.rawValue,
#keyPath(UserDefaults.isButtonHapticFeedbackEnabled): true,
#keyPath(UserDefaults.isThumbstickHapticFeedbackEnabled): true,
#keyPath(UserDefaults.sortSaveStatesByOldestFirst): true] as [String : Any]
#keyPath(UserDefaults.sortSaveStatesByOldestFirst): true,
Settings.preferredCoreSettingsKey(for: .ds): DS.core.identifier] as [String : Any]
UserDefaults.standard.register(defaults: defaults)
}
}
@ -177,6 +182,26 @@ extension Settings
}
}
static func preferredCore(for gameType: GameType) -> DeltaCoreProtocol?
{
let key = self.preferredCoreSettingsKey(for: gameType)
let identifier = UserDefaults.standard.string(forKey: key)
let core = System.allCores.first { $0.identifier == identifier }
return core
}
static func setPreferredCore(_ core: DeltaCoreProtocol, for gameType: GameType)
{
Delta.register(core)
let key = self.preferredCoreSettingsKey(for: gameType)
UserDefaults.standard.set(core.identifier, forKey: key)
NotificationCenter.default.post(name: .settingsDidChange, object: nil, userInfo: [NotificationUserInfoKey.name: key, NotificationUserInfoKey.core: core])
}
static func preferredControllerSkin(for system: System, traits: DeltaCore.ControllerSkin.Traits) -> ControllerSkin?
{
guard let userDefaultsKey = self.preferredControllerSkinKey(for: system, traits: traits) else { return nil }
@ -288,6 +313,15 @@ extension Settings
}
}
extension Settings
{
static func preferredCoreSettingsKey(for gameType: GameType) -> String
{
let key = "core." + gameType.rawValue
return key
}
}
private extension Settings
{
static func preferredControllerSkinKey(for system: System, traits: DeltaCore.ControllerSkin.Traits) -> String?

View File

@ -23,6 +23,7 @@ private extension SettingsViewController
case hapticFeedback
case syncing
case threeDTouch
case cores
case patreon
case credits
}
@ -31,6 +32,7 @@ private extension SettingsViewController
{
case controllers = "controllersSegue"
case controllerSkins = "controllerSkinsSegue"
case dsSettings = "dsSettingsSegue"
}
enum SyncingRow: Int, CaseIterable
@ -143,6 +145,8 @@ class SettingsViewController: UITableViewController
let system = System.registeredSystems[indexPath.row]
preferredControllerSkinsViewController.system = system
case Segue.dsSettings: break
}
}
}
@ -341,6 +345,10 @@ extension SettingsViewController
case .service: break
}
case .cores:
let preferredCore = Settings.preferredCore(for: .ds)
cell.detailTextLabel?.text = preferredCore?.metadata?.name.value ?? preferredCore?.name ?? NSLocalizedString("Unknown", comment: "")
case .controllerOpacity, .hapticFeedback, .threeDTouch, .patreon, .credits: break
}
@ -356,6 +364,7 @@ extension SettingsViewController
{
case .controllers: self.performSegue(withIdentifier: Segue.controllers.rawValue, sender: cell)
case .controllerSkins: self.performSegue(withIdentifier: Segue.controllerSkins.rawValue, sender: cell)
case .cores: self.performSegue(withIdentifier: Segue.dsSettings.rawValue, sender: cell)
case .controllerOpacity, .hapticFeedback, .threeDTouch, .syncing: break
case .patreon:
let patreonURL = URL(string: "altstore://patreon")!

View File

@ -0,0 +1,93 @@
//
// DeltaCoreProtocol+Delta.swift
// Delta
//
// Created by Riley Testut on 4/30/17.
// Copyright © 2017 Riley Testut. All rights reserved.
//
import DeltaCore
import NESDeltaCore
import SNESDeltaCore
import GBCDeltaCore
import GBADeltaCore
import N64DeltaCore
import MelonDSDeltaCore
// Legacy Cores
import struct DSDeltaCore.DS
@dynamicMemberLookup
struct DeltaCoreMetadata
{
enum Key: CaseIterable
{
case name
case developer
case source
case donate
}
struct Item
{
var value: String
var url: URL?
}
var name: Item { self.items[.name]! }
private let items: [Key: Item]
init?(_ items: [Key: Item])
{
guard items.keys.contains(.name) else { return nil }
self.items = items
}
subscript(dynamicMember keyPath: KeyPath<Key.Type, Key>) -> Item?
{
let key = Key.self[keyPath: keyPath]
return self[key]
}
subscript(_ key: Key) -> Item?
{
let item = self.items[key]
return item
}
}
extension DeltaCoreProtocol
{
var supportedRates: ClosedRange<Double> {
switch self
{
case NES.core: return 1...4
case SNES.core: return 1...4
case GBC.core: return 1...4
case GBA.core: return 1...3
case N64.core: return 1...3
case DS.core: return 1...3
case MelonDS.core: return 1...2
default: return 1...2
}
}
var metadata: DeltaCoreMetadata? {
switch self
{
case DS.core:
return DeltaCoreMetadata([.name: .init(value: NSLocalizedString("DeSmuME (Legacy)", comment: ""), url: URL(string: "http://desmume.org")),
.developer: .init(value: NSLocalizedString("DeSmuME team", comment: ""), url: URL(string: "https://wiki.desmume.org/index.php?title=DeSmuME:About")),
.source: .init(value: NSLocalizedString("GitHub", comment: ""), url: URL(string: "https://github.com/TASVideos/desmume"))])
case MelonDS.core:
return DeltaCoreMetadata([.name: .init(value: NSLocalizedString("melonDS", comment: ""), url: URL(string: "http://melonds.kuribo64.net")),
.developer: .init(value: NSLocalizedString("Arisotura", comment: ""), url: URL(string: "https://twitter.com/Arisotura")),
.source: .init(value: NSLocalizedString("GitHub", comment: ""), url: URL(string: "https://github.com/Arisotura/melonDS")),
.donate: .init(value: NSLocalizedString("Patreon", comment: ""), url: URL(string: "https://www.patreon.com/staplebutter"))])
default: return nil
}
}
}

View File

@ -15,6 +15,9 @@ import NESDeltaCore
import N64DeltaCore
import MelonDSDeltaCore
// Legacy Cores
import struct DSDeltaCore.DS
enum System: CaseIterable
{
case nes
@ -28,6 +31,10 @@ enum System: CaseIterable
let systems = System.allCases.filter { Delta.registeredCores.keys.contains($0.gameType) }
return systems
}
static var allCores: [DeltaCoreProtocol] {
return [NES.core, SNES.core, N64.core, GBC.core, GBA.core, DS.core, MelonDS.core]
}
}
extension System