v0.9.4: added iOS module!
Note that this commit includes several changes made iteratively over time, from TestFlight 1.0 to 1.5
|
@ -5,6 +5,7 @@ buildscript {
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:4.2.1'
|
classpath 'com.android.tools.build:gradle:4.2.1'
|
||||||
|
classpath 'com.mobidevelop.robovm:robovm-gradle-plugin:2.3.13'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -24,12 +25,14 @@ allprojects {
|
||||||
appAndroidTargetSDK = 30
|
appAndroidTargetSDK = 30
|
||||||
|
|
||||||
gdxVersion = '1.10.0'
|
gdxVersion = '1.10.0'
|
||||||
|
robovmVersion = '2.3.13'
|
||||||
}
|
}
|
||||||
version = appVersionName
|
version = appVersionName
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
google()
|
google()
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
maven { url 'https://oss.sonatype.org/content/repositories/snapshots' }
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
5
ios/.gitignore
vendored
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
#RoboVM build folders
|
||||||
|
robovm-build/
|
||||||
|
|
||||||
|
#RoboVM config (we dynamically generate it)
|
||||||
|
robovm.properties
|
60
ios/Info.plist
Normal file
|
@ -0,0 +1,60 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||||
|
<plist version="1.0">
|
||||||
|
<dict>
|
||||||
|
<key>CFBundleDevelopmentRegion</key>
|
||||||
|
<string>en</string>
|
||||||
|
<key>CFBundleDisplayName</key>
|
||||||
|
<string>${appName}</string>
|
||||||
|
<key>CFBundleExecutable</key>
|
||||||
|
<string>${appExecutable}</string>
|
||||||
|
<key>CFBundleIdentifier</key>
|
||||||
|
<string>${appPackageName}</string>
|
||||||
|
<key>CFBundleInfoDictionaryVersion</key>
|
||||||
|
<string>6.0</string>
|
||||||
|
<key>CFBundleName</key>
|
||||||
|
<string>${appName}</string>
|
||||||
|
<key>CFBundlePackageType</key>
|
||||||
|
<string>APPL</string>
|
||||||
|
<key>CFBundleShortVersionString</key>
|
||||||
|
<string>${appShortVersionName}</string>
|
||||||
|
<key>CFBundleVersionString</key>
|
||||||
|
<string>${appVersionName}</string>
|
||||||
|
<key>CFBundleVersion</key>
|
||||||
|
<string>${appVersionCode}</string>
|
||||||
|
<key>LSRequiresIPhoneOS</key>
|
||||||
|
<true/>
|
||||||
|
<key>UIStatusBarHidden</key>
|
||||||
|
<false/>
|
||||||
|
<key>UIViewControllerBasedStatusBarAppearance</key>
|
||||||
|
<false/>
|
||||||
|
<key>UIStatusBarStyle</key>
|
||||||
|
<string>UIStatusBarStyleLightContent</string>
|
||||||
|
<key>MinimumOSVersion</key>
|
||||||
|
<string>9.0</string>
|
||||||
|
<key>UIDeviceFamily</key>
|
||||||
|
<array>
|
||||||
|
<integer>1</integer>
|
||||||
|
<integer>2</integer>
|
||||||
|
</array>
|
||||||
|
<key>UIRequiredDeviceCapabilities</key>
|
||||||
|
<array>
|
||||||
|
<string>opengles-2</string>
|
||||||
|
</array>
|
||||||
|
<key>UISupportedInterfaceOrientations</key>
|
||||||
|
<array>
|
||||||
|
<string>UIInterfaceOrientationPortrait</string>
|
||||||
|
<string>UIInterfaceOrientationPortraitUpsideDown</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeLeft</string>
|
||||||
|
<string>UIInterfaceOrientationLandscapeRight</string>
|
||||||
|
</array>
|
||||||
|
<key>UILaunchStoryboardName</key>
|
||||||
|
<string>LaunchScreen</string>
|
||||||
|
<key>UIRequiresFullScreen</key>
|
||||||
|
<true/>
|
||||||
|
<key>CFBundleIconName</key>
|
||||||
|
<string>AppIcon</string>
|
||||||
|
<key>ITSAppUsesNonExemptEncryption</key>
|
||||||
|
<false/>
|
||||||
|
</dict>
|
||||||
|
</plist>
|
166
ios/assets/Assets.xcassets/AppIcon.appiconset/Contents.json
Normal file
|
@ -0,0 +1,166 @@
|
||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "Icon-20@2x.png",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "20x20"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Icon-20@3x.png",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"scale" : "3x",
|
||||||
|
"size" : "20x20"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Icon-29@2x.png",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "29x29"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Icon-29@3x.png",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"scale" : "3x",
|
||||||
|
"size" : "29x29"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Icon-40@2x.png",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "40x40"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Icon-40@3x.png",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"scale" : "3x",
|
||||||
|
"size" : "40x40"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Icon-60@2x.png",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "60x60"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Icon-60@3x.png",
|
||||||
|
"idiom" : "iphone",
|
||||||
|
"scale" : "3x",
|
||||||
|
"size" : "60x60"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Icon-20.png",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"scale" : "1x",
|
||||||
|
"size" : "20x20"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Icon-20@2x.png",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "20x20"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Icon-29.png",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"scale" : "1x",
|
||||||
|
"size" : "29x29"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Icon-29@2x.png",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "29x29"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Icon-40.png",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"scale" : "1x",
|
||||||
|
"size" : "40x40"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Icon-40@2x.png",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "40x40"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Icon-76.png",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"scale" : "1x",
|
||||||
|
"size" : "76x76"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Icon-76@2x.png",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "76x76"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Icon-83.5@2x.png",
|
||||||
|
"idiom" : "ipad",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "83.5x83.5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Icon-1024.png",
|
||||||
|
"idiom" : "ios-marketing",
|
||||||
|
"scale" : "1x",
|
||||||
|
"size" : "1024x1024"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "1x",
|
||||||
|
"size" : "16x16"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "16x16"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "1x",
|
||||||
|
"size" : "32x32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "32x32"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "1x",
|
||||||
|
"size" : "128x128"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "128x128"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "1x",
|
||||||
|
"size" : "256x256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "256x256"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "1x",
|
||||||
|
"size" : "512x512"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idiom" : "mac",
|
||||||
|
"scale" : "2x",
|
||||||
|
"size" : "512x512"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
BIN
ios/assets/Assets.xcassets/AppIcon.appiconset/Icon-1024.png
Normal file
After Width: | Height: | Size: 16 KiB |
BIN
ios/assets/Assets.xcassets/AppIcon.appiconset/Icon-20.png
Normal file
After Width: | Height: | Size: 484 B |
BIN
ios/assets/Assets.xcassets/AppIcon.appiconset/Icon-20@2x.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
ios/assets/Assets.xcassets/AppIcon.appiconset/Icon-20@3x.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
ios/assets/Assets.xcassets/AppIcon.appiconset/Icon-29.png
Normal file
After Width: | Height: | Size: 1.1 KiB |
BIN
ios/assets/Assets.xcassets/AppIcon.appiconset/Icon-29@2x.png
Normal file
After Width: | Height: | Size: 2.5 KiB |
BIN
ios/assets/Assets.xcassets/AppIcon.appiconset/Icon-29@3x.png
Normal file
After Width: | Height: | Size: 3.4 KiB |
BIN
ios/assets/Assets.xcassets/AppIcon.appiconset/Icon-40.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
ios/assets/Assets.xcassets/AppIcon.appiconset/Icon-40@2x.png
Normal file
After Width: | Height: | Size: 2.8 KiB |
BIN
ios/assets/Assets.xcassets/AppIcon.appiconset/Icon-40@3x.png
Normal file
After Width: | Height: | Size: 4.0 KiB |
BIN
ios/assets/Assets.xcassets/AppIcon.appiconset/Icon-60@2x.png
Normal file
After Width: | Height: | Size: 4.0 KiB |
BIN
ios/assets/Assets.xcassets/AppIcon.appiconset/Icon-60@3x.png
Normal file
After Width: | Height: | Size: 6.0 KiB |
BIN
ios/assets/Assets.xcassets/AppIcon.appiconset/Icon-76.png
Normal file
After Width: | Height: | Size: 3.0 KiB |
BIN
ios/assets/Assets.xcassets/AppIcon.appiconset/Icon-76@2x.png
Normal file
After Width: | Height: | Size: 2.9 KiB |
BIN
ios/assets/Assets.xcassets/AppIcon.appiconset/Icon-83.5@2x.png
Normal file
After Width: | Height: | Size: 6.1 KiB |
BIN
ios/assets/Assets.xcassets/Banner.imageset/Banner.png
vendored
Normal file
After Width: | Height: | Size: 10 KiB |
BIN
ios/assets/Assets.xcassets/Banner.imageset/Banner@2x.png
vendored
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
ios/assets/Assets.xcassets/Banner.imageset/Banner@3x.png
vendored
Normal file
After Width: | Height: | Size: 17 KiB |
23
ios/assets/Assets.xcassets/Banner.imageset/Contents.json
vendored
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
{
|
||||||
|
"images" : [
|
||||||
|
{
|
||||||
|
"filename" : "Banner.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "1x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Banner@2x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "2x"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"filename" : "Banner@3x.png",
|
||||||
|
"idiom" : "universal",
|
||||||
|
"scale" : "3x"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"info" : {
|
||||||
|
"author" : "xcode",
|
||||||
|
"version" : 1
|
||||||
|
}
|
||||||
|
}
|
38
ios/assets/LaunchScreen.storyboard
Normal file
|
@ -0,0 +1,38 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<document type="com.apple.InterfaceBuilder3.CocoaTouch.Storyboard.XIB" version="3.0" toolsVersion="18122" targetRuntime="iOS.CocoaTouch" propertyAccessControl="none" useAutolayout="YES" launchScreen="YES" useTraitCollections="YES" useSafeAreas="YES" colorMatched="YES" initialViewController="01J-lp-oVM">
|
||||||
|
<device id="retina6_1" orientation="portrait" appearance="light"/>
|
||||||
|
<dependencies>
|
||||||
|
<plugIn identifier="com.apple.InterfaceBuilder.IBCocoaTouchPlugin" version="18093"/>
|
||||||
|
<capability name="Safe area layout guides" minToolsVersion="9.0"/>
|
||||||
|
<capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/>
|
||||||
|
</dependencies>
|
||||||
|
<scenes>
|
||||||
|
<!--View Controller-->
|
||||||
|
<scene sceneID="EHf-IW-A2E">
|
||||||
|
<objects>
|
||||||
|
<viewController id="01J-lp-oVM" sceneMemberID="viewController">
|
||||||
|
<view key="view" contentMode="scaleToFill" id="Ze5-6b-2t3">
|
||||||
|
<rect key="frame" x="0.0" y="0.0" width="450" height="500"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/>
|
||||||
|
<subviews>
|
||||||
|
<imageView clipsSubviews="YES" userInteractionEnabled="NO" contentMode="scaleAspectFit" horizontalHuggingPriority="251" verticalHuggingPriority="251" fixedFrame="YES" image="Banner" translatesAutoresizingMaskIntoConstraints="NO" id="hN2-E0-Tu8">
|
||||||
|
<rect key="frame" x="25" y="0" width="400" height="250"/>
|
||||||
|
<autoresizingMask key="autoresizingMask" flexibleMinX="YES" widthSizable="YES" flexibleMaxX="YES" flexibleMinY="YES" heightSizable="YES" flexibleMaxY="YES"/>
|
||||||
|
</imageView>
|
||||||
|
</subviews>
|
||||||
|
<viewLayoutGuide key="safeArea" id="6Tk-OE-BBY"/>
|
||||||
|
<color key="backgroundColor" white="0" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||||
|
<color key="tintColor" white="1" alpha="1" colorSpace="custom" customColorSpace="genericGamma22GrayColorSpace"/>
|
||||||
|
</view>
|
||||||
|
<extendedEdge key="edgesForExtendedLayout"/>
|
||||||
|
<nil key="simulatedTopBarMetrics"/>
|
||||||
|
</viewController>
|
||||||
|
<placeholder placeholderIdentifier="IBFirstResponder" id="iYj-Kq-Ea1" userLabel="First Responder" sceneMemberID="firstResponder"/>
|
||||||
|
</objects>
|
||||||
|
<point key="canvasLocation" x="52.173913043478265" y="375"/>
|
||||||
|
</scene>
|
||||||
|
</scenes>
|
||||||
|
<resources>
|
||||||
|
<image name="Banner" width="400" height="250"/>
|
||||||
|
</resources>
|
||||||
|
</document>
|
43
ios/build.gradle
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
apply plugin: "java"
|
||||||
|
apply plugin: "robovm"
|
||||||
|
|
||||||
|
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'
|
||||||
|
sourceCompatibility = targetCompatibility = appJavaCompatibility
|
||||||
|
|
||||||
|
task updateRoboVMProps(){
|
||||||
|
def props = new Properties()
|
||||||
|
|
||||||
|
props.setProperty ('appName', appName)
|
||||||
|
//append .apple because com.shatteredpixel.shatteredpixeldungeon was taken =(
|
||||||
|
props.setProperty ('appPackageName', appPackageName + ".apple")
|
||||||
|
|
||||||
|
props.setProperty ('appVersionCode', appVersionCode.toString())
|
||||||
|
props.setProperty ('appVersionName', appVersionName)
|
||||||
|
//parse out just #.#.# from version name, this is an apple requirement
|
||||||
|
props.setProperty ('appShortVersionName', (appVersionName =~ /\d+\.\d+\.\d+/)[0])
|
||||||
|
|
||||||
|
props.setProperty ('appMainclass', "com.shatteredpixel.shatteredpixeldungeon.ios.IOSLauncher")
|
||||||
|
props.setProperty ('appExecutable', "IOSLauncher")
|
||||||
|
|
||||||
|
file("robovm.properties").withWriter { props.store(it, "Dynamically generated, do not commit to version control!") }
|
||||||
|
}
|
||||||
|
|
||||||
|
build.dependsOn updateRoboVMProps
|
||||||
|
|
||||||
|
launchIPhoneSimulator.dependsOn build
|
||||||
|
launchIPadSimulator.dependsOn build
|
||||||
|
launchIOSDevice.dependsOn build
|
||||||
|
createIPA.dependsOn build
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation project(':core')
|
||||||
|
implementation project(':services:updates:debugUpdates')
|
||||||
|
implementation project(':services:news:shatteredNews')
|
||||||
|
|
||||||
|
implementation "com.badlogicgames.gdx:gdx-freetype:$gdxVersion"
|
||||||
|
implementation "com.mobidevelop.robovm:robovm-rt:$robovmVersion"
|
||||||
|
implementation "com.mobidevelop.robovm:robovm-cocoatouch:$robovmVersion"
|
||||||
|
implementation "com.badlogicgames.gdx:gdx-backend-robovm:$gdxVersion"
|
||||||
|
implementation "com.badlogicgames.gdx:gdx-platform:$gdxVersion:natives-ios"
|
||||||
|
implementation "com.badlogicgames.gdx:gdx-freetype-platform:$gdxVersion:natives-ios"
|
||||||
|
}
|
52
ios/robovm.xml
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
<config>
|
||||||
|
<executableName>${appExecutable}</executableName>
|
||||||
|
<mainClass>${appMainclass}</mainClass>
|
||||||
|
<os>ios</os>
|
||||||
|
<arch>thumbv7</arch>
|
||||||
|
<target>ios</target>
|
||||||
|
<iosInfoPList>Info.plist</iosInfoPList>
|
||||||
|
<resources>
|
||||||
|
<resource>
|
||||||
|
<directory>../core/src/main/assets</directory>
|
||||||
|
<includes>
|
||||||
|
<include>**</include>
|
||||||
|
</includes>
|
||||||
|
<skipPngCrush>true</skipPngCrush>
|
||||||
|
</resource>
|
||||||
|
<resource>
|
||||||
|
<directory>../desktop/src/main/assets</directory>
|
||||||
|
<includes>
|
||||||
|
<include>**</include>
|
||||||
|
</includes>
|
||||||
|
<skipPngCrush>true</skipPngCrush>
|
||||||
|
</resource>
|
||||||
|
<resource>
|
||||||
|
<directory>assets</directory>
|
||||||
|
</resource>
|
||||||
|
</resources>
|
||||||
|
<forceLinkClasses>
|
||||||
|
<pattern>com.badlogic.gdx.scenes.scene2d.ui.*</pattern>
|
||||||
|
<pattern>com.badlogic.gdx.graphics.g3d.particles.**</pattern>
|
||||||
|
<pattern>com.android.okhttp.HttpHandler</pattern>
|
||||||
|
<pattern>com.android.okhttp.HttpsHandler</pattern>
|
||||||
|
<pattern>com.android.org.conscrypt.**</pattern>
|
||||||
|
<pattern>com.android.org.bouncycastle.jce.provider.BouncyCastleProvider</pattern>
|
||||||
|
<pattern>com.android.org.bouncycastle.jcajce.provider.keystore.BC$Mappings</pattern>
|
||||||
|
<pattern>com.android.org.bouncycastle.jcajce.provider.keystore.bc.BcKeyStoreSpi</pattern>
|
||||||
|
<pattern>com.android.org.bouncycastle.jcajce.provider.keystore.bc.BcKeyStoreSpi$Std</pattern>
|
||||||
|
<pattern>com.android.org.bouncycastle.jce.provider.PKIXCertPathValidatorSpi</pattern>
|
||||||
|
<pattern>com.android.org.bouncycastle.crypto.digests.AndroidDigestFactoryOpenSSL</pattern>
|
||||||
|
<pattern>org.apache.harmony.security.provider.cert.DRLCertFactory</pattern>
|
||||||
|
<pattern>org.apache.harmony.security.provider.crypto.CryptoProvider</pattern>
|
||||||
|
</forceLinkClasses>
|
||||||
|
<frameworks>
|
||||||
|
<framework>UIKit</framework>
|
||||||
|
<framework>OpenGLES</framework>
|
||||||
|
<framework>QuartzCore</framework>
|
||||||
|
<framework>CoreGraphics</framework>
|
||||||
|
<framework>OpenAL</framework>
|
||||||
|
<framework>AudioToolbox</framework>
|
||||||
|
<framework>AVFoundation</framework>
|
||||||
|
<framework>GameController</framework>
|
||||||
|
</frameworks>
|
||||||
|
</config>
|
|
@ -0,0 +1,103 @@
|
||||||
|
package com.shatteredpixel.shatteredpixeldungeon.ios;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.Files;
|
||||||
|
import com.badlogic.gdx.backends.iosrobovm.IOSApplication;
|
||||||
|
import com.badlogic.gdx.backends.iosrobovm.IOSApplicationConfiguration;
|
||||||
|
import com.badlogic.gdx.graphics.glutils.HdpiMode;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.services.news.News;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.services.news.NewsImpl;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.services.updates.UpdateImpl;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.services.updates.Updates;
|
||||||
|
import com.watabou.noosa.Game;
|
||||||
|
import com.watabou.utils.FileUtils;
|
||||||
|
|
||||||
|
import org.robovm.apple.coregraphics.CGRect;
|
||||||
|
import org.robovm.apple.foundation.NSAutoreleasePool;
|
||||||
|
import org.robovm.apple.foundation.NSBundle;
|
||||||
|
import org.robovm.apple.foundation.NSDictionary;
|
||||||
|
import org.robovm.apple.foundation.NSException;
|
||||||
|
import org.robovm.apple.glkit.GLKViewDrawableColorFormat;
|
||||||
|
import org.robovm.apple.glkit.GLKViewDrawableDepthFormat;
|
||||||
|
import org.robovm.apple.uikit.UIApplication;
|
||||||
|
|
||||||
|
public class IOSLauncher extends IOSApplication.Delegate {
|
||||||
|
@Override
|
||||||
|
protected IOSApplication createApplication() {
|
||||||
|
|
||||||
|
//ensures the app actually crashes if there's an error in the mobiVM runtime
|
||||||
|
Thread.setDefaultUncaughtExceptionHandler(new Thread.UncaughtExceptionHandler() {
|
||||||
|
public void uncaughtException(Thread thread, Throwable ex) {
|
||||||
|
new NSException(ex.getClass().getName(), ex.getMessage(), new NSDictionary()).raise();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
try {
|
||||||
|
Game.version = NSBundle.getMainBundle().getInfoDictionaryObject("CFBundleVersionString").toString();
|
||||||
|
} catch (Exception e) {
|
||||||
|
Game.version = "???";
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
Game.versionCode = Integer.parseInt(NSBundle.getMainBundle().getInfoDictionaryObject("CFBundleVersion").toString());
|
||||||
|
} catch (Exception e) {
|
||||||
|
Game.versionCode = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (UpdateImpl.supportsUpdates()) {
|
||||||
|
Updates.service = UpdateImpl.getUpdateService();
|
||||||
|
}
|
||||||
|
if (NewsImpl.supportsNews()) {
|
||||||
|
News.service = NewsImpl.getNewsService();
|
||||||
|
}
|
||||||
|
|
||||||
|
FileUtils.setDefaultFileProperties(Files.FileType.Local, "");
|
||||||
|
|
||||||
|
IOSApplicationConfiguration config = new IOSApplicationConfiguration();
|
||||||
|
|
||||||
|
config.colorFormat = GLKViewDrawableColorFormat.RGBA8888;
|
||||||
|
config.depthFormat = GLKViewDrawableDepthFormat.None;
|
||||||
|
config.hdpiMode = HdpiMode.Pixels;
|
||||||
|
|
||||||
|
CGRect statusBarFrame = UIApplication.getSharedApplication().getStatusBarFrame();
|
||||||
|
double statusBarHeight = Math.min(statusBarFrame.getWidth(), statusBarFrame.getHeight());
|
||||||
|
|
||||||
|
//if the application has a short status bar (no notch), then hide it
|
||||||
|
//TODO we do this check elsewhere now, can this be removed?
|
||||||
|
if (statusBarHeight <= 24) {
|
||||||
|
UIApplication.getSharedApplication().setStatusBarHidden(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
config.useAccelerometer = false;
|
||||||
|
config.useCompass = false;
|
||||||
|
|
||||||
|
//devices not currently listed in LibGDX's IOSDevice class
|
||||||
|
config.addIosDevice("IPHONE_12_MINI", "iPhone13,1", 476);
|
||||||
|
config.addIosDevice("IPHONE_12", "iPhone13,2", 460);
|
||||||
|
config.addIosDevice("IPHONE_12_PRO", "iPhone13,3", 460);
|
||||||
|
config.addIosDevice("IPHONE_12_PRO_MAX", "iPhone13,4", 458);
|
||||||
|
|
||||||
|
config.addIosDevice("IPAD_7G_WIFI", "iPad7,11", 264);
|
||||||
|
config.addIosDevice("IPAD_7G_WIFI_CELLULAR", "iPad7,12", 264);
|
||||||
|
|
||||||
|
config.addIosDevice("IPAD_8G_WIFI", "iPad11,6", 264);
|
||||||
|
config.addIosDevice("IPAD_8G_WIFI_CELLULAR", "iPad11,7", 264);
|
||||||
|
config.addIosDevice("IPAD_AIR_4G_WIFI", "iPad13,1", 264);
|
||||||
|
config.addIosDevice("IPAD_AIR_4G_WIFI_CELLULAR", "iPad13,2", 264);
|
||||||
|
config.addIosDevice("IPAD_PRO_11_3G", "iPad13,4", 264);
|
||||||
|
config.addIosDevice("IPAD_PRO_11_3G", "iPad13,5", 264);
|
||||||
|
config.addIosDevice("IPAD_PRO_11_3G", "iPad13,6", 264);
|
||||||
|
config.addIosDevice("IPAD_PRO_11_3G", "iPad13,7", 264);
|
||||||
|
config.addIosDevice("IPAD_PRO_12.8_5G", "iPad13,8", 264);
|
||||||
|
config.addIosDevice("IPAD_PRO_12.8_5G", "iPad13,9", 264);
|
||||||
|
config.addIosDevice("IPAD_PRO_12.8_5G", "iPad13,10", 264);
|
||||||
|
config.addIosDevice("IPAD_PRO_12.8_5G", "iPad13,11", 264);
|
||||||
|
|
||||||
|
return new IOSApplication(new ShatteredPixelDungeon(new IOSPlatformSupport()), config);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void main(String[] argv) {
|
||||||
|
NSAutoreleasePool pool = new NSAutoreleasePool();
|
||||||
|
UIApplication.main(argv, null, IOSLauncher.class);
|
||||||
|
pool.close();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,235 @@
|
||||||
|
package com.shatteredpixel.shatteredpixeldungeon.ios;
|
||||||
|
|
||||||
|
import com.badlogic.gdx.Gdx;
|
||||||
|
import com.badlogic.gdx.backends.iosrobovm.IOSGraphics;
|
||||||
|
import com.badlogic.gdx.graphics.Pixmap;
|
||||||
|
import com.badlogic.gdx.graphics.Texture;
|
||||||
|
import com.badlogic.gdx.graphics.g2d.BitmapFont;
|
||||||
|
import com.badlogic.gdx.graphics.g2d.PixmapPacker;
|
||||||
|
import com.badlogic.gdx.graphics.g2d.freetype.FreeTypeFontGenerator;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.SPDSettings;
|
||||||
|
import com.shatteredpixel.shatteredpixeldungeon.ShatteredPixelDungeon;
|
||||||
|
import com.watabou.noosa.Game;
|
||||||
|
import com.watabou.utils.PlatformSupport;
|
||||||
|
|
||||||
|
import org.robovm.apple.audiotoolbox.AudioServices;
|
||||||
|
import org.robovm.apple.systemconfiguration.SCNetworkReachability;
|
||||||
|
import org.robovm.apple.systemconfiguration.SCNetworkReachabilityFlags;
|
||||||
|
import org.robovm.apple.uikit.UIApplication;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.regex.Pattern;
|
||||||
|
|
||||||
|
public class IOSPlatformSupport extends PlatformSupport {
|
||||||
|
@Override
|
||||||
|
public void updateDisplaySize() {
|
||||||
|
//non-zero safe insets on left/top/right means device has a notch, show status bar
|
||||||
|
if (Gdx.graphics.getSafeInsetTop() != 0
|
||||||
|
|| Gdx.graphics.getSafeInsetLeft() != 0
|
||||||
|
|| Gdx.graphics.getSafeInsetRight() != 0){
|
||||||
|
UIApplication.getSharedApplication().setStatusBarHidden(false);
|
||||||
|
} else {
|
||||||
|
UIApplication.getSharedApplication().setStatusBarHidden(true);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SPDSettings.fullscreen()) {
|
||||||
|
Game.bottomInset = Gdx.graphics.getSafeInsetBottom();
|
||||||
|
Game.height -= Game.bottomInset;
|
||||||
|
Game.dispHeight = Game.height;
|
||||||
|
} else {
|
||||||
|
Game.height += Game.bottomInset;
|
||||||
|
Game.dispHeight = Game.height;
|
||||||
|
Game.bottomInset = 0;
|
||||||
|
}
|
||||||
|
Gdx.gl.glViewport(0, Game.bottomInset, Game.width, Game.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void updateSystemUI() {
|
||||||
|
updateDisplaySize();
|
||||||
|
ShatteredPixelDungeon.seamlessResetScene();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean connectedToUnmeteredNetwork() {
|
||||||
|
SCNetworkReachability test = new SCNetworkReachability("www.apple.com");
|
||||||
|
return !test.getFlags().contains(SCNetworkReachabilityFlags.IsWWAN);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void promptTextInput(String title, String hintText, int maxLen, boolean multiLine, String posTxt, String negTxt, TextCallback callback) {
|
||||||
|
//TODO need multiplat text input, this does nothing atm!
|
||||||
|
}
|
||||||
|
|
||||||
|
public void vibrate( int millis ){
|
||||||
|
//gives a short vibrate on iPhone 6+, no vibration otherwise
|
||||||
|
AudioServices.playSystemSound(1520);
|
||||||
|
}
|
||||||
|
|
||||||
|
private int pageSize;
|
||||||
|
private PixmapPacker packer;
|
||||||
|
private boolean systemfont;
|
||||||
|
|
||||||
|
//custom pixel font, for use with Latin and Cyrillic languages
|
||||||
|
private static FreeTypeFontGenerator basicFontGenerator;
|
||||||
|
private static HashMap<Integer, BitmapFont> basicFonts = new HashMap<>();
|
||||||
|
|
||||||
|
//droid sans fallback, for asian fonts
|
||||||
|
private static FreeTypeFontGenerator asianFontGenerator;
|
||||||
|
private static HashMap<Integer, BitmapFont> asianFonts = new HashMap<>();
|
||||||
|
|
||||||
|
private static HashMap<FreeTypeFontGenerator, HashMap<Integer, BitmapFont>> fonts;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void setupFontGenerators(int pageSize, boolean systemfont) {
|
||||||
|
//don't bother doing anything if nothing has changed
|
||||||
|
if (fonts != null && this.pageSize == pageSize && this.systemfont == systemfont){
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.pageSize = pageSize;
|
||||||
|
this.systemfont = systemfont;
|
||||||
|
|
||||||
|
if (fonts != null){
|
||||||
|
for (FreeTypeFontGenerator generator : fonts.keySet()){
|
||||||
|
for (BitmapFont f : fonts.get(generator).values()){
|
||||||
|
f.dispose();
|
||||||
|
}
|
||||||
|
fonts.get(generator).clear();
|
||||||
|
generator.dispose();
|
||||||
|
}
|
||||||
|
fonts.clear();
|
||||||
|
if (packer != null){
|
||||||
|
for (PixmapPacker.Page p : packer.getPages()){
|
||||||
|
p.getTexture().dispose();
|
||||||
|
}
|
||||||
|
packer.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fonts = new HashMap<>();
|
||||||
|
|
||||||
|
if (systemfont) {
|
||||||
|
basicFontGenerator = asianFontGenerator = new FreeTypeFontGenerator(Gdx.files.internal("fonts/droid_sans.ttf"));
|
||||||
|
} else {
|
||||||
|
basicFontGenerator = new FreeTypeFontGenerator(Gdx.files.internal("fonts/pixel_font.ttf"));
|
||||||
|
asianFontGenerator = new FreeTypeFontGenerator(Gdx.files.internal("fonts/droid_sans.ttf"));
|
||||||
|
}
|
||||||
|
|
||||||
|
fonts.put(basicFontGenerator, basicFonts);
|
||||||
|
fonts.put(asianFontGenerator, asianFonts);
|
||||||
|
|
||||||
|
packer = new PixmapPacker(pageSize, pageSize, Pixmap.Format.RGBA8888, 1, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void resetGenerators() {
|
||||||
|
if (fonts != null) {
|
||||||
|
for (FreeTypeFontGenerator generator : fonts.keySet()) {
|
||||||
|
for (BitmapFont f : fonts.get(generator).values()) {
|
||||||
|
f.dispose();
|
||||||
|
}
|
||||||
|
fonts.get(generator).clear();
|
||||||
|
generator.dispose();
|
||||||
|
}
|
||||||
|
fonts.clear();
|
||||||
|
if (packer != null) {
|
||||||
|
for (PixmapPacker.Page p : packer.getPages()) {
|
||||||
|
p.getTexture().dispose();
|
||||||
|
}
|
||||||
|
packer.dispose();
|
||||||
|
}
|
||||||
|
fonts = null;
|
||||||
|
}
|
||||||
|
setupFontGenerators(pageSize, systemfont);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void reloadGenerators() {
|
||||||
|
if (packer != null) {
|
||||||
|
for (PixmapPacker.Page p : packer.getPages()) {
|
||||||
|
p.getTexture().dispose();
|
||||||
|
p.updateTexture(Texture.TextureFilter.Nearest, Texture.TextureFilter.Nearest, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Pattern asianMatcher = Pattern.compile("\\p{InHangul_Syllables}|" +
|
||||||
|
"\\p{InCJK_Unified_Ideographs}|\\p{InCJK_Symbols_and_Punctuation}|\\p{InHalfwidth_and_Fullwidth_Forms}|" +
|
||||||
|
"\\p{InHiragana}|\\p{InKatakana}");
|
||||||
|
|
||||||
|
private static FreeTypeFontGenerator getGeneratorForString( String input ){
|
||||||
|
if (asianMatcher.matcher(input).find()){
|
||||||
|
return asianFontGenerator;
|
||||||
|
} else {
|
||||||
|
return basicFontGenerator;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public BitmapFont getFont(int size, String text) {
|
||||||
|
FreeTypeFontGenerator generator = getGeneratorForString(text);
|
||||||
|
|
||||||
|
if (generator == null){
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!fonts.get(generator).containsKey(size)) {
|
||||||
|
FreeTypeFontGenerator.FreeTypeFontParameter parameters = new FreeTypeFontGenerator.FreeTypeFontParameter();
|
||||||
|
parameters.size = size;
|
||||||
|
parameters.flip = true;
|
||||||
|
parameters.borderWidth = parameters.size / 10f;
|
||||||
|
if (size >= 20){
|
||||||
|
parameters.renderCount = 2;
|
||||||
|
} else {
|
||||||
|
parameters.renderCount = 3;
|
||||||
|
}
|
||||||
|
parameters.hinting = FreeTypeFontGenerator.Hinting.None;
|
||||||
|
parameters.spaceX = -(int) parameters.borderWidth;
|
||||||
|
parameters.incremental = true;
|
||||||
|
if (generator == basicFontGenerator){
|
||||||
|
//if we're using latin/cyrillic, we can safely pre-generate some common letters
|
||||||
|
//(we define common as >4% frequency in english)
|
||||||
|
parameters.characters = "<EFBFBD>etaoinshrdl";
|
||||||
|
} else {
|
||||||
|
parameters.characters = "<EFBFBD>";
|
||||||
|
}
|
||||||
|
parameters.packer = packer;
|
||||||
|
|
||||||
|
try {
|
||||||
|
BitmapFont font = generator.generateFont(parameters);
|
||||||
|
font.getData().missingGlyph = font.getData().getGlyph('<27>');
|
||||||
|
fonts.get(generator).put(size, font);
|
||||||
|
} catch ( Exception e ){
|
||||||
|
Game.reportException(e);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fonts.get(generator).get(size);
|
||||||
|
}
|
||||||
|
|
||||||
|
//splits on newlines, underscores, and chinese/japaneses characters
|
||||||
|
private Pattern regularsplitter = Pattern.compile(
|
||||||
|
"(?<=\n)|(?=\n)|(?<=_)|(?=_)|" +
|
||||||
|
"(?<=\\p{InHiragana})|(?=\\p{InHiragana})|" +
|
||||||
|
"(?<=\\p{InKatakana})|(?=\\p{InKatakana})|" +
|
||||||
|
"(?<=\\p{InCJK_Unified_Ideographs})|(?=\\p{InCJK_Unified_Ideographs})|" +
|
||||||
|
"(?<=\\p{InCJK_Symbols_and_Punctuation})|(?=\\p{InCJK_Symbols_and_Punctuation})");
|
||||||
|
|
||||||
|
//additionally splits on words, so that each word can be arranged individually
|
||||||
|
private Pattern regularsplitterMultiline = Pattern.compile(
|
||||||
|
"(?<= )|(?= )|(?<=\n)|(?=\n)|(?<=_)|(?=_)|" +
|
||||||
|
"(?<=\\p{InHiragana})|(?=\\p{InHiragana})|" +
|
||||||
|
"(?<=\\p{InKatakana})|(?=\\p{InKatakana})|" +
|
||||||
|
"(?<=\\p{InCJK_Unified_Ideographs})|(?=\\p{InCJK_Unified_Ideographs})|" +
|
||||||
|
"(?<=\\p{InCJK_Symbols_and_Punctuation})|(?=\\p{InCJK_Symbols_and_Punctuation})");
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String[] splitforTextBlock(String text, boolean multiline) {
|
||||||
|
if (multiline) {
|
||||||
|
return regularsplitterMultiline.split(text);
|
||||||
|
} else {
|
||||||
|
return regularsplitter.split(text);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,3 +1,3 @@
|
||||||
include ':core', ':SPD-classes', ':android', ':desktop', ':services',
|
include ':core', ':SPD-classes', ':android', ':ios', ':desktop', ':services',
|
||||||
':services:updates:debugUpdates', ':services:updates:githubUpdates',
|
':services:updates:debugUpdates', ':services:updates:githubUpdates',
|
||||||
':services:news:debugNews', ':services:news:shatteredNews'
|
':services:news:debugNews', ':services:news:shatteredNews'
|