Add Android project

This commit is contained in:
Marijn van der Werf 2017-06-15 14:22:15 +02:00
parent 5f5f12a63c
commit 8766ec37a1
47 changed files with 3361 additions and 9 deletions

3
.gitignore vendored
View File

@ -1,12 +1,13 @@
# OPENRCT2
sdl
/sdl
# Compiled dll
openrct2.dll
# Distribution
distribution/windows/*.exe
distribution/android/*/external/
# Build artifacts
artifacts

View File

@ -86,6 +86,42 @@ matrix:
curl -o - -v --form "key=$OPENRCT2_ORG_TOKEN" --form "fileName=OpenRCT2-${OPENRCT2_VERSION}${FILENAME_PART}-macos.zip" --form "version=${OPENRCT2_VERSION}" --form "gitHash=$TRAVIS_COMMIT" --form "gitBranch=$PUSH_BRANCH" --form "flavourId=3" --form "file=@openrct2-macos.zip" "https://openrct2.org/altapi/?command=push-build"; else
curl --progress-bar --upload-file openrct2-macos.zip https://transfer.sh/openrct2-macos.zip -o link && cat link;
fi
- os: linux
language: android
dist: precise
before_install: []
addons:
apt:
sources:
- ubuntu-toolchain-r-test
packages:
- libstdc++6-4.7-dev
android:
components:
- build-tools-25.0.2
jdk: oraclejdk8
before_script:
- pushd ~
- wget https://dl.google.com/android/repository/sdk-tools-linux-3859397.zip
- unzip -qo sdk-tools-linux-3859397.zip
- rm -Rf "$ANDROID_HOME/tools"
- mv tools "$ANDROID_HOME/tools"
- popd
- 'echo "count=0" > ~/.android/repositories.cfg'
- '"$ANDROID_HOME/tools/bin/sdkmanager" --list'
- 'echo y | "$ANDROID_HOME/tools/bin/sdkmanager" platform-tools'
- 'echo y | "$ANDROID_HOME/tools/bin/sdkmanager" "platforms;android-25"'
- 'echo y | "$ANDROID_HOME/tools/bin/sdkmanager" "cmake;3.6.3155560"'
- '"$ANDROID_HOME/tools/bin/sdkmanager" ndk-bundle'
- '"$ANDROID_HOME/tools/bin/sdkmanager" --list'
- 'export ANDROID_NDK_HOME="$ANDROID_HOME/ndk-bundle"'
- 'cd src/openrct2-android'
- TERM=dumb # Makes Gradle use 'boring' output
script:
- './gradlew app:assemblePR'
after_success:
- curl --progress-bar --upload-file app/build/outputs/apk/app-arm-pr.apk https://transfer.sh/openrct2-android-arm.apk -o link && cat link
- curl --progress-bar --upload-file app/build/outputs/apk/app-x86-pr.apk https://transfer.sh/openrct2-android-x86.apk -o link && cat link
# Following entries used to be included in testing, but they only proved useful while changing things in CMake setup.
# They are meant to be used when there are changes to CMakeLists.txt
# - os: linux

39
src/openrct2-android/.gitignore vendored Normal file
View File

@ -0,0 +1,39 @@
# Built application files
*.apk
*.ap_
# Files for the Dalvik VM
*.dex
# Java class files
*.class
# Generated files
bin/
gen/
out/
# Gradle files
.gradle/
build/
# Local configuration file (sdk path, etc)
local.properties
# Proguard folder generated by Eclipse
proguard/
# Log Files
*.log
# Android Studio Navigation editor temp files
.navigation/
# Android Studio captures folder
captures/
# Intellij
*.iml
# Keystore files
*.jks

View File

@ -0,0 +1,102 @@
apply plugin: 'com.android.application'
android {
compileSdkVersion 25
buildToolsVersion '25.0.2'
defaultConfig {
applicationId 'website.openrct2'
minSdkVersion 16
targetSdkVersion 25
versionCode 2
versionName '0.0.8'
externalNativeBuild {
cmake {
arguments '-DANDROID_STL=c++_shared'
targets 'openrct2', 'openrct2-ui'
}
}
}
signingConfigs {
debug {
storeFile file('external/debug.keystore')
}
}
buildTypes {
debug {
applicationIdSuffix '.debug'
versionNameSuffix '-DEBUG'
}
pr {
applicationIdSuffix '.debug'
signingConfig signingConfigs.debug
}
develop {
applicationIdSuffix '.develop'
versionNameSuffix '-DEVELOP'
signingConfig signingConfigs.debug
}
release {
signingConfig signingConfigs.debug
}
}
externalNativeBuild {
cmake {
path 'src/main/CMakeLists.txt'
}
}
productFlavors {
arm7 {
ndk {
abiFilters 'armeabi-v7a'
}
}
arm {
ndk {
abiFilters 'armeabi-v7a', 'arm64-v8a'
}
}
x86 {
ndk {
abiFilters 'x86', 'x86_64'
}
}
}
}
apply plugin: 'de.undercouch.download'
android.applicationVariants.all { variant ->
variant.mergeAssets.doLast {
copy {
from '../../../data'
into "$variant.mergeAssets.outputDir/data"
}
download {
src 'https://github.com/marijnvdwerf/openrct2-dependencies-android/releases/download/v0.7/g2.dat'
dest "$variant.mergeAssets.outputDir/data"
}
download {
src 'https://github.com/OpenRCT2/title-sequences/releases/download/v0.0.5/title-sequence-v0.0.5.zip'
dest new File(buildDir, 'title-sequence.zip')
}
copy {
from zipTree(new File(buildDir, 'title-sequence.zip'))
into "$variant.mergeAssets.outputDir/data/title"
}
}
}
dependencies {
compile 'commons-io:commons-io:2.5'
compile 'com.android.support:appcompat-v7:25.3.1'
compile 'com.google.android.gms:play-services-analytics:10.2.1'
}
apply plugin: 'com.google.gms.google-services'

Binary file not shown.

View File

@ -0,0 +1,96 @@
{
"project_info": {
"project_number": "",
"project_id": ""
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "",
"android_client_info": {
"package_name": "website.openrct2.debug"
}
},
"oauth_client": [],
"api_key": [
{
"current_key": ""
}
],
"services": {
"analytics_service": {
"status": 2,
"analytics_property": {
"tracking_id": "UA-XXXXXXXX-1"
}
},
"appinvite_service": {
"status": 1,
"other_platform_oauth_client": []
},
"ads_service": {
"status": 1
}
}
},
{
"client_info": {
"mobilesdk_app_id": "",
"android_client_info": {
"package_name": "website.openrct2.develop"
}
},
"oauth_client": [],
"api_key": [
{
"current_key": ""
}
],
"services": {
"analytics_service": {
"status": 2,
"analytics_property": {
"tracking_id": "UA-XXXXXXXX-1"
}
},
"appinvite_service": {
"status": 1,
"other_platform_oauth_client": []
},
"ads_service": {
"status": 1
}
}
},
{
"client_info": {
"mobilesdk_app_id": "",
"android_client_info": {
"package_name": "website.openrct2"
}
},
"oauth_client": [],
"api_key": [
{
"current_key": ""
}
],
"services": {
"analytics_service": {
"status": 2,
"analytics_property": {
"tracking_id": "UA-XXXXXXXX-1"
}
},
"appinvite_service": {
"status": 1,
"other_platform_oauth_client": []
},
"ads_service": {
"status": 1
}
}
}
],
"configuration_version": "1"
}

View File

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="website.openrct2">
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<application
android:name=".OpenRCT2App"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:largeHeap="true"
android:theme="@style/AppTheme.Splash">
<activity
android:name=".MainActivity"
android:theme="@style/AppTheme.Splash">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".GameActivity"
android:configChanges="keyboardHidden|orientation|screenSize">
</activity>
</application>
</manifest>

View File

@ -0,0 +1,123 @@
cmake_minimum_required(VERSION 3.6.0)
set(CMAKE_VERBOSE_MAKEFILE on)
set(lib_src_DIR ${CMAKE_SOURCE_DIR}/../../../libs)
set(lib_build_DIR $ENV{HOME}/tmp)
file(MAKE_DIRECTORY ${lib_build_DIR})
set(DEBUG_LEVEL 0 CACHE STRING "Select debug level for compilation. Use value in range 03.")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DDEBUG=${DEBUG_LEVEL}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DDEBUG=${DEBUG_LEVEL}")
include(ExternalProject)
ExternalProject_Add(libs
URL https://github.com/marijnvdwerf/openrct2-dependencies-android/releases/download/v0.7/openrct2-libs-android-${ANDROID_ABI}.zip
SOURCE_DIR "${CMAKE_BINARY_DIR}/libs"
CONFIGURE_COMMAND ""
BUILD_COMMAND ""
INSTALL_COMMAND ""
BUILD_BYPRODUCTS
${CMAKE_BINARY_DIR}/libs/lib/${CMAKE_SHARED_LIBRARY_PREFIX}freetype${CMAKE_SHARED_LIBRARY_SUFFIX}
${CMAKE_BINARY_DIR}/libs/lib/${CMAKE_SHARED_LIBRARY_PREFIX}jansson${CMAKE_SHARED_LIBRARY_SUFFIX}
${CMAKE_BINARY_DIR}/libs/lib/${CMAKE_SHARED_LIBRARY_PREFIX}png16${CMAKE_SHARED_LIBRARY_SUFFIX}
${CMAKE_BINARY_DIR}/libs/lib/${CMAKE_SHARED_LIBRARY_PREFIX}SDL2-2.0${CMAKE_SHARED_LIBRARY_SUFFIX}
${CMAKE_BINARY_DIR}/libs/lib/${CMAKE_STATIC_LIBRARY_PREFIX}SDL2main${CMAKE_STATIC_LIBRARY_SUFFIX}
${CMAKE_BINARY_DIR}/libs/lib/${CMAKE_SHARED_LIBRARY_PREFIX}speexdsp${CMAKE_SHARED_LIBRARY_SUFFIX}
LOG_DOWNLOAD 1
LOG_UPDATE 1
LOG_CONFIGURE 1
LOG_BUILD 1
LOG_TEST 1
LOG_INSTALL 1
)
add_custom_command(TARGET libs POST_BUILD
COMMAND ${CMAKE_COMMAND} -E make_directory ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}
COMMAND ${CMAKE_COMMAND} -E copy "${CMAKE_BINARY_DIR}/libs/lib/*.so" ${CMAKE_LIBRARY_OUTPUT_DIRECTORY}
)
add_library(freetype SHARED IMPORTED)
set_target_properties(freetype PROPERTIES IMPORTED_LOCATION
${CMAKE_BINARY_DIR}/libs/lib/${CMAKE_SHARED_LIBRARY_PREFIX}freetype${CMAKE_SHARED_LIBRARY_SUFFIX}
)
add_dependencies(freetype libs)
add_library(jansson SHARED IMPORTED)
set_target_properties(jansson PROPERTIES IMPORTED_LOCATION
${CMAKE_BINARY_DIR}/libs/lib/${CMAKE_SHARED_LIBRARY_PREFIX}jansson${CMAKE_SHARED_LIBRARY_SUFFIX}
)
add_dependencies(jansson libs)
add_library(png SHARED IMPORTED)
set_target_properties(png PROPERTIES IMPORTED_LOCATION
${CMAKE_BINARY_DIR}/libs/lib/${CMAKE_SHARED_LIBRARY_PREFIX}png16${CMAKE_SHARED_LIBRARY_SUFFIX}
)
add_dependencies(png libs)
add_library(SDL2 SHARED IMPORTED)
set_target_properties(SDL2 PROPERTIES IMPORTED_LOCATION
${CMAKE_BINARY_DIR}/libs/lib/${CMAKE_SHARED_LIBRARY_PREFIX}SDL2-2.0${CMAKE_SHARED_LIBRARY_SUFFIX}
)
add_dependencies(SDL2 libs)
add_library(SDL2main STATIC IMPORTED)
set_target_properties(SDL2main PROPERTIES IMPORTED_LOCATION
${CMAKE_BINARY_DIR}/libs/lib/${CMAKE_STATIC_LIBRARY_PREFIX}SDL2main${CMAKE_STATIC_LIBRARY_SUFFIX}
)
add_dependencies(SDL2main libs)
add_library(speexdsp SHARED IMPORTED)
set_target_properties(speexdsp PROPERTIES IMPORTED_LOCATION
${CMAKE_BINARY_DIR}/libs/lib/${CMAKE_SHARED_LIBRARY_PREFIX}speexdsp${CMAKE_SHARED_LIBRARY_SUFFIX}
)
add_dependencies(speexdsp libs)
include_directories("${CMAKE_BINARY_DIR}/libs/include")
include_directories("${CMAKE_BINARY_DIR}/libs/include/freetype2")
include_directories("${CMAKE_BINARY_DIR}/libs/include/SDL2")
# now build app's shared lib
include_directories(./ndk_helper
${ANDROID_NDK}/sources/android/cpufeatures)
add_definitions(-DDISABLE_HTTP -DDISABLE_TWITCH -DDISABLE_NETWORK -DDISABLE_OPENGL -DGL_GLEXT_PROTOTYPES -D__STDC_LIMIT_MACROS -DNO_RCT2 -DNO_TTF -DSDL_MAIN_HANDLED)
# Fix SpeexDSP compilation
add_definitions(-DHAVE_STDINT_H)
set(COMMON_COMPILE_OPTIONS "${COMMON_COMPILE_OPTIONS} -fstrict-aliasing -Werror -Wundef -Wmissing-declarations -Winit-self -Wall -Wno-unknown-pragmas -Wno-unused-function -Wno-missing-braces ")
set(COMMON_COMPILE_OPTIONS "${COMMON_COMPILE_OPTIONS} -Wno-comment -Wshadow -Wmissing-declarations -Wnonnull")
set(COMMON_COMPILE_OPTIONS "${COMMON_COMPILE_OPTIONS} -fPIC")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--undefined=Java_org_libsdl_app_SDLActivity_nativeInit")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--no-undefined")
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -std=gnu11 ${COMMON_COMPILE_OPTIONS} -Wimplicit")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=gnu++14 ${COMMON_COMPILE_OPTIONS} -Wnon-virtual-dtor")
get_filename_component(ORCT2_ROOT "${CMAKE_SOURCE_DIR}/../../../../../" REALPATH)
file(GLOB_RECURSE LIBOPENRCT2_SOURCES
"${ORCT2_ROOT}/src/openrct2/*.c"
"${ORCT2_ROOT}/src/openrct2/*.cpp"
"${ORCT2_ROOT}/src/openrct2/*.h"
"${ORCT2_ROOT}/src/openrct2/*.hpp")
file(GLOB_RECURSE OPENRCT2_GUI_SOURCES
"${ORCT2_ROOT}/src/openrct2-ui/*.c"
"${ORCT2_ROOT}/src/openrct2-ui/*.cpp"
"${ORCT2_ROOT}/src/openrct2-ui/*.h"
"${ORCT2_ROOT}/src/openrct2-ui/*.hpp")
add_library(openrct2 SHARED ${LIBOPENRCT2_SOURCES})
target_link_libraries(openrct2
android log dl GLESv1_CM GLESv2 z
SDL2 png jansson speexdsp
)
add_library(openrct2-ui SHARED ${OPENRCT2_GUI_SOURCES})
target_link_libraries(openrct2-ui openrct2 SDL2main)
target_include_directories(openrct2-ui PRIVATE "${ORCT2_ROOT}/src")

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,31 @@
package website.openrct2;
import org.libsdl.app.SDLActivity;
public class GameActivity extends SDLActivity {
public float getDefaultScale() {
return getResources().getDisplayMetrics().density;
}
@Override
protected String[] getLibraries() {
return new String[]{
"c++_shared",
"speexdsp",
"jansson",
"png16",
"SDL2-2.0",
"openrct2",
"openrct2-ui"
};
}
protected String[] getArguments() {
if (getIntent().hasExtra("commandLineArgs")) {
return getIntent().getStringArrayExtra("commandLineArgs");
}
return new String[0];
}
}

View File

@ -0,0 +1,18 @@
package website.openrct2;
import java.io.UnsupportedEncodingException;
public class Localisation {
static final String TAG = Localisation.class.getSimpleName();
public static String win1252ToUtf8(byte[] src) {
try {
return new String(src, "CP1252");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return "";
}
}

View File

@ -0,0 +1,195 @@
package website.openrct2;
import android.Manifest;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.AssetManager;
import android.graphics.Point;
import android.graphics.PointF;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.support.v7.app.AppCompatActivity;
import android.text.TextUtils;
import android.util.DisplayMetrics;
import android.util.Log;
import android.view.Display;
import android.view.Surface;
import com.google.android.gms.analytics.HitBuilders;
import com.google.android.gms.analytics.Tracker;
import org.apache.commons.io.IOUtils;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class MainActivity extends AppCompatActivity {
public static final String TAG = "OpenRCT2";
private boolean assetsCopied = false;
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (hasRequiredPermissions()) {
startGame();
}
}
private String[] getSupportedAbis() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
return Build.SUPPORTED_ABIS;
}
if (!TextUtils.isEmpty(Build.CPU_ABI2)) {
return new String[]{Build.CPU_ABI, Build.CPU_ABI2};
}
return new String[]{Build.CPU_ABI};
}
private PointF getResolutionDips() {
PointF out = new PointF();
Point pixelSize = new Point();
Display display = getWindowManager().getDefaultDisplay();
DisplayMetrics metrics = new DisplayMetrics();
display.getMetrics(metrics);
boolean success = false;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
display.getRealSize(pixelSize);
display.getRealMetrics(metrics);
success = true;
} else {
try {
Method getRawHeight = Display.class.getMethod("getRawHeight");
Method getRawWidth = Display.class.getMethod("getRawWidth");
pixelSize.x = (Integer) getRawWidth.invoke(display);
pixelSize.y = (Integer) getRawHeight.invoke(display);
success = true;
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
if (!success) {
// Fall back to viewport size
display.getSize(pixelSize);
}
int rotation = display.getRotation();
if (rotation == Surface.ROTATION_90 || rotation == Surface.ROTATION_270) {
pixelSize = new Point(pixelSize.y, pixelSize.x);
}
out.x = ((float) pixelSize.x) / metrics.density;
out.y = ((float) pixelSize.y) / metrics.density;
return out;
}
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
String[] supportedAbis = getSupportedAbis();
PointF resolution = getResolutionDips();
DisplayMetrics displayMetrics = getResources().getDisplayMetrics();
Tracker tracker = ((OpenRCT2App) getApplication()).getDefaultTracker();
tracker.setScreenName("Main");
tracker.setScreenResolution(Math.round(resolution.x), Math.round(resolution.y));
tracker.send(new HitBuilders.ScreenViewBuilder()
.setCustomDimension(1, Float.toString(displayMetrics.density))
.setCustomDimension(2, TextUtils.join(", ", supportedAbis))
.build()
);
}
@Override
protected void onStart() {
super.onStart();
if (!hasRequiredPermissions()) {
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE}, 1);
} else {
startGame();
}
}
private boolean hasRequiredPermissions() {
if (ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) {
return false;
}
if (ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_DENIED) {
return false;
}
return true;
}
private void startGame() {
copyAssets();
Intent intent = new Intent(this, GameActivity.class);
if (getIntent().hasExtra("commandLineArgs")) {
intent.putExtra("commandLineArgs", getIntent().getStringArrayExtra("commandLineArgs"));
}
startActivity(intent);
finish();
}
private void copyAssets() {
File dataDir = new File("/sdcard/openrct2/");
try {
copyAsset(getAssets(), "data", dataDir, "");
} catch (IOException e) {
Log.e(TAG, "Error extracting files", e);
return;
}
assetsCopied = true;
}
private void copyAsset(AssetManager assets, String srcPath, File dataDir, String destPath) throws IOException {
String[] list = assets.list(srcPath);
if (list.length == 0) {
InputStream input = assets.open(srcPath);
File extractedFile = new File(dataDir, destPath);
File parentFile = extractedFile.getParentFile();
if (!parentFile.exists()) {
boolean success = parentFile.mkdirs();
if (!success) {
Log.d(TAG, String.format("Error creating folder '%s'", parentFile));
}
}
FileOutputStream output = new FileOutputStream(extractedFile);
IOUtils.copyLarge(input, output);
output.close();
input.close();
return;
}
for (String fileName : list) {
copyAsset(assets, srcPath + File.separator + fileName, dataDir, destPath + File.separator + fileName);
}
}
}

View File

@ -0,0 +1,24 @@
package website.openrct2;
import android.app.Application;
import com.google.android.gms.analytics.GoogleAnalytics;
import com.google.android.gms.analytics.Tracker;
public class OpenRCT2App extends Application {
private Tracker mTracker;
/**
* Gets the default {@link Tracker} for this {@link Application}.
*
* @return tracker
*/
synchronized public Tracker getDefaultTracker() {
if (mTracker == null) {
GoogleAnalytics analytics = GoogleAnalytics.getInstance(this);
// To enable debug logging use: adb shell setprop log.tag.GAv4 DEBUG
mTracker = analytics.newTracker(R.xml.global_tracker);
}
return mTracker;
}
}

View File

@ -0,0 +1,107 @@
package website.openrct2;
import android.util.Log;
import org.apache.commons.io.IOUtils;
import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
public class ZipArchive {
private final ZipFile _zipArchive;
public ZipArchive(String path) throws IOException {
_zipArchive = new ZipFile(path);
}
public void close() {
try {
_zipArchive.close();
} catch (IOException e) {
e.printStackTrace();
}
}
public int getNumFiles() {
return _zipArchive.size();
}
private ZipEntry getZipEntry(int index) {
Enumeration<? extends ZipEntry> entries = _zipArchive.entries();
int i = 0;
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
if (index == i) {
return entry;
}
i++;
}
return null;
}
public String getFileName(int index) {
ZipEntry entry = getZipEntry(index);
if (entry != null) {
return entry.getName();
}
return null;
}
public long getFileSize(int index) {
ZipEntry entry = getZipEntry(index);
if (entry != null) {
return entry.getSize();
}
return -1;
}
public int getFileIndex(String path) {
Enumeration<? extends ZipEntry> entries = _zipArchive.entries();
int i = 0;
while (entries.hasMoreElements()) {
ZipEntry entry = entries.nextElement();
if (entry.getName().equalsIgnoreCase(path)) {
return i;
}
i++;
}
return -1;
}
public long getFile(int index) throws IOException {
ZipEntry entry = getZipEntry(index);
if (entry == null) {
return 0;
}
InputStream inputStream = _zipArchive.getInputStream(entry);
int numBytesToRead = (int) entry.getSize();
if (numBytesToRead == -1) {
Log.e("ZipArchive", "Unknown length for zip entry");
return 0;
}
byte[] inBuffer = new byte[numBytesToRead];
IOUtils.read(inputStream, inBuffer);
return allocBytes(inBuffer, numBytesToRead);
}
native static long allocBytes(byte[] input, int size);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@ -0,0 +1,34 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="org.openrct2.android.MainActivity">
<RelativeLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@drawable/logo_icon"
android:id="@+id/imageView"
android:layout_centerHorizontal="false" />
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:srcCompat="@drawable/logo_text"
android:id="@+id/imageView2"
android:layout_marginTop="18dp"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="false"
android:layout_marginLeft="104dp" />
</RelativeLayout>
</RelativeLayout>

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

View File

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="colorPrimary">#3F51B5</color>
<color name="colorPrimaryDark">#303F9F</color>
<color name="colorAccent">#FF4081</color>
</resources>

View File

@ -0,0 +1,3 @@
<resources>
<string name="app_name">OpenRCT2</string>
</resources>

View File

@ -0,0 +1,19 @@
<resources>
<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
<!-- Base application theme. -->
<style name="AppTheme.Splash" parent="Theme.AppCompat.NoActionBar">
<!-- Customize your theme here. -->
<item name="colorPrimary">@color/colorPrimary</item>
<item name="colorPrimaryDark">@color/colorPrimaryDark</item>
<item name="colorAccent">@color/colorAccent</item>
</style>
</resources>

View File

@ -0,0 +1,23 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
repositories {
jcenter()
maven {
url "https://oss.sonatype.org/content/repositories/snapshots/"
}
}
dependencies {
classpath 'com.android.tools.build:gradle:2.3.3'
classpath 'de.undercouch:gradle-download-task:3.2.0'
classpath 'com.google.gms:google-services:3.0.0'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
jcenter()
}
}

View File

@ -0,0 +1,18 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
# Default value: -Xmx10248m -XX:MaxPermSize=256m
# org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true

Binary file not shown.

View File

@ -0,0 +1,6 @@
#Sat Apr 15 05:32:00 CEST 2017
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip

160
src/openrct2-android/gradlew vendored Executable file
View File

@ -0,0 +1,160 @@
#!/usr/bin/env bash
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS=""
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn ( ) {
echo "$*"
}
die ( ) {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
esac
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin, switch paths to Windows format before running java
if $cygwin ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=$((i+1))
done
case $i in
(0) set -- ;;
(1) set -- "$args0" ;;
(2) set -- "$args0" "$args1" ;;
(3) set -- "$args0" "$args1" "$args2" ;;
(4) set -- "$args0" "$args1" "$args2" "$args3" ;;
(5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
(6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
(7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
(8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
(9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules
function splitJvmOpts() {
JVM_OPTS=("$@")
}
eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS
JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME"
exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@"

90
src/openrct2-android/gradlew.bat vendored Normal file
View File

@ -0,0 +1,90 @@
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS=
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto init
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto init
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:init
@rem Get command-line arguments, handling Windowz variants
if not "%OS%" == "Windows_NT" goto win9xME_args
if "%@eval[2+2]" == "4" goto 4NT_args
:win9xME_args
@rem Slurp the command line arguments.
set CMD_LINE_ARGS=
set _SKIP=2
:win9xME_args_slurp
if "x%~1" == "x" goto execute
set CMD_LINE_ARGS=%*
goto execute
:4NT_args
@rem Get arguments from the 4NT Shell from JP Software
set CMD_LINE_ARGS=%$
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

View File

@ -0,0 +1 @@
include ':app'

View File

@ -64,3 +64,13 @@ int main(int argc, char * * argv)
}
return gExitCode;
}
#ifdef __ANDROID__
extern "C" {
int SDL_main(int argc, char *argv[])
{
return main(argc, argv);
}
}
#endif

View File

@ -0,0 +1,79 @@
#pragma region Copyright (c) 2014-2017 OpenRCT2 Developers
/*****************************************************************************
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
*
* OpenRCT2 is the work of many authors, a full list can be found in contributors.md
* For more information, visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* A full copy of the GNU General Public License can be found in licence.txt
*****************************************************************************/
#pragma endregion
#ifdef __ANDROID__
#include <dlfcn.h>
#include <sstream>
#include <stdexcept>
#include <openrct2/common.h>
#include <openrct2/core/String.hpp>
#include <openrct2/ui/UiContext.h>
#include "UiContext.h"
#include <SDL.h>
namespace OpenRCT2 { namespace Ui
{
class AndroidContext final : public IPlatformUiContext
{
private:
public:
AndroidContext()
{
}
void SetWindowIcon(SDL_Window * window) override
{
}
bool IsSteamOverlayAttached() override
{
return false;
}
void ShowMessageBox(SDL_Window * window, const std::string &message) override
{
log_verbose(message.c_str());
STUB();
}
std::string ShowFileDialog(SDL_Window * window, const FileDialogDesc &desc) override
{
STUB();
return nullptr;
}
std::string ShowDirectoryDialog(SDL_Window * window, const std::string &title) override
{
log_info(title.c_str());
STUB();
return "/sdcard/rct2";
}
};
IPlatformUiContext * CreatePlatformUiContext()
{
return new AndroidContext();
}
} }
#endif // __ANDROID__

View File

@ -14,7 +14,7 @@
*****************************************************************************/
#pragma endregion
#ifdef __linux__
#if defined(__linux__) && !defined(__ANDROID__)
#include <dlfcn.h>
#include <sstream>

View File

@ -28,9 +28,17 @@
#elif defined(__aarch64__)
#define OPENRCT2_ARCHITECTURE "AArch64"
#elif defined(__arm__) || defined(_M_ARM)
#define OPENRCT2_ARCHITECTURE "ARMv7"
#if defined(__ARM_ARCH_7A__)
#define OPENRCT2_ARCHITECTURE "arm-v7a"
#else
#define OPENRCT2_ARCHITECTURE "arm"
#endif
#elif defined(__powerpc__) || defined(_M_PPC)
#define OPENRCT2_ARCHITECTURE "PowerPC"
#elif defined(__mips64)
#define OPENRCT2_ARCHITECTURE "mips64"
#elif defined(__mips__)
#define OPENRCT2_ARCHITECTURE "mips"
#endif
#ifndef OPENRCT2_ARCHITECTURE
@ -41,7 +49,7 @@
#ifdef _WIN32
#define OPENRCT2_PLATFORM "Windows"
#endif
#ifdef __linux__
#if defined(__linux__) && !defined(__ANDROID__)
#define OPENRCT2_PLATFORM "Linux"
#endif
#if (defined(__APPLE__) && defined(__MACH__))
@ -50,6 +58,9 @@
#ifdef __FreeBSD__
#define OPENRCT2_PLATFORM "FreeBSD"
#endif
#ifdef __ANDROID__
#define OPENRCT2_PLATFORM "Android"
#endif
#ifndef OPENRCT2_PLATFORM
#error Unknown platform!
#endif

View File

@ -185,7 +185,7 @@ namespace Config
model->disable_lightning_effect = reader->GetBoolean("disable_lightning_effect", false);
model->allow_loading_with_incorrect_checksum = reader->GetBoolean("allow_loading_with_incorrect_checksum", true);
model->steam_overlay_pause = reader->GetBoolean("steam_overlay_pause", true);
model->window_scale = reader->GetFloat("window_scale", 1.0f);
model->window_scale = reader->GetFloat("window_scale", platform_get_default_scale());
model->scale_quality = reader->GetSint32("scale_quality", 1);
model->use_nn_at_integer_scales = reader->GetBoolean("use_nn_at_integer_scales", true);
model->show_fps = reader->GetBoolean("show_fps", false);

View File

@ -116,7 +116,7 @@ public:
{
#if defined(_MSC_VER)
return _ftelli64(_file);
#elif (defined(__APPLE__) && defined(__MACH__))
#elif (defined(__APPLE__) && defined(__MACH__)) || defined(__ANDROID__)
return ftello(_file);
#else
return ftello64(_file);
@ -142,7 +142,7 @@ public:
_fseeki64(_file, offset, SEEK_END);
break;
}
#elif (defined(__APPLE__) && defined(__MACH__))
#elif (defined(__APPLE__) && defined(__MACH__)) || defined(__ANDROID__)
switch (origin) {
case STREAM_SEEK_BEGIN:
fseeko(_file, offset, SEEK_SET);

View File

@ -14,6 +14,7 @@
*****************************************************************************/
#pragma endregion
#ifndef __ANDROID__
#include <zip.h>
#include "IStream.hpp"
#include "MemoryStream.h"
@ -159,3 +160,5 @@ namespace Zip
return result;
}
}
# endif

View File

@ -0,0 +1,179 @@
#pragma region Copyright (c) 2014-2017 OpenRCT2 Developers
/*****************************************************************************
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
*
* OpenRCT2 is the work of many authors, a full list can be found in contributors.md
* For more information, visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* A full copy of the GNU General Public License can be found in licence.txt
*****************************************************************************/
#pragma endregion
#ifdef __ANDROID__
#include <SDL.h>
#include <jni.h>
#include "IStream.hpp"
#include "Zip.h"
#include "MemoryStream.h"
class ZipArchive final : public IZipArchive {
private:
jobject _zip;
public:
ZipArchive(const utf8 *path, ZIP_ACCESS access) {
// retrieve the JNI environment.
JNIEnv *env = (JNIEnv *) SDL_AndroidGetJNIEnv();
jclass jniClass = env->FindClass("website/openrct2/ZipArchive");
jmethodID constructor = env->GetMethodID(jniClass, "<init>", "(Ljava/lang/String;)V");
jstring jniPath = env->NewStringUTF(path);
// TODO: Catch exceptions. Should probably be done on Java side, and just return null from a static method
jobject zip = env->NewObject(jniClass, constructor, jniPath);
_zip = env->NewGlobalRef(zip);
}
~ZipArchive() override {
// retrieve the JNI environment.
JNIEnv *env = (JNIEnv *) SDL_AndroidGetJNIEnv();
jclass zipClass = env->GetObjectClass(_zip);
jmethodID closeMethod = env->GetMethodID(zipClass, "close", "()V");
env->CallVoidMethod(_zip, closeMethod);
env->DeleteGlobalRef(_zip);
}
size_t GetNumFiles() const override {
// retrieve the JNI environment.
JNIEnv *env = (JNIEnv *) SDL_AndroidGetJNIEnv();
jclass zipClass = env->GetObjectClass(_zip);
jmethodID fileCountMethod = env->GetMethodID(zipClass, "getNumFiles", "()I");
return (size_t) env->CallIntMethod(_zip, fileCountMethod);
}
const utf8 *GetFileName(size_t index) const override {
// retrieve the JNI environment.
JNIEnv *env = (JNIEnv *) SDL_AndroidGetJNIEnv();
jclass zipClass = env->GetObjectClass(_zip);
jmethodID fileNameMethod = env->GetMethodID(zipClass, "getFileName",
"(I)Ljava/lang/String;");
jstring jniString = (jstring) env->CallObjectMethod(_zip, fileNameMethod, (jint) index);
const char *jniChars = env->GetStringUTFChars(jniString, nullptr);
utf8 *string = (char *) malloc(strlen(jniChars) + 1);
memcpy((void *) string, jniChars, strlen(jniChars));
string[strlen(jniChars)] = 0x00;
env->ReleaseStringUTFChars(jniString, jniChars);
return string;
}
uint64 GetFileSize(size_t index) const override {
// retrieve the JNI environment.
JNIEnv *env = (JNIEnv *) SDL_AndroidGetJNIEnv();
jclass zipClass = env->GetObjectClass(_zip);
jmethodID fileSizeMethod = env->GetMethodID(zipClass, "getFileSize", "(I)J");
return (size_t) env->CallLongMethod(_zip, fileSizeMethod, (jint) index);
}
void *GetFileData(const utf8 *path, size_t *outSize) const override {
// retrieve the JNI environment.
JNIEnv *env = (JNIEnv *) SDL_AndroidGetJNIEnv();
jclass zipClass = env->GetObjectClass(_zip);
jstring javaPath = env->NewStringUTF(path);
jmethodID indexMethod = env->GetMethodID(zipClass, "getFileIndex", "(Ljava/lang/String;)I");
jint index = env->CallIntMethod(_zip, indexMethod, javaPath);
jmethodID fileMethod = env->GetMethodID(zipClass, "getFile", "(I)J");
jlong ptr = env->CallLongMethod(_zip, fileMethod, index);
*outSize = this->GetFileSize(index);
return reinterpret_cast<void *>(ptr);
}
IStream *GetFileStream(const utf8 *path) const override {
IStream * stream = nullptr;
size_t dataSize;
void * data = GetFileData(path, &dataSize);
if (data != nullptr)
{
stream = new MemoryStream(data, dataSize, MEMORY_ACCESS::READ | MEMORY_ACCESS::OWNER);
}
return stream;
}
void SetFileData(const utf8 *path, void *data, size_t dataSize) override {
STUB();
}
void DeleteFile(const utf8 *path) override {
STUB();
}
void RenameFile(const utf8 *path, const utf8 *newPath) override {
STUB();
}
};
namespace Zip {
IZipArchive *Open(const utf8 *path, ZIP_ACCESS access) {
return new ZipArchive(path, access);
}
IZipArchive *TryOpen(const utf8 *path, ZIP_ACCESS access) {
IZipArchive *result = nullptr;
try {
result = new ZipArchive(path, access);
}
catch (Exception) {
}
return result;
}
}
extern "C" {
JNIEXPORT jlong JNICALL
Java_website_openrct2_ZipArchive_allocBytes(JNIEnv *env, jclass, jbyteArray input,
jint numBytes);
}
JNIEXPORT jlong JNICALL
Java_website_openrct2_ZipArchive_allocBytes(JNIEnv *env, jclass, jbyteArray input,
jint numBytes) {
jbyte *bufferPtr = env->GetByteArrayElements(input, NULL);
void *data = Memory::Allocate<void>((size_t) numBytes);
memcpy(data, bufferPtr, numBytes);
env->ReleaseByteArrayElements(input, bufferPtr, 0);
return (uintptr_t) data;
}
#endif // __ANDROID__

View File

@ -19,6 +19,10 @@
#include <stdio.h>
#include "diagnostic.h"
#ifdef __ANDROID__
#include <android/log.h>
#endif
static bool _log_location_enabled = true;
bool _log_levels[DIAGNOSTIC_LEVEL_COUNT] = { true, true, true, false, true };
@ -41,6 +45,40 @@ static FILE * diagnostic_get_stream(DiagnosticLevel level)
}
}
#ifdef __ANDROID__
int _android_log_priority[DIAGNOSTIC_LEVEL_COUNT] = {ANDROID_LOG_FATAL, ANDROID_LOG_ERROR, ANDROID_LOG_WARN, ANDROID_LOG_VERBOSE, ANDROID_LOG_INFO};
void diagnostic_log(DiagnosticLevel diagnosticLevel, const char *format, ...)
{
va_list args;
if (!_log_levels[diagnosticLevel])
return;
va_start(args, format);
__android_log_vprint(_android_log_priority[diagnosticLevel], "OpenRCT2", format, args);
va_end(args);
}
void diagnostic_log_with_location(DiagnosticLevel diagnosticLevel, const char *file, const char *function, sint32 line, const char *format, ...)
{
va_list args;
char buf[1024];
if (!_log_levels[diagnosticLevel])
return;
UNUSED(_log_location_enabled);
snprintf(buf, 1024, "[%s:%d (%s)]: ", file, line, function);
va_start(args, format);
__android_log_vprint(_android_log_priority[diagnosticLevel], file, format, args);
va_end(args);
}
#else
void diagnostic_log(DiagnosticLevel diagnosticLevel, const char *format, ...)
{
va_list args;
@ -85,3 +123,5 @@ void diagnostic_log_with_location(DiagnosticLevel diagnosticLevel, const char *f
// Line terminator
fprintf(stream, "\n");
}
#endif // __ANDROID__

View File

@ -20,6 +20,10 @@
#ifdef _WIN32
#include <windows.h>
#elif defined(__ANDROID__)
#include <jni.h>
#include <SDL.h>
#else
#include <iconv.h>
#include <errno.h>
@ -1345,6 +1349,25 @@ sint32 win1252_to_utf8(utf8string dst, const char *src, size_t srcLength, size_t
sint32 result = WideCharToMultiByte(CP_UTF8, 0, intermediateBuffer, -1, dst, (sint32)maxBufferLength, NULL, NULL);
free(heapBuffer);
#elif defined(__ANDROID__)
JNIEnv *env = SDL_AndroidGetJNIEnv();
jclass *localisation = (*env)->FindClass(env, "website/openrct2/Localisation");
jmethodID win1252ToUtf8 = (*env)->GetStaticMethodID(env, localisation, "win1252ToUtf8", "([B)Ljava/lang/String;");
jbyteArray *bytes = (*env)->NewByteArray(env, srcLength);
(*env)->SetByteArrayRegion(env, bytes, 0, srcLength, (jbyte *) src);
jstring * jstring1 = (*env)->CallStaticObjectMethod(env, localisation, win1252ToUtf8, bytes);
const char* utf = (*env)->GetStringUTFChars(env, jstring1, NULL);
strcpy(dst, utf);
(*env)->ReleaseStringUTFChars(env, jstring1, utf);
(*env)->DeleteLocalRef(env, localisation);
(*env)->DeleteLocalRef(env, bytes);
(*env)->DeleteLocalRef(env, jstring1);
int result = strlen(dst) + 1;
#else
//log_warning("converting %s of size %d", src, srcLength);
char *buffer_conv = strndup(src, srcLength);

View File

@ -0,0 +1,90 @@
#pragma region Copyright (c) 2014-2017 OpenRCT2 Developers
/*****************************************************************************
* OpenRCT2, an open source clone of Roller Coaster Tycoon 2.
*
* OpenRCT2 is the work of many authors, a full list can be found in contributors.md
* For more information, visit https://github.com/OpenRCT2/OpenRCT2
*
* OpenRCT2 is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* A full copy of the GNU General Public License can be found in licence.txt
*****************************************************************************/
#pragma endregion
#ifdef __ANDROID__
#include "platform.h"
#include "../config/Config.h"
#include "../localisation/language.h"
#include "../util/util.h"
#include <wchar.h>
#include <jni.h>
#include <SDL.h>
//int mbtowc(wchar_t *__restrict pwc, const char *__restrict s, size_t n) {
// static mbstate_t mbs;
// size_t rval;
// if (s == NULL) {
// /* No support for state dependent encodings. */
// memset(&mbs, 0, sizeof(mbs));
// return (0);
// }
// rval = mbrtowc(pwc, s, n, &mbs);
// if (rval == (size_t) -1 || rval == (size_t) -2)
// return (-1);
// return ((int) rval);
//}
void platform_get_exe_path(utf8 *outPath, size_t outSize)
{
safe_strcpy(outPath, "/sdcard/openrct2", outSize);
}
void platform_posix_sub_user_data_path(char *buffer, size_t size, const char *homedir) {
safe_strcpy(buffer, "/sdcard/openrct2-user/", size);
}
#ifndef NO_TTF
bool platform_get_font_path(TTFFontDescriptor *font, utf8 *buffer, size_t size)
{
STUB();
return false;
}
#endif
void platform_posix_sub_resolve_openrct_data_path(utf8 *out, size_t size) {
safe_strcpy(out, "/sdcard/openrct2", size);
}
uint16 platform_get_locale_language() {
return LANGUAGE_ENGLISH_UK;
}
uint8 platform_get_locale_currency() {
return platform_get_currency_value(NULL);
}
uint8 platform_get_locale_measurement_format() {
return MEASUREMENT_FORMAT_METRIC;
}
float platform_get_default_scale() {
JNIEnv *env = SDL_AndroidGetJNIEnv();
jobject *activity = (jobject *) SDL_AndroidGetActivity();
jclass *activityClass = (*env)->GetObjectClass(env, activity);
jmethodID getDefaultScale = (*env)->GetMethodID(env, activityClass, "getDefaultScale", "()F");
jfloat displayScale = (*env)->CallFloatMethod(env, activity, getDefaultScale);
(*env)->DeleteLocalRef(env, activity);
(*env)->DeleteLocalRef(env, activityClass);
return displayScale;
}
#endif

View File

@ -18,7 +18,7 @@
// Despite the name, this file contains support for more OSs besides Linux, provided the necessary ifdefs remain small.
// Otherwise, they should be spun off into their own files.
#if defined(__linux__) || defined(__FREEBSD__)
#if (defined(__linux__) || defined(__FREEBSD__)) && !defined(__ANDROID__)
#ifdef __FREEBSD__
#include <sys/sysctl.h>

View File

@ -143,6 +143,8 @@ bool platform_get_font_path(TTFFontDescriptor *font, utf8 *buffer, size_t size);
datetime64 platform_get_datetime_now_utc();
float platform_get_default_scale();
// Called very early in the program before parsing commandline arguments.
void core_init();
@ -163,7 +165,7 @@ void core_init();
__declspec(dllexport) sint32 StartOpenRCT(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, sint32 nCmdShow);
#endif // _WIN32
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__FreeBSD__)
#if defined(__unix__) || (defined(__APPLE__) && defined(__MACH__)) || defined(__FreeBSD__) || defined(__ANDROID__)
void platform_posix_sub_user_data_path(char *buffer, size_t size, const char *homedir);
void platform_posix_sub_resolve_openrct_data_path(utf8 *out, size_t size);
#endif

View File

@ -195,6 +195,12 @@ uint8 platform_get_currency_value(const char *currCode) {
return CURRENCY_POUNDS;
}
#ifndef __ANDROID__
float platform_get_default_scale() {
return 1;
}
#endif
void core_init()
{
static bool initialised = false;

View File

@ -144,6 +144,8 @@ extern "C"
handle->Stream = zip->GetFileStream(filename);
handle->HintPath = String::Duplicate(filename);
delete zip;
} else {
Console::Error::WriteLine("Failed to open zipped path '%s' from zip '%s'", filename, seq->Path);
}
}
else