mirror of
https://github.com/izzy2lost/2ship2harkinian-Android.git
synced 2026-06-19 01:20:08 -07:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5ad3f98ee6 | ||
|
|
d11c66eea9 | ||
|
|
d6c503f0e9 | ||
|
|
e9a5064e59 | ||
|
|
821dd700ff | ||
|
|
ef7780ffaa |
@@ -0,0 +1,74 @@
|
|||||||
|
name: generate-android-apk
|
||||||
|
|
||||||
|
on:
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
generate-2ship-otr:
|
||||||
|
runs-on: ubuntu-22.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
- name: Install dependencies
|
||||||
|
run: |
|
||||||
|
sudo apt-get update
|
||||||
|
sudo apt-get install -y ninja-build cmake g++ gcc libzip-dev zipcmp zipmerge ziptool
|
||||||
|
- name: Install latest SDL
|
||||||
|
run: |
|
||||||
|
if [ ! -d "SDL2-2.28.5" ]; then
|
||||||
|
wget https://github.com/libsdl-org/SDL/releases/download/release-2.28.5/SDL2-2.28.5.tar.gz
|
||||||
|
tar -xzf SDL2-2.28.5.tar.gz
|
||||||
|
fi
|
||||||
|
cd SDL2-2.28.5
|
||||||
|
./configure --enable-hidapi-libusb
|
||||||
|
make -j 10
|
||||||
|
sudo make install
|
||||||
|
sudo cp -av /usr/local/lib/libSDL* /lib/x86_64-linux-gnu/
|
||||||
|
- name: Install latest tinyxml2
|
||||||
|
run: |
|
||||||
|
sudo apt-get remove libtinyxml2-dev
|
||||||
|
if [ ! -d "tinyxml2-10.0.0" ]; then
|
||||||
|
wget https://github.com/leethomason/tinyxml2/archive/refs/tags/10.0.0.tar.gz
|
||||||
|
tar -xzf 10.0.0.tar.gz
|
||||||
|
fi
|
||||||
|
cd tinyxml2-10.0.0
|
||||||
|
mkdir -p build
|
||||||
|
cd build
|
||||||
|
cmake ..
|
||||||
|
make
|
||||||
|
sudo make install
|
||||||
|
- name: Generate 2ship.o2r
|
||||||
|
run: |
|
||||||
|
cmake --no-warn-unused-cli -H. -Bbuild-cmake -GNinja -DCMAKE_BUILD_TYPE:STRING=Release
|
||||||
|
cmake --build build-cmake --config Release --target Generate2ShipOtr -j3
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: 2ship.o2r
|
||||||
|
path: 2ship.o2r
|
||||||
|
retention-days: 1
|
||||||
|
|
||||||
|
build-android:
|
||||||
|
needs: generate-2ship-otr
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
- name: Install dependencies
|
||||||
|
run: sudo apt-get install -y ninja-build
|
||||||
|
- name: Download 2ship.o2r
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: 2ship.o2r
|
||||||
|
path: Android/app/src/main/assets
|
||||||
|
- name: Build 2Ship APK
|
||||||
|
run: |
|
||||||
|
cd Android/
|
||||||
|
./gradlew assembleDebug -P elfBuildType=RelWithDebInfo
|
||||||
|
mv app/build/outputs/apk/debug/app-debug.apk ../2ship.apk
|
||||||
|
- name: Upload APK artifact
|
||||||
|
uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: 2ship-apk
|
||||||
|
path: 2ship.apk
|
||||||
@@ -1,7 +1,8 @@
|
|||||||
name: generate-builds
|
name: generate-builds
|
||||||
on:
|
on:
|
||||||
push:
|
# push:
|
||||||
pull_request:
|
# pull_request:
|
||||||
|
workflow_dispatch:
|
||||||
concurrency:
|
concurrency:
|
||||||
group: ${{ github.workflow }}-${{ github.ref }}
|
group: ${{ github.workflow }}-${{ github.ref }}
|
||||||
cancel-in-progress: true
|
cancel-in-progress: true
|
||||||
@@ -380,3 +381,29 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
name: 2ship-windows
|
name: 2ship-windows
|
||||||
path: 2ship-windows
|
path: 2ship-windows
|
||||||
|
|
||||||
|
build-android:
|
||||||
|
needs: generate-2ship-otr
|
||||||
|
runs-on: ubuntu-24.04
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
submodules: true
|
||||||
|
- name: Install dependencies
|
||||||
|
run: sudo apt-get install -y ninja-build
|
||||||
|
- name: Download 2ship.o2r
|
||||||
|
uses: actions/download-artifact@v4
|
||||||
|
with:
|
||||||
|
name: 2ship.o2r
|
||||||
|
path: Android/app/src/main/assets
|
||||||
|
- name: Build 2Ship
|
||||||
|
run: |
|
||||||
|
cd Android/
|
||||||
|
./gradlew assembleDebug -P elfBuildType=RelWithDebInfo
|
||||||
|
mv app/build/outputs/apk/debug/app-debug.apk ../2ship.apk
|
||||||
|
- name: Create release
|
||||||
|
uses: svenstaro/upload-release-action@v2
|
||||||
|
with:
|
||||||
|
repo_token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
tag: ${{ github.ref }}
|
||||||
|
file: 2ship.apk
|
||||||
|
|||||||
@@ -67,3 +67,6 @@ _packages/
|
|||||||
/mm/src/boot/build.c
|
/mm/src/boot/build.c
|
||||||
/mm/windows/properties.h
|
/mm/windows/properties.h
|
||||||
/clang-format.exe
|
/clang-format.exe
|
||||||
|
|
||||||
|
# IntelliJ / Android Studio
|
||||||
|
.idea
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
[submodule "libultraship"]
|
[submodule "libultraship"]
|
||||||
path = libultraship
|
path = libultraship
|
||||||
url = https://github.com/Waterdish/libultraship.git
|
url = https://github.com/robertkirkman/libultraship.git
|
||||||
[submodule "OTRExporter"]
|
[submodule "OTRExporter"]
|
||||||
path = OTRExporter
|
path = OTRExporter
|
||||||
url = https://github.com/Waterdish/OTRExporter.git
|
url = https://github.com/Waterdish/OTRExporter.git
|
||||||
|
|||||||
+23
-25
@@ -1,4 +1,4 @@
|
|||||||
def buildAsLibrary = project.hasProperty('BUILD_AS_LIBRARY');
|
def buildAsLibrary = project.hasProperty('BUILD_AS_LIBRARY')
|
||||||
def buildAsApplication = !buildAsLibrary
|
def buildAsApplication = !buildAsLibrary
|
||||||
if (buildAsApplication) {
|
if (buildAsApplication) {
|
||||||
apply plugin: 'com.android.application'
|
apply plugin: 'com.android.application'
|
||||||
@@ -8,25 +8,21 @@ else {
|
|||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
ndkPath "/home/waterdish/Android/Sdk/ndk/26.0.10792818" // Point to your own NDK
|
ndkVersion '27.2.12479018'
|
||||||
compileSdkVersion 31
|
compileSdkVersion 34
|
||||||
defaultConfig {
|
defaultConfig {
|
||||||
if (buildAsApplication) {
|
if (buildAsApplication) {
|
||||||
applicationId "com.dishii.mm"
|
applicationId "com.dishii.mm"
|
||||||
}
|
}
|
||||||
minSdkVersion 24
|
minSdkVersion 21
|
||||||
targetSdkVersion 31
|
//noinspection OldTargetApi
|
||||||
|
targetSdkVersion 34
|
||||||
versionCode 4
|
versionCode 4
|
||||||
versionName "1.1.1"
|
versionName "1.1.1"
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
//ndkBuild {
|
|
||||||
// arguments "APP_PLATFORM=android-23"
|
|
||||||
// abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
|
|
||||||
//}
|
|
||||||
cmake {
|
cmake {
|
||||||
arguments "-DSDL_SHARED=ON", "-DANDROID_STL=c++_static", "-DHAVE_LD_VERSION_SCRIPT=OFF",'-DUSE_OPENGLES=ON'
|
arguments "-DANDROID_APPNAME=${applicationId}", "-DANDROID_APP_PLATFORM=android-21", "-DANDROID_STL=c++_static", "-DHAVE_LD_VERSION_SCRIPT=OFF", "-DUSE_OPENGLES=ON", "-DCMAKE_BUILD_TYPE=$elfBuildType"
|
||||||
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
|
abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
|
||||||
//abiFilters 'arm64-v8a'
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -34,9 +30,17 @@ android {
|
|||||||
release {
|
release {
|
||||||
minifyEnabled false
|
minifyEnabled false
|
||||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
||||||
|
signingConfig signingConfigs.debug
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
applicationVariants.all { variant ->
|
buildFeatures {
|
||||||
|
buildConfig = true
|
||||||
|
}
|
||||||
|
namespace 'com.dishii.mm'
|
||||||
|
lint {
|
||||||
|
abortOnError false
|
||||||
|
}
|
||||||
|
applicationVariants.configureEach { variant ->
|
||||||
tasks["merge${variant.name.capitalize()}Assets"]
|
tasks["merge${variant.name.capitalize()}Assets"]
|
||||||
.dependsOn("externalNativeBuild${variant.name.capitalize()}")
|
.dependsOn("externalNativeBuild${variant.name.capitalize()}")
|
||||||
}
|
}
|
||||||
@@ -45,26 +49,20 @@ android {
|
|||||||
jniLibs.srcDir 'libs'
|
jniLibs.srcDir 'libs'
|
||||||
}
|
}
|
||||||
externalNativeBuild {
|
externalNativeBuild {
|
||||||
//ndkBuild {
|
|
||||||
// path 'jni/Android.mk'
|
|
||||||
//}
|
|
||||||
cmake {
|
cmake {
|
||||||
path '../../CMakeLists.txt'
|
path '../../CMakeLists.txt'
|
||||||
version "3.25.1"
|
version "3.31.5"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
lintOptions {
|
|
||||||
abortOnError false
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buildAsLibrary) {
|
if (buildAsLibrary) {
|
||||||
libraryVariants.all { variant ->
|
libraryVariants.all { variant ->
|
||||||
variant.outputs.each { output ->
|
variant.outputs.each { output ->
|
||||||
def outputFile = output.outputFile
|
def outputFile = output.outputFile
|
||||||
if (outputFile != null && outputFile.name.endsWith(".aar")) {
|
if (outputFile != null && outputFile.name.endsWith(".aar")) {
|
||||||
def fileName = "org.libsdl.app.aar";
|
def fileName = "com.dishii.mm.aar"
|
||||||
output.outputFile = new File(outputFile.parent, fileName);
|
output.outputFile = new File(outputFile.parent, fileName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -74,13 +72,13 @@ android {
|
|||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
implementation fileTree(include: ['*.jar'], dir: 'libs')
|
||||||
implementation 'androidx.core:core:1.7.0' // Use the latest version
|
implementation 'androidx.core:core:1.13.1'
|
||||||
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
|
implementation 'androidx.constraintlayout:constraintlayout:2.2.0'
|
||||||
}
|
}
|
||||||
|
|
||||||
task wrapper(type: Wrapper) {
|
tasks.register('wrapper', Wrapper) {
|
||||||
gradleVersion = '7.0.3'
|
gradleVersion = '8.10.2'
|
||||||
}
|
}
|
||||||
|
|
||||||
task prepareKotlinBuildScriptModel {
|
tasks.register('prepareKotlinBuildScriptModel') {
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
Binary file not shown.
@@ -1,5 +0,0 @@
|
|||||||
distributionBase=GRADLE_USER_HOME
|
|
||||||
distributionPath=wrapper/dists
|
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip
|
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
|
||||||
zipStorePath=wrapper/dists
|
|
||||||
@@ -3,7 +3,6 @@
|
|||||||
com.gamemaker.game
|
com.gamemaker.game
|
||||||
-->
|
-->
|
||||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
package="com.dishii.mm"
|
|
||||||
android:versionCode="4"
|
android:versionCode="4"
|
||||||
android:versionName="1.1.1"
|
android:versionName="1.1.1"
|
||||||
android:installLocation="auto">
|
android:installLocation="auto">
|
||||||
@@ -54,8 +53,8 @@
|
|||||||
<!-- Allow access to the vibrator -->
|
<!-- Allow access to the vibrator -->
|
||||||
<uses-permission android:name="android.permission.VIBRATE" />
|
<uses-permission android:name="android.permission.VIBRATE" />
|
||||||
|
|
||||||
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
|
|
||||||
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
|
||||||
|
<uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE" />
|
||||||
|
|
||||||
<!-- if you want to capture audio, uncomment this. -->
|
<!-- if you want to capture audio, uncomment this. -->
|
||||||
<!-- <uses-permission android:name="android.permission.RECORD_AUDIO" /> -->
|
<!-- <uses-permission android:name="android.permission.RECORD_AUDIO" /> -->
|
||||||
@@ -73,7 +72,8 @@
|
|||||||
android:allowBackup="true"
|
android:allowBackup="true"
|
||||||
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
|
android:theme="@android:style/Theme.NoTitleBar.Fullscreen"
|
||||||
android:hardwareAccelerated="true"
|
android:hardwareAccelerated="true"
|
||||||
android:appCategory="game" >
|
android:appCategory="game"
|
||||||
|
android:requestLegacyExternalStorage="true">
|
||||||
|
|
||||||
|
|
||||||
<!-- Example of setting SDL hints from AndroidManifest.xml:
|
<!-- Example of setting SDL hints from AndroidManifest.xml:
|
||||||
@@ -84,7 +84,6 @@
|
|||||||
|
|
||||||
|
|
||||||
<activity android:name="MainActivity"
|
<activity android:name="MainActivity"
|
||||||
android:label="@string/app_name"
|
|
||||||
android:alwaysRetainTaskState="true"
|
android:alwaysRetainTaskState="true"
|
||||||
android:launchMode="singleInstance"
|
android:launchMode="singleInstance"
|
||||||
android:configChanges="layoutDirection|locale|orientation|uiMode|screenLayout|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation"
|
android:configChanges="layoutDirection|locale|orientation|uiMode|screenLayout|screenSize|smallestScreenSize|keyboard|keyboardHidden|navigation"
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
# Extractor Assets Copied by CMake during buildtime
|
# Extractor Assets Copied by CMake during buildtime
|
||||||
assets/
|
assets/
|
||||||
|
mods/
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ package com.dishii.mm;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.res.AssetManager;
|
import android.content.res.AssetManager;
|
||||||
|
import android.util.Log;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
@@ -9,53 +11,70 @@ import java.io.InputStream;
|
|||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
|
|
||||||
public class AssetCopyUtil {
|
public class AssetCopyUtil {
|
||||||
|
// based on https://stackoverflow.com/a/8366081/11708026
|
||||||
public static void copyAssetsToExternal(Context context, String assetsFolderPath, String externalFolderPath) throws IOException {
|
// This is desirable because it bulk copies all assets indiscriminately, simplifying the code in MainActivity
|
||||||
AssetManager assetManager = context.getAssets();
|
// the side effect is that, some people will see strange, unidentifiable files appearing in their destination folder.
|
||||||
String[] assetFiles = assetManager.list(assetsFolderPath);
|
// those extra files do not come from the app itself. They originate from something inside the Android ROM
|
||||||
|
// of the device they are using, and can be observed to vary between different models of devices.
|
||||||
for (String assetFile : assetFiles) {
|
public static void copyAssetsToExternal(Context context, String externalFolderPath) {
|
||||||
String assetPath = assetsFolderPath + File.separator + assetFile;
|
externalFolderPath = externalFolderPath + "/";
|
||||||
String externalPath = externalFolderPath + File.separator + assetFile;
|
copyFileOrDir(context, "", externalFolderPath); // copy all files in assets folder to the destination
|
||||||
|
|
||||||
if (assetManager.list(assetPath).length > 0) {
|
|
||||||
// It's a directory
|
|
||||||
// Check if the directory exists in the external storage
|
|
||||||
File externalDir = new File(externalPath);
|
|
||||||
if (!externalDir.exists()) {
|
|
||||||
externalDir.mkdirs(); // Create the directory if it doesn't exist
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Recursively copy contents of the directory
|
private static void copyFileOrDir(Context context, String srcpath, String destpath) {
|
||||||
copyAssetsToExternal(context, assetPath, externalPath);
|
AssetManager assetManager = context.getAssets();
|
||||||
|
String assets[] = null;
|
||||||
|
String tag = "AssetCopyUtil";
|
||||||
|
try {
|
||||||
|
Log.i(tag, "copyFileOrDir() " + srcpath);
|
||||||
|
assets = assetManager.list(srcpath);
|
||||||
|
if (assets.length == 0) {
|
||||||
|
copyFile(context, srcpath, destpath);
|
||||||
} else {
|
} else {
|
||||||
// It's a file
|
String fullPath = destpath + srcpath;
|
||||||
File externalFile = new File(externalPath);
|
Log.i(tag, "path=" + fullPath);
|
||||||
if (!externalFile.exists()) {
|
File dir = new File(fullPath);
|
||||||
// Check if the file exists in the external storage
|
if (!dir.exists())
|
||||||
|
if (!dir.mkdirs())
|
||||||
|
Log.i(tag, "could not create dir " + fullPath);
|
||||||
|
for (int i = 0; i < assets.length; ++i) {
|
||||||
|
String p;
|
||||||
|
if (srcpath.isEmpty())
|
||||||
|
p = "";
|
||||||
|
else
|
||||||
|
p = srcpath + "/";
|
||||||
|
copyFileOrDir(context,p + assets[i], destpath);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (IOException ex) {
|
||||||
|
Log.e(tag, "I/O Exception", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void copyFile(Context context, String filename, String destpath) {
|
||||||
|
AssetManager assetManager = context.getAssets();
|
||||||
InputStream in = null;
|
InputStream in = null;
|
||||||
OutputStream out = null;
|
OutputStream out = null;
|
||||||
|
String newFileName = null;
|
||||||
|
String tag = "AssetCopyUtil";
|
||||||
try {
|
try {
|
||||||
in = assetManager.open(assetPath);
|
Log.i(tag, "copyFile() " + filename);
|
||||||
out = new FileOutputStream(externalPath);
|
in = assetManager.open(filename);
|
||||||
|
newFileName = destpath + filename;
|
||||||
|
out = new FileOutputStream(newFileName);
|
||||||
byte[] buffer = new byte[1024];
|
byte[] buffer = new byte[1024];
|
||||||
int read;
|
int read;
|
||||||
while ((read = in.read(buffer)) != -1) {
|
while ((read = in.read(buffer)) != -1) {
|
||||||
out.write(buffer, 0, read);
|
out.write(buffer, 0, read);
|
||||||
}
|
}
|
||||||
|
|
||||||
} finally {
|
|
||||||
if (in != null) {
|
|
||||||
in.close();
|
in.close();
|
||||||
}
|
in = null;
|
||||||
if (out != null) {
|
out.flush();
|
||||||
out.close();
|
out.close();
|
||||||
}
|
out = null;
|
||||||
}
|
} catch (Exception e) {
|
||||||
}
|
Log.e(tag, "Exception in copyFile() of " + newFileName);
|
||||||
}
|
Log.e(tag, "Exception in copyFile() " + e.toString());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,20 +6,12 @@ import android.content.Context;
|
|||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
import android.provider.Settings;
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.io.OutputStream;
|
|
||||||
import java.io.FileOutputStream;
|
|
||||||
import android.Manifest;
|
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
import androidx.core.app.ActivityCompat;
|
|
||||||
import androidx.core.content.ContextCompat;
|
|
||||||
import android.util.Log;
|
|
||||||
|
|
||||||
|
import android.provider.Settings;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
import android.widget.Button;
|
import android.widget.Button;
|
||||||
import android.widget.FrameLayout;
|
import android.widget.FrameLayout;
|
||||||
@@ -28,28 +20,48 @@ import android.view.MotionEvent;
|
|||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.widget.ImageView;
|
import android.widget.ImageView;
|
||||||
|
|
||||||
//This class is the main SDLActivity and just sets up a bunch of default files and the input overlay
|
import java.io.File;
|
||||||
public class MainActivity extends SDLActivity{
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
|
import java.io.OutputStream;
|
||||||
|
|
||||||
private static final int STORAGE_PERMISSION_REQUEST_CODE = 1;
|
//This class is the main SDLActivity and just sets up a bunch of default files and the input overlay
|
||||||
|
public class MainActivity extends SDLActivity {
|
||||||
|
|
||||||
|
private static final int FILE_HANDLER_REQUEST_CODE = 0;
|
||||||
|
private static final int SPECIAL_STORAGE_PERMISSION_REQUEST_CODE = 1;
|
||||||
|
|
||||||
SharedPreferences preferences;
|
SharedPreferences preferences;
|
||||||
|
|
||||||
|
private boolean hasSpecialExternalStoragePermission = false;
|
||||||
|
|
||||||
|
private boolean permissionPopupIsOpen = false;
|
||||||
|
|
||||||
|
// this is a case where I feel like it is actually clearer to have a double negative boolean,
|
||||||
|
// than to have one named "permissionPopupChargeIsAvailable = true", but you can let me know
|
||||||
|
// if you would prefer to reorganize this.
|
||||||
|
private boolean permissionPopupWasDeclined = false;
|
||||||
|
|
||||||
|
private boolean hasInstalledExternalAssetFiles = false;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String[] getLibraries() {
|
||||||
|
return new String[] {
|
||||||
|
"SDL2",
|
||||||
|
"2ship"
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected void onCreate(Bundle savedInstanceState) {
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
preferences = getSharedPreferences("com.dishii.mm.prefs",Context.MODE_PRIVATE);
|
preferences = getSharedPreferences("com.dishii.mm.prefs", Context.MODE_PRIVATE);
|
||||||
|
|
||||||
|
doVersionCheck();
|
||||||
|
|
||||||
setupControllerOverlay();
|
setupControllerOverlay();
|
||||||
|
|
||||||
// Check if storage permissions are granted
|
|
||||||
if (hasStoragePermission()) {
|
|
||||||
doVersionCheck();
|
|
||||||
setupFiles();
|
|
||||||
} else {
|
|
||||||
requestStoragePermission();
|
|
||||||
}
|
|
||||||
attachController();
|
attachController();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,116 +70,108 @@ public class MainActivity extends SDLActivity{
|
|||||||
int storedVersion = preferences.getInt("appVersion", 1);
|
int storedVersion = preferences.getInt("appVersion", 1);
|
||||||
|
|
||||||
if (currentVersion > storedVersion) {
|
if (currentVersion > storedVersion) {
|
||||||
deleteOutdatedAssets();
|
// I tend to just copy all assets on every app launch, overwriting the old ones,
|
||||||
|
// so that I don't have to change appVersion every time I need to make sure that the newest assets
|
||||||
|
// are guaranteed to always be present. Also, when /storage/emulated/0/com.dishii.mm is used, the assets
|
||||||
|
// could be from a whole different version of the app and that wouldn't be detected (at least by this
|
||||||
|
// particular SharedPreferences), so my way always overwrites those.
|
||||||
|
// My way is also very slow to load at every startup, which is ok for
|
||||||
|
// apps that have only a few external assets, but for apps like this one that have
|
||||||
|
// a lot of external assets, the slowness is pretty severe. Let me know if that is not desirable
|
||||||
|
// and you would prefer it to work differently.
|
||||||
|
//deleteOutdatedAssets();
|
||||||
preferences.edit().putInt("appVersion", currentVersion).apply();
|
preferences.edit().putInt("appVersion", currentVersion).apply();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void deleteOutdatedAssets(){
|
// called from native code through JNI where necessary
|
||||||
File externalSohFile = new File(getExternalFilesDir(null), "2ship.o2r");
|
public String getExternalAssetsPath() {
|
||||||
externalSohFile.delete();
|
// the original location, /storage/emulated/0/Android/data/com.dishii.mm/files,
|
||||||
File externalOotFile = new File(getExternalFilesDir(null), "mm.o2r");
|
// can be the fallback if the user denies the permission
|
||||||
externalOotFile.delete();
|
String externalAssetsPath = getExternalFilesDir(null).getAbsolutePath();
|
||||||
File externalAssetsFolder = new File(getExternalFilesDir(null), "assets");
|
|
||||||
deleteRecursive(externalAssetsFolder);
|
|
||||||
|
|
||||||
|
if (!permissionPopupWasDeclined) {
|
||||||
|
requestSpecialExternalStoragePermission();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void deleteRecursive(File fileOrDirectory) {
|
while(permissionPopupIsOpen) {
|
||||||
if (fileOrDirectory.isDirectory()) {
|
// Do nothing until a permission is chosen
|
||||||
for (File child : fileOrDirectory.listFiles()) {
|
try {
|
||||||
deleteRecursive(child);
|
Thread.sleep(250);
|
||||||
|
} catch (InterruptedException e) {
|
||||||
|
// do nothing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
fileOrDirectory.delete();
|
|
||||||
|
if (hasSpecialExternalStoragePermission) {
|
||||||
|
// /storage/emulated/0/com.dishii.mm, also mounted at /sdcard/com.dishii.mm
|
||||||
|
externalAssetsPath = Environment.getExternalStorageDirectory().getAbsolutePath() + "/" + getApplicationContext().getPackageName();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!hasInstalledExternalAssetFiles) {
|
||||||
|
setupFiles(externalAssetsPath);
|
||||||
// Check if storage permission is granted
|
|
||||||
private boolean hasStoragePermission() {
|
|
||||||
return ContextCompat.checkSelfPermission(this, Manifest.permission.READ_EXTERNAL_STORAGE)
|
|
||||||
== PackageManager.PERMISSION_GRANTED &&
|
|
||||||
ContextCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
|
||||||
== PackageManager.PERMISSION_GRANTED;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Request storage permission
|
return externalAssetsPath;
|
||||||
private void requestStoragePermission() {
|
}
|
||||||
ActivityCompat.requestPermissions(this,
|
|
||||||
new String[]{Manifest.permission.READ_EXTERNAL_STORAGE,
|
// Request the special external storage permission
|
||||||
Manifest.permission.WRITE_EXTERNAL_STORAGE},
|
private void requestSpecialExternalStoragePermission() {
|
||||||
STORAGE_PERMISSION_REQUEST_CODE);
|
// Android 5 or older
|
||||||
|
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.LOLLIPOP_MR1) {
|
||||||
|
hasSpecialExternalStoragePermission = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Android 10 or older
|
||||||
|
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) {
|
||||||
|
if (checkSelfPermission("android.permission.WRITE_EXTERNAL_STORAGE") == PackageManager.PERMISSION_GRANTED) {
|
||||||
|
hasSpecialExternalStoragePermission = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
requestPermissions(new String[]{"android.permission.WRITE_EXTERNAL_STORAGE"}, SPECIAL_STORAGE_PERMISSION_REQUEST_CODE);
|
||||||
|
permissionPopupIsOpen = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Android 11 or newer
|
||||||
|
if (Environment.isExternalStorageManager()) {
|
||||||
|
hasSpecialExternalStoragePermission = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
Intent intent = new Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION);
|
||||||
|
intent.addCategory("android.intent.category.DEFAULT");
|
||||||
|
intent.setData(Uri.parse(String.format("package:%s", getApplicationContext().getPackageName())));
|
||||||
|
startActivityForResult(intent, SPECIAL_STORAGE_PERMISSION_REQUEST_CODE);
|
||||||
|
} catch (Exception e) {
|
||||||
|
Intent intent = new Intent();
|
||||||
|
intent.setAction(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION);
|
||||||
|
startActivityForResult(intent, SPECIAL_STORAGE_PERMISSION_REQUEST_CODE);
|
||||||
|
}
|
||||||
|
|
||||||
|
permissionPopupIsOpen = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Handle permission request result
|
// Handle permission request result
|
||||||
@Override
|
@Override
|
||||||
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
||||||
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
|
||||||
if (requestCode == STORAGE_PERMISSION_REQUEST_CODE) {
|
if (requestCode == SPECIAL_STORAGE_PERMISSION_REQUEST_CODE) {
|
||||||
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
|
||||||
setupFiles();
|
hasSpecialExternalStoragePermission = true;
|
||||||
} else {
|
} else {
|
||||||
// Permission denied, handle accordingly (e.g., show a message)
|
permissionPopupWasDeclined = true;
|
||||||
}
|
}
|
||||||
|
permissionPopupIsOpen = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setupFiles(){
|
private void setupFiles(String externalAssetsPath) {
|
||||||
//Copy assets folder for rom extraction
|
AssetCopyUtil.copyAssetsToExternal(this, externalAssetsPath);
|
||||||
File externalAssetsDir = new File(getExternalFilesDir(null), "assets");
|
hasInstalledExternalAssetFiles = true;
|
||||||
if (!externalAssetsDir.exists()) {
|
|
||||||
try {
|
|
||||||
externalAssetsDir.mkdirs();
|
|
||||||
AssetCopyUtil.copyAssetsToExternal(this, "assets", externalAssetsDir.getAbsolutePath());
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//Create empty mods folder
|
|
||||||
File externalModsDir = new File(getExternalFilesDir(null), "mods");
|
|
||||||
externalModsDir.mkdirs();
|
|
||||||
|
|
||||||
//Copy 2ship.o2r
|
|
||||||
File externalSohOtrFile = new File(getExternalFilesDir(null), "2ship.o2r");
|
|
||||||
if (!externalSohOtrFile.exists()) {
|
|
||||||
try {
|
|
||||||
InputStream in = getAssets().open("2ship.o2r");
|
|
||||||
OutputStream out = new FileOutputStream(externalSohOtrFile);
|
|
||||||
|
|
||||||
byte[] buffer = new byte[1024];
|
|
||||||
int read;
|
|
||||||
while ((read = in.read(buffer)) != -1) {
|
|
||||||
out.write(buffer, 0, read);
|
|
||||||
}
|
|
||||||
|
|
||||||
in.close();
|
|
||||||
out.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
File configFile = new File(getExternalFilesDir(null), "2ship2harkinian.json");
|
|
||||||
if (!configFile.exists()) {
|
|
||||||
try {
|
|
||||||
InputStream in = getAssets().open("2ship2harkinian.json");
|
|
||||||
OutputStream out = new FileOutputStream(configFile);
|
|
||||||
|
|
||||||
byte[] buffer = new byte[1024];
|
|
||||||
int read;
|
|
||||||
while ((read = in.read(buffer)) != -1) {
|
|
||||||
out.write(buffer, 0, read);
|
|
||||||
}
|
|
||||||
|
|
||||||
in.close();
|
|
||||||
out.close();
|
|
||||||
} catch (IOException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private native void nativeHandleSelectedFile(String filePath);
|
private native void nativeHandleSelectedFile(String filePath);
|
||||||
@@ -175,10 +179,11 @@ public class MainActivity extends SDLActivity{
|
|||||||
@Override
|
@Override
|
||||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
if (requestCode == 0 && resultCode == RESULT_OK) {
|
|
||||||
|
if (requestCode == FILE_HANDLER_REQUEST_CODE && resultCode == RESULT_OK) {
|
||||||
Uri selectedFileUri = data.getData();
|
Uri selectedFileUri = data.getData();
|
||||||
String fileName = "MM.z64";
|
String fileName = "MM.z64";
|
||||||
File destinationDirectory = getExternalFilesDir(null); // The second argument can specify a subdirectory, or you can pass null to use the root directory.
|
String destinationDirectory = getExternalAssetsPath();
|
||||||
File destinationFile = new File(destinationDirectory, fileName);
|
File destinationFile = new File(destinationDirectory, fileName);
|
||||||
|
|
||||||
if (destinationDirectory != null) {
|
if (destinationDirectory != null) {
|
||||||
@@ -200,8 +205,20 @@ public class MainActivity extends SDLActivity{
|
|||||||
}
|
}
|
||||||
nativeHandleSelectedFile(destinationFile.getPath());
|
nativeHandleSelectedFile(destinationFile.getPath());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (requestCode == SPECIAL_STORAGE_PERMISSION_REQUEST_CODE) {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R /* Android 11 or newer */) {
|
||||||
|
if (Environment.isExternalStorageManager()) {
|
||||||
|
hasSpecialExternalStoragePermission = true;
|
||||||
|
} else {
|
||||||
|
permissionPopupWasDeclined = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
permissionPopupIsOpen = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// called from native code through JNI where necessary
|
||||||
public void openFilePicker() {
|
public void openFilePicker() {
|
||||||
// Create an Intent to open the file picker dialog
|
// Create an Intent to open the file picker dialog
|
||||||
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
|
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT);
|
||||||
@@ -211,14 +228,8 @@ public class MainActivity extends SDLActivity{
|
|||||||
startActivityForResult(intent, 0);
|
startActivityForResult(intent, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if external storage is available and writable
|
|
||||||
private boolean isExternalStorageWritable() {
|
|
||||||
String state = Environment.getExternalStorageState();
|
|
||||||
return Environment.MEDIA_MOUNTED.equals(state);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public native void attachController();
|
public native void attachController();
|
||||||
|
public native void detachController();
|
||||||
// Native method for setting button state
|
// Native method for setting button state
|
||||||
public native void setButton(int button, boolean value);
|
public native void setButton(int button, boolean value);
|
||||||
public native void setCameraState(int axis, float value);
|
public native void setCameraState(int axis, float value);
|
||||||
@@ -284,10 +295,10 @@ public class MainActivity extends SDLActivity{
|
|||||||
addTouchListener(buttonX, ControllerButtons.BUTTON_X); // SDL Button 2 (X)
|
addTouchListener(buttonX, ControllerButtons.BUTTON_X); // SDL Button 2 (X)
|
||||||
addTouchListener(buttonY, ControllerButtons.BUTTON_Y); // SDL Button 3 (Y)
|
addTouchListener(buttonY, ControllerButtons.BUTTON_Y); // SDL Button 3 (Y)
|
||||||
|
|
||||||
addTouchListener(buttonDpadUp, ControllerButtons.BUTTON_DPAD_UP); // SDL Button 10 (D-Pad Up)
|
setupCButtons(buttonDpadUp, ControllerButtons.AXIS_RY, 1); // SDL Button 10 (D-Pad Up)
|
||||||
addTouchListener(buttonDpadDown, ControllerButtons.BUTTON_DPAD_DOWN); // SDL Button 11 (D-Pad Down)
|
setupCButtons(buttonDpadDown, ControllerButtons.AXIS_RY , -1); // SDL Button 11 (D-Pad Down)
|
||||||
addTouchListener(buttonDpadLeft, ControllerButtons.BUTTON_DPAD_LEFT); // SDL Button 12 (D-Pad Left)
|
setupCButtons(buttonDpadLeft, ControllerButtons.AXIS_RX, 1); // SDL Button 12 (D-Pad Left)
|
||||||
addTouchListener(buttonDpadRight, ControllerButtons.BUTTON_DPAD_RIGHT); // SDL Button 13 (D-Pad Right)
|
setupCButtons(buttonDpadRight, ControllerButtons.AXIS_RX, -1); // SDL Button 13 (D-Pad Right)
|
||||||
|
|
||||||
addTouchListener(buttonLB, ControllerButtons.BUTTON_LB); // SDL Button 4 (LB)
|
addTouchListener(buttonLB, ControllerButtons.BUTTON_LB); // SDL Button 4 (LB)
|
||||||
addTouchListener(buttonRB, ControllerButtons.BUTTON_RB); // SDL Button 5 (RB)
|
addTouchListener(buttonRB, ControllerButtons.BUTTON_RB); // SDL Button 5 (RB)
|
||||||
@@ -309,14 +320,19 @@ public class MainActivity extends SDLActivity{
|
|||||||
private void setupToggleButton(Button button, ViewGroup uiGroup){
|
private void setupToggleButton(Button button, ViewGroup uiGroup){
|
||||||
boolean isHidden = preferences.getBoolean("controlsVisible", false); // Default to 'false' (visible)
|
boolean isHidden = preferences.getBoolean("controlsVisible", false); // Default to 'false' (visible)
|
||||||
uiGroup.setVisibility(isHidden ? View.INVISIBLE : View.VISIBLE); // Set the initial visibility based on the saved state
|
uiGroup.setVisibility(isHidden ? View.INVISIBLE : View.VISIBLE); // Set the initial visibility based on the saved state
|
||||||
|
/*if(isHidden){
|
||||||
|
detachController();
|
||||||
|
}*/
|
||||||
button.setOnClickListener(new View.OnClickListener() {
|
button.setOnClickListener(new View.OnClickListener() {
|
||||||
boolean isHidden = false;
|
boolean isHidden = false;
|
||||||
@Override
|
@Override
|
||||||
public void onClick(View v) {
|
public void onClick(View v) {
|
||||||
if (isHidden) {
|
if (isHidden) {
|
||||||
uiGroup.setVisibility(View.VISIBLE); // Show UI elements
|
uiGroup.setVisibility(View.VISIBLE); // Show UI elements
|
||||||
|
//attachController();
|
||||||
} else {
|
} else {
|
||||||
uiGroup.setVisibility(View.INVISIBLE); // Hide UI elements
|
uiGroup.setVisibility(View.INVISIBLE); // Hide UI elements
|
||||||
|
//detachController();
|
||||||
}
|
}
|
||||||
preferences.edit().putBoolean("controlsVisible", !isHidden).apply();
|
preferences.edit().putBoolean("controlsVisible", !isHidden).apply();
|
||||||
isHidden = !isHidden; // Toggle state
|
isHidden = !isHidden; // Toggle state
|
||||||
@@ -347,6 +363,28 @@ public class MainActivity extends SDLActivity{
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setupCButtons(Button button, int buttonNum, int direction) {
|
||||||
|
button.setOnTouchListener(new View.OnTouchListener() {
|
||||||
|
@Override
|
||||||
|
public boolean onTouch(View v, MotionEvent event) {
|
||||||
|
switch (event.getAction()) {
|
||||||
|
case MotionEvent.ACTION_DOWN:
|
||||||
|
setAxis(buttonNum, direction<0 ? Short.MAX_VALUE : Short.MIN_VALUE);
|
||||||
|
button.setPressed(true);
|
||||||
|
return true;
|
||||||
|
case MotionEvent.ACTION_UP:
|
||||||
|
setAxis(buttonNum, (short) 0);
|
||||||
|
button.setPressed(false);
|
||||||
|
return true;
|
||||||
|
case MotionEvent.ACTION_CANCEL:
|
||||||
|
setAxis(buttonNum, (short) 0);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
boolean TouchAreaEnabled = true;
|
boolean TouchAreaEnabled = true;
|
||||||
|
|
||||||
void DisableTouchArea(){
|
void DisableTouchArea(){
|
||||||
|
|||||||
@@ -60,8 +60,8 @@ import java.util.Locale;
|
|||||||
public class SDLActivity extends Activity implements View.OnSystemUiVisibilityChangeListener {
|
public class SDLActivity extends Activity implements View.OnSystemUiVisibilityChangeListener {
|
||||||
private static final String TAG = "SDL";
|
private static final String TAG = "SDL";
|
||||||
private static final int SDL_MAJOR_VERSION = 2;
|
private static final int SDL_MAJOR_VERSION = 2;
|
||||||
private static final int SDL_MINOR_VERSION = 30;
|
private static final int SDL_MINOR_VERSION = 32;
|
||||||
private static final int SDL_MICRO_VERSION = 5;
|
private static final int SDL_MICRO_VERSION = 0;
|
||||||
/*
|
/*
|
||||||
// Display InputType.SOURCE/CLASS of events and devices
|
// Display InputType.SOURCE/CLASS of events and devices
|
||||||
//
|
//
|
||||||
@@ -89,7 +89,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
|||||||
| InputDevice.SOURCE_CLASS_POSITION
|
| InputDevice.SOURCE_CLASS_POSITION
|
||||||
| InputDevice.SOURCE_CLASS_TRACKBALL);
|
| InputDevice.SOURCE_CLASS_TRACKBALL);
|
||||||
|
|
||||||
if (s2 != 0) cls += "Some_Unkown";
|
if (s2 != 0) cls += "Some_Unknown";
|
||||||
|
|
||||||
s2 = s_copy & InputDevice.SOURCE_ANY; // keep source only, no class;
|
s2 = s_copy & InputDevice.SOURCE_ANY; // keep source only, no class;
|
||||||
|
|
||||||
@@ -163,7 +163,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
|||||||
if (s == FLAG_TAINTED) src += " FLAG_TAINTED";
|
if (s == FLAG_TAINTED) src += " FLAG_TAINTED";
|
||||||
s2 &= ~FLAG_TAINTED;
|
s2 &= ~FLAG_TAINTED;
|
||||||
|
|
||||||
if (s2 != 0) src += " Some_Unkown";
|
if (s2 != 0) src += " Some_Unknown";
|
||||||
|
|
||||||
Log.v(TAG, prefix + "int=" + s_copy + " CLASS={" + cls + " } source(s):" + src);
|
Log.v(TAG, prefix + "int=" + s_copy + " CLASS={" + cls + " } source(s):" + src);
|
||||||
}
|
}
|
||||||
@@ -274,7 +274,7 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
|||||||
// "SDL2_mixer",
|
// "SDL2_mixer",
|
||||||
// "SDL2_net",
|
// "SDL2_net",
|
||||||
// "SDL2_ttf",
|
// "SDL2_ttf",
|
||||||
"2ship"
|
"main"
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -790,6 +790,9 @@ public class SDLActivity extends Activity implements View.OnSystemUiVisibilityCh
|
|||||||
window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
window.clearFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||||
SDLActivity.mFullscreenModeActive = false;
|
SDLActivity.mFullscreenModeActive = false;
|
||||||
}
|
}
|
||||||
|
if (Build.VERSION.SDK_INT >= 28 /* Android 9 (Pie) */) {
|
||||||
|
window.getAttributes().layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
Log.e(TAG, "error handling message, getContext() returned no Activity");
|
Log.e(TAG, "error handling message, getContext() returned no Activity");
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ buildscript {
|
|||||||
google()
|
google()
|
||||||
}
|
}
|
||||||
dependencies {
|
dependencies {
|
||||||
classpath 'com.android.tools.build:gradle:7.0.3'
|
classpath 'com.android.tools.build:gradle:8.8.0'
|
||||||
|
|
||||||
// NOTE: Do not place your application dependencies here; they belong
|
// NOTE: Do not place your application dependencies here; they belong
|
||||||
// in the individual module build.gradle files
|
// in the individual module build.gradle files
|
||||||
@@ -20,6 +20,6 @@ allprojects {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
task clean(type: Delete) {
|
tasks.register('clean', Delete) {
|
||||||
delete rootProject.buildDir
|
delete rootProject.buildDir
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -18,3 +18,8 @@ org.gradle.jvmargs=-Xmx1536m
|
|||||||
# org.gradle.parallel=true
|
# org.gradle.parallel=true
|
||||||
|
|
||||||
android.useAndroidX=true
|
android.useAndroidX=true
|
||||||
|
android.nonTransitiveRClass=false
|
||||||
|
android.nonFinalResIds=false
|
||||||
|
|
||||||
|
# set to Release or RelWithDebInfo to avoid slow mm.o2r generation
|
||||||
|
elfBuildType=Debug
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
#Thu Nov 11 18:20:34 PST 2021
|
#Thu Nov 11 18:20:34 PST 2021
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.2-bin.zip
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
|||||||
@@ -148,6 +148,8 @@ file(COPY "${CMAKE_SOURCE_DIR}/OTRExporter/CFG/filelists/" DESTINATION "${CMAKE_
|
|||||||
file(COPY "${CMAKE_SOURCE_DIR}/OTRExporter/CFG/ActorList_MM.txt" DESTINATION "${CMAKE_SOURCE_DIR}/Android/app/src/main/assets/assets/extractor/symbols")
|
file(COPY "${CMAKE_SOURCE_DIR}/OTRExporter/CFG/ActorList_MM.txt" DESTINATION "${CMAKE_SOURCE_DIR}/Android/app/src/main/assets/assets/extractor/symbols")
|
||||||
file(COPY "${CMAKE_SOURCE_DIR}/OTRExporter/CFG/ObjectList_MM.txt" DESTINATION "${CMAKE_SOURCE_DIR}/Android/app/src/main/assets/assets/extractor/symbols")
|
file(COPY "${CMAKE_SOURCE_DIR}/OTRExporter/CFG/ObjectList_MM.txt" DESTINATION "${CMAKE_SOURCE_DIR}/Android/app/src/main/assets/assets/extractor/symbols")
|
||||||
file(COPY "${CMAKE_SOURCE_DIR}/OTRExporter/CFG/SymbolMap_MM.txt" DESTINATION "${CMAKE_SOURCE_DIR}/Android/app/src/main/assets/assets/extractor/symbols")
|
file(COPY "${CMAKE_SOURCE_DIR}/OTRExporter/CFG/SymbolMap_MM.txt" DESTINATION "${CMAKE_SOURCE_DIR}/Android/app/src/main/assets/assets/extractor/symbols")
|
||||||
|
file(MAKE_DIRECTORY "${CMAKE_SOURCE_DIR}/Android/app/src/main/assets/mods")
|
||||||
|
file(TOUCH "${CMAKE_SOURCE_DIR}/Android/app/src/main/assets/mods/custom_mod_files_go_here.txt")
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,8 +4,6 @@ A port of 2 Ship 2 Harkinian to Android. <br>
|
|||||||
Original Repository: https://github.com/HarbourMasters/2ship2harkinian <br>
|
Original Repository: https://github.com/HarbourMasters/2ship2harkinian <br>
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
NOTE: Controller only. No touch controls yet except for in the enhancements menu. <br>
|
|
||||||
|
|
||||||
Supported (probably): Android 7+ (OpenGL ES 3.0+ required) <br>
|
Supported (probably): Android 7+ (OpenGL ES 3.0+ required) <br>
|
||||||
Tested On: Android 14 <br>
|
Tested On: Android 14 <br>
|
||||||
|
|
||||||
@@ -32,7 +30,7 @@ Q: The GUI scaling is too big/too small. <br>
|
|||||||
A: There is no GUI scaling option implemented yet. This will come in a future update. <br><br>
|
A: There is no GUI scaling option implemented yet. This will come in a future update. <br><br>
|
||||||
|
|
||||||
Q: Gyro Aim? <br>
|
Q: Gyro Aim? <br>
|
||||||
A: It will come once it works in the base 2 Ship 2 Harkinian. <br> <br>
|
A: It works. You just need to press any controller button when it asks for input. It will default to your phone's gyro if the controller doesn't support it. <br> <br>
|
||||||
|
|
||||||
Q: My controller is not doing anything. <br>
|
Q: My controller is not doing anything. <br>
|
||||||
A: Close the Enhancements Menu. If the Enhancements Menu is not open, open it with the Android back button and check if it is detected in Settings->Controller->Controller Mapping. If it is, press refresh. <br><br>
|
A: Close the Enhancements Menu. If the Enhancements Menu is not open, open it with the Android back button and check if it is detected in Settings->Controller->Controller Mapping. If it is, press refresh. <br><br>
|
||||||
|
|||||||
+1
-1
Submodule libultraship updated: 2860d3df9c...1799c5f863
@@ -101,8 +101,8 @@ bool Camera_FreeLook(Camera* camera) {
|
|||||||
|
|
||||||
#ifdef __ANDROID__
|
#ifdef __ANDROID__
|
||||||
if(Ship::Mobile::IsUsingTouchscreenControls()) {
|
if(Ship::Mobile::IsUsingTouchscreenControls()) {
|
||||||
yawDiff = -Ship::Mobile::GetCameraYaw()*10.0f;
|
yawDiff += -Ship::Mobile::GetCameraYaw()*10.0f;
|
||||||
pitchDiff = Ship::Mobile::GetCameraPitch()*10.0f;
|
pitchDiff += Ship::Mobile::GetCameraPitch()*10.0f;
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ enum class ButtonId : int {
|
|||||||
|
|
||||||
#ifdef __ANDROID__
|
#ifdef __ANDROID__
|
||||||
|
|
||||||
const char* javaRomPath = NULL;
|
static char javaRomPath[4096] = { 0 };
|
||||||
bool fileDialogOpen = false;
|
bool fileDialogOpen = false;
|
||||||
|
|
||||||
//function to be called from C
|
//function to be called from C
|
||||||
@@ -92,7 +92,7 @@ void openFilePickerFromC(JNIEnv* env, jobject javaObject) {
|
|||||||
// Define the native method to handle the selected file path
|
// Define the native method to handle the selected file path
|
||||||
extern "C" void JNICALL Java_com_dishii_mm_MainActivity_nativeHandleSelectedFile(JNIEnv* env, jobject obj, jstring filePath) {
|
extern "C" void JNICALL Java_com_dishii_mm_MainActivity_nativeHandleSelectedFile(JNIEnv* env, jobject obj, jstring filePath) {
|
||||||
const char* filePathStr = env->GetStringUTFChars(filePath, 0);
|
const char* filePathStr = env->GetStringUTFChars(filePath, 0);
|
||||||
javaRomPath = strdup(filePathStr); // save filepath to string
|
snprintf(javaRomPath, sizeof(javaRomPath), "%s", filePathStr);
|
||||||
fileDialogOpen = false;
|
fileDialogOpen = false;
|
||||||
env->ReleaseStringUTFChars(filePath, filePathStr);
|
env->ReleaseStringUTFChars(filePath, filePathStr);
|
||||||
}
|
}
|
||||||
@@ -322,7 +322,7 @@ bool Extractor::GetRomPathFromBox() {
|
|||||||
//Do nothing until it's chosen
|
//Do nothing until it's chosen
|
||||||
SDL_Delay(250);
|
SDL_Delay(250);
|
||||||
}
|
}
|
||||||
SDL_Log("%s",javaRomPath);
|
SDL_Log("javaRomPath: %s", javaRomPath);
|
||||||
selection.push_back(javaRomPath);
|
selection.push_back(javaRomPath);
|
||||||
#endif
|
#endif
|
||||||
if (selection.empty()) {
|
if (selection.empty()) {
|
||||||
@@ -332,12 +332,6 @@ bool Extractor::GetRomPathFromBox() {
|
|||||||
mCurrentRomPath = selection[0];
|
mCurrentRomPath = selection[0];
|
||||||
#endif
|
#endif
|
||||||
mCurRomSize = GetCurRomSize();
|
mCurRomSize = GetCurRomSize();
|
||||||
#ifdef __ANDROID__
|
|
||||||
if (javaRomPath) {
|
|
||||||
free((void*)javaRomPath);
|
|
||||||
javaRomPath = NULL;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user