Android: latest bugfixes and features (#39)
Co-authored-by: Maksim <MoNTE48@mail.ua>
This commit is contained in:
parent
e03170fb77
commit
db273c4645
@ -2,13 +2,13 @@ apply plugin: 'com.android.application'
|
||||
apply plugin: 'kotlin-android'
|
||||
|
||||
android {
|
||||
compileSdkVersion 31
|
||||
buildToolsVersion '31.0.0'
|
||||
compileSdkVersion 32
|
||||
buildToolsVersion '32.0.0'
|
||||
ndkVersion '23.1.7779620'
|
||||
defaultConfig {
|
||||
applicationId 'com.multicraft.game'
|
||||
minSdkVersion 19
|
||||
targetSdkVersion 31
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 32
|
||||
versionName "${versionMajor}.${versionMinor}.${versionPatch}"
|
||||
versionCode project.versionCode
|
||||
}
|
||||
@ -135,9 +135,9 @@ dependencies {
|
||||
implementation project(':native')
|
||||
|
||||
/* Third-party libraries */
|
||||
implementation 'androidx.appcompat:appcompat:1.4.0'
|
||||
implementation 'androidx.appcompat:appcompat-resources:1.4.0'
|
||||
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.0'
|
||||
implementation 'androidx.appcompat:appcompat:1.4.1'
|
||||
implementation 'androidx.appcompat:appcompat-resources:1.4.1'
|
||||
implementation 'androidx.lifecycle:lifecycle-runtime-ktx:2.4.1'
|
||||
implementation 'androidx.work:work-runtime-ktx:2.7.1'
|
||||
implementation 'com.google.android.material:material:1.4.0'
|
||||
implementation 'com.google.android.material:material:1.5.0'
|
||||
}
|
||||
|
@ -25,7 +25,6 @@ import static android.text.InputType.TYPE_CLASS_TEXT;
|
||||
import static android.text.InputType.TYPE_TEXT_FLAG_MULTI_LINE;
|
||||
import static android.text.InputType.TYPE_TEXT_VARIATION_PASSWORD;
|
||||
import static com.multicraft.game.helpers.Utilities.finishApp;
|
||||
import static com.multicraft.game.helpers.Utilities.getTotalMem;
|
||||
import static com.multicraft.game.helpers.Utilities.makeFullScreen;
|
||||
|
||||
import android.app.NativeActivity;
|
||||
@ -104,7 +103,6 @@ public class GameActivity extends NativeActivity {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void showDialog(String s, String hint, String current, int editType) {
|
||||
runOnUiThread(() -> showDialogUI(hint, current, editType));
|
||||
}
|
||||
@ -164,7 +162,6 @@ public class GameActivity extends NativeActivity {
|
||||
return messageReturnCode;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public String getDialogValue() {
|
||||
messageReturnCode = -1;
|
||||
return messageReturnValue;
|
||||
@ -174,10 +171,6 @@ public class GameActivity extends NativeActivity {
|
||||
return getResources().getDisplayMetrics().density;
|
||||
}
|
||||
|
||||
public float getMemoryMax() {
|
||||
return getTotalMem(this);
|
||||
}
|
||||
|
||||
public void notifyServerConnect(boolean multiplayer) {
|
||||
isMultiPlayer = multiplayer;
|
||||
}
|
||||
@ -185,7 +178,6 @@ public class GameActivity extends NativeActivity {
|
||||
public void notifyExitGame() {
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void openURI(String uri) {
|
||||
try {
|
||||
Intent browserIntent = new Intent(Intent.ACTION_VIEW, Uri.parse(uri));
|
||||
@ -194,12 +186,13 @@ public class GameActivity extends NativeActivity {
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void finishGame(String exc) {
|
||||
finishApp(true, this);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public void handleError(String exc) {
|
||||
}
|
||||
|
||||
public void upgrade(String item) {
|
||||
}
|
||||
}
|
||||
|
@ -20,9 +20,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
|
||||
package com.multicraft.game
|
||||
|
||||
import android.content.DialogInterface
|
||||
import android.content.Intent
|
||||
import android.content.SharedPreferences
|
||||
import android.content.*
|
||||
import android.graphics.Color
|
||||
import android.graphics.drawable.LayerDrawable
|
||||
import android.os.Bundle
|
||||
@ -34,9 +32,7 @@ import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.graphics.BlendModeColorFilterCompat
|
||||
import androidx.core.graphics.BlendModeCompat
|
||||
import androidx.lifecycle.Observer
|
||||
import androidx.lifecycle.ViewModelProvider
|
||||
import androidx.lifecycle.lifecycleScope
|
||||
import androidx.lifecycle.*
|
||||
import androidx.work.WorkInfo
|
||||
import com.multicraft.game.databinding.ActivityMainBinding
|
||||
import com.multicraft.game.helpers.Constants.NO_SPACE_LEFT
|
||||
@ -51,10 +47,10 @@ import com.multicraft.game.helpers.PreferenceHelper.getStringValue
|
||||
import com.multicraft.game.helpers.PreferenceHelper.set
|
||||
import com.multicraft.game.helpers.Utilities.addShortcut
|
||||
import com.multicraft.game.helpers.Utilities.copyInputStreamToFile
|
||||
import com.multicraft.game.helpers.Utilities.finishApp
|
||||
import com.multicraft.game.helpers.Utilities.getIcon
|
||||
import com.multicraft.game.helpers.Utilities.isConnected
|
||||
import com.multicraft.game.helpers.Utilities.makeFullScreen
|
||||
import com.multicraft.game.helpers.Utilities.showRestartDialog
|
||||
import com.multicraft.game.workmanager.UnzipWorker.Companion.PROGRESS
|
||||
import com.multicraft.game.workmanager.WorkerViewModel
|
||||
import com.multicraft.game.workmanager.WorkerViewModelFactory
|
||||
@ -75,17 +71,14 @@ class MainActivity : AppCompatActivity() {
|
||||
binding = ActivityMainBinding.inflate(layoutInflater)
|
||||
setContentView(binding.root)
|
||||
prefs = PreferenceHelper.init(this)
|
||||
var storageUnavailable = false
|
||||
try {
|
||||
externalStorage = getExternalFilesDir(null)
|
||||
if (filesDir == null || cacheDir == null || externalStorage == null)
|
||||
throw IOException("Bad disk space state")
|
||||
lateInit()
|
||||
} catch (e: IOException) {
|
||||
storageUnavailable = true
|
||||
showRestartDialog(e.message!!.contains(NO_SPACE_LEFT))
|
||||
showRestartDialog(this, !e.message!!.contains(NO_SPACE_LEFT))
|
||||
}
|
||||
if (storageUnavailable) return
|
||||
lateInit()
|
||||
}
|
||||
|
||||
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
|
||||
@ -153,7 +146,7 @@ class MainActivity : AppCompatActivity() {
|
||||
startActivity(intent)
|
||||
} else {
|
||||
prefs[TAG_BUILD_VER] = "0"
|
||||
showRestartDialog(false)
|
||||
showRestartDialog(this)
|
||||
}
|
||||
}
|
||||
|
||||
@ -180,11 +173,20 @@ class MainActivity : AppCompatActivity() {
|
||||
File(cacheDir, it).copyInputStreamToFile(input)
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
runOnUiThread { showRestartDialog(e.message!!.contains(NO_SPACE_LEFT)) }
|
||||
runOnUiThread {
|
||||
showRestartDialog(
|
||||
this@MainActivity,
|
||||
!e.message!!.contains(NO_SPACE_LEFT)
|
||||
)
|
||||
}
|
||||
return@forEach
|
||||
}
|
||||
}
|
||||
startUnzipWorker(zips)
|
||||
try {
|
||||
startUnzipWorker(zips)
|
||||
} catch (e: Exception) {
|
||||
runOnUiThread { showRestartDialog(this@MainActivity) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -219,7 +221,7 @@ class MainActivity : AppCompatActivity() {
|
||||
|
||||
if (workInfo.state.isFinished) {
|
||||
if (workInfo.state == WorkInfo.State.FAILED) {
|
||||
showRestartDialog(false)
|
||||
showRestartDialog(this)
|
||||
} else if (workInfo.state == WorkInfo.State.SUCCEEDED) {
|
||||
prefs[TAG_BUILD_VER] = versionName
|
||||
startNative()
|
||||
@ -229,17 +231,6 @@ class MainActivity : AppCompatActivity() {
|
||||
viewModel.startOneTimeWorkRequest()
|
||||
}
|
||||
|
||||
private fun showRestartDialog(space: Boolean) {
|
||||
val message = if (space) getString(R.string.no_space) else getString(R.string.restart)
|
||||
val builder = AlertDialog.Builder(this)
|
||||
builder.setMessage(message)
|
||||
.setPositiveButton(R.string.ok) { _, _ -> finishApp(!space, this) }
|
||||
.setCancelable(false)
|
||||
val dialog = builder.create()
|
||||
makeFullScreen(dialog.window!!)
|
||||
if (!isFinishing) dialog.show()
|
||||
}
|
||||
|
||||
// connection dialog
|
||||
private fun showConnectionDialog() {
|
||||
val builder = AlertDialog.Builder(this)
|
||||
|
@ -26,9 +26,9 @@ import android.os.Build.VERSION_CODES.*
|
||||
object ApiLevelHelper {
|
||||
private fun isGreaterOrEqual(versionCode: Int) = SDK_INT >= versionCode
|
||||
|
||||
fun isLollipop() = isGreaterOrEqual(LOLLIPOP)
|
||||
|
||||
fun isMarshmallow() = isGreaterOrEqual(M)
|
||||
|
||||
fun isOreo() = isGreaterOrEqual(O)
|
||||
|
||||
fun isAndroid12() = isGreaterOrEqual(S)
|
||||
}
|
||||
|
@ -20,11 +20,12 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
|
||||
package com.multicraft.game.helpers
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.app.Activity
|
||||
import android.app.ActivityManager
|
||||
import android.app.AlarmManager
|
||||
import android.app.PendingIntent
|
||||
import android.app.PendingIntent.FLAG_CANCEL_CURRENT
|
||||
import android.app.PendingIntent.FLAG_IMMUTABLE
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
@ -32,8 +33,8 @@ import android.graphics.Bitmap
|
||||
import android.graphics.drawable.BitmapDrawable
|
||||
import android.net.ConnectivityManager
|
||||
import android.net.NetworkCapabilities.NET_CAPABILITY_VALIDATED
|
||||
import android.view.View
|
||||
import android.view.Window
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
import androidx.appcompat.app.AppCompatActivity
|
||||
import androidx.core.content.ContextCompat
|
||||
import androidx.core.view.WindowCompat
|
||||
@ -43,41 +44,24 @@ import androidx.core.view.WindowInsetsControllerCompat
|
||||
import androidx.core.view.WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
||||
import com.multicraft.game.MainActivity
|
||||
import com.multicraft.game.R
|
||||
import com.multicraft.game.helpers.ApiLevelHelper.isLollipop
|
||||
import com.multicraft.game.databinding.RestartDialogBinding
|
||||
import com.multicraft.game.helpers.ApiLevelHelper.isAndroid12
|
||||
import com.multicraft.game.helpers.ApiLevelHelper.isMarshmallow
|
||||
import com.multicraft.game.helpers.ApiLevelHelper.isOreo
|
||||
import com.multicraft.game.helpers.PreferenceHelper.TAG_SHORTCUT_EXIST
|
||||
import com.multicraft.game.helpers.PreferenceHelper.set
|
||||
import java.io.File
|
||||
import java.io.InputStream
|
||||
import kotlin.math.roundToInt
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
object Utilities {
|
||||
|
||||
@JvmStatic
|
||||
fun getTotalMem(context: Context): Float {
|
||||
val actManager = context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
|
||||
val memInfo = ActivityManager.MemoryInfo()
|
||||
actManager.getMemoryInfo(memInfo)
|
||||
var memory = memInfo.totalMem * 1.0f / (1024 * 1024 * 1024)
|
||||
memory = (memory * 100).roundToInt() / 100.0f
|
||||
return memory
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun makeFullScreen(window: Window) {
|
||||
if (isLollipop()) {
|
||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||
WindowInsetsControllerCompat(window, window.decorView).let {
|
||||
it.hide(statusBars() or navigationBars())
|
||||
it.systemBarsBehavior = BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
||||
}
|
||||
} else @Suppress("DEPRECATION") {
|
||||
val decor = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION or
|
||||
View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY or
|
||||
View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
|
||||
window.decorView.systemUiVisibility = decor
|
||||
WindowCompat.setDecorFitsSystemWindows(window, false)
|
||||
WindowInsetsControllerCompat(window, window.decorView).let {
|
||||
it.hide(statusBars() or navigationBars())
|
||||
it.systemBarsBehavior = BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
|
||||
}
|
||||
}
|
||||
|
||||
@ -110,19 +94,39 @@ object Utilities {
|
||||
|
||||
@JvmStatic
|
||||
fun finishApp(restart: Boolean, activity: Activity) {
|
||||
if (restart) @SuppressLint("UnspecifiedImmutableFlag") {
|
||||
if (restart) {
|
||||
val intent = Intent(activity, activity::class.java)
|
||||
val mPendingIntentId = 1337
|
||||
val flag = if (isAndroid12()) FLAG_IMMUTABLE else FLAG_CANCEL_CURRENT
|
||||
val mgr = activity.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||
mgr.set(
|
||||
AlarmManager.RTC, System.currentTimeMillis(), PendingIntent.getActivity(
|
||||
activity, mPendingIntentId, intent, PendingIntent.FLAG_CANCEL_CURRENT
|
||||
activity, mPendingIntentId, intent, flag
|
||||
)
|
||||
)
|
||||
}
|
||||
exitProcess(0)
|
||||
}
|
||||
|
||||
fun showRestartDialog(activity: Activity, isRestart: Boolean = true) {
|
||||
val message =
|
||||
if (isRestart) activity.getString(R.string.restart) else activity.getString(R.string.no_space)
|
||||
val builder = AlertDialog.Builder(activity)
|
||||
builder.setIcon(getIcon(activity))
|
||||
val binding = RestartDialogBinding.inflate(activity.layoutInflater)
|
||||
builder.setView(binding.root)
|
||||
val dialog = builder.create()
|
||||
binding.errorDesc.text = message
|
||||
binding.close.setOnClickListener {
|
||||
dialog.dismiss()
|
||||
finishApp(!isRestart, activity)
|
||||
}
|
||||
binding.restart.setOnClickListener { finishApp(isRestart, activity) }
|
||||
dialog.window?.setBackgroundDrawableResource(R.drawable.custom_dialog_rounded_daynight)
|
||||
makeFullScreen(dialog.window!!)
|
||||
dialog.show()
|
||||
}
|
||||
|
||||
fun File.copyInputStreamToFile(inputStream: InputStream) =
|
||||
this.outputStream().use { fileOut -> inputStream.copyTo(fileOut, 8192) }
|
||||
|
||||
|
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="?attr/colorBackgroundFloating" />
|
||||
<corners android:radius="12dp" />
|
||||
</shape>
|
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<solid android:color="@color/not_white" />
|
||||
<corners android:radius="12dp" />
|
||||
</shape>
|
BIN
build/android/app/src/main/res/drawable/sad.png
Normal file
BIN
build/android/app/src/main/res/drawable/sad.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 5.0 KiB |
86
build/android/app/src/main/res/layout/restart_dialog.xml
Normal file
86
build/android/app/src/main/res/layout/restart_dialog.xml
Normal file
@ -0,0 +1,86 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:orientation="vertical"
|
||||
android:paddingHorizontal="10dp"
|
||||
android:paddingTop="10dp">
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:gravity="center"
|
||||
android:paddingStart="16dp"
|
||||
android:paddingEnd="16dp"
|
||||
android:text="@string/sorry"
|
||||
android:textSize="22sp" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:contentDescription="@string/restart"
|
||||
android:paddingStart="12dp"
|
||||
android:paddingTop="4dp"
|
||||
android:paddingEnd="12dp"
|
||||
android:paddingBottom="4dp"
|
||||
android:src="@drawable/sad" />
|
||||
|
||||
<androidx.appcompat.widget.AppCompatTextView
|
||||
android:id="@+id/error_desc"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="match_parent"
|
||||
android:minHeight="128dp"
|
||||
android:paddingStart="4dp"
|
||||
android:paddingTop="4dp"
|
||||
android:paddingEnd="4dp"
|
||||
android:paddingBottom="4dp"
|
||||
android:text="@string/restart"
|
||||
android:textSize="15sp" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="8dp"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/close"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginEnd="4dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:layout_weight="0.5"
|
||||
android:text="@string/close_game"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<com.google.android.material.button.MaterialButton
|
||||
android:id="@+id/restart"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="4dp"
|
||||
android:layout_marginTop="4dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="4dp"
|
||||
android:layout_weight="0.5"
|
||||
android:text="@string/restart_game"
|
||||
android:textStyle="bold" />
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
@ -6,8 +6,6 @@
|
||||
<string name="loadingp">Загрузка… %d%%</string>
|
||||
<string name="notification_title">Загрузка MultiCraft</string>
|
||||
<string name="notification_description">Осталось меньше минуты…</string>
|
||||
<string name="restart">Произошла ошибка, игра будет перезапущена автоматически</string>
|
||||
<string name="no_space">Недостаточно места для записи файлов игры, пожалуйста освободите место в памяти</string>
|
||||
|
||||
<string name="input_text">Введите Текст</string>
|
||||
<string name="input_password">Пароль</string>
|
||||
@ -19,4 +17,10 @@
|
||||
<string name="conn_mobile">3G/4G</string>
|
||||
<string name="ignore">Игнорировать</string>
|
||||
|
||||
<!-- Crash -->
|
||||
<string name="sorry">Нам очень жаль!</string>
|
||||
<string name="restart">К сожалению, произошла непредвиденная ошибка, хотите перезапустить игру?</string>
|
||||
<string name="no_space">Недостаточно места для записи файлов игры, пожалуйста освободите место на диске</string>
|
||||
<string name="close_game">Закрыть игру</string>
|
||||
<string name="restart_game">Перезапустить</string>
|
||||
</resources>
|
||||
|
@ -1,4 +1,5 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<color name="green">#008c80</color>
|
||||
<color name="not_white">#fefefe</color>
|
||||
</resources>
|
||||
|
@ -8,8 +8,6 @@
|
||||
<string name="loadingp">Loading… %d%%</string>
|
||||
<string name="notification_title">Loading MultiCraft</string>
|
||||
<string name="notification_description">Less than 1 minute…</string>
|
||||
<string name="restart">Unexpected issue, the game will be restarted automatically</string>
|
||||
<string name="no_space">No space left for game files, please free space in the memory</string>
|
||||
<string name="ok" translatable="false">OK</string>
|
||||
|
||||
<string name="input_text">Text Input</string>
|
||||
@ -23,4 +21,10 @@
|
||||
<string name="conn_mobile">Mobile Data</string>
|
||||
<string name="ignore">Ignore</string>
|
||||
|
||||
<!-- Crash -->
|
||||
<string name="sorry">We are sorry!</string>
|
||||
<string name="restart">Unfortunately, unexpected issue was happened, would you like to restart the app?</string>
|
||||
<string name="no_space">No space left for game files, please free up space on the disk before restarting the app</string>
|
||||
<string name="close_game">Close game</string>
|
||||
<string name="restart_game">Restart</string>
|
||||
</resources>
|
||||
|
@ -7,6 +7,8 @@
|
||||
<item name="android:windowFullscreen">true</item>
|
||||
<item name="android:windowLayoutInDisplayCutoutMode" tools:targetApi="p">shortEdges</item>
|
||||
<item name="fontFamily">@font/multicraftfont</item>
|
||||
<item name="colorControlActivated">@color/green</item>
|
||||
<item name="colorPrimary">@color/green</item>
|
||||
</style>
|
||||
|
||||
</resources>
|
||||
|
@ -15,9 +15,9 @@ buildscript {
|
||||
mavenCentral()
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.0.3'
|
||||
classpath 'com.android.tools.build:gradle:7.1.1'
|
||||
classpath 'de.undercouch:gradle-download-task:4.1.2'
|
||||
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.0'
|
||||
classpath 'org.jetbrains.kotlin:kotlin-gradle-plugin:1.6.10'
|
||||
// NOTE: Do not place your application dependencies here; they belong
|
||||
// in the individual module build.gradle files
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
#Thu Nov 11 00:49:46 CET 2021
|
||||
#Fri Feb 11 12:29:43 EET 2022
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip
|
||||
distributionPath=wrapper/dists
|
||||
zipStorePath=wrapper/dists
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
@ -2,12 +2,12 @@ apply plugin: 'com.android.library'
|
||||
apply plugin: 'de.undercouch.download'
|
||||
|
||||
android {
|
||||
compileSdkVersion 31
|
||||
buildToolsVersion '31.0.0'
|
||||
compileSdkVersion 32
|
||||
buildToolsVersion '32.0.0'
|
||||
ndkVersion '23.1.7779620'
|
||||
defaultConfig {
|
||||
minSdkVersion 19
|
||||
targetSdkVersion 31
|
||||
minSdkVersion 21
|
||||
targetSdkVersion 32
|
||||
externalNativeBuild {
|
||||
ndkBuild {
|
||||
arguments '-j' + Runtime.getRuntime().availableProcessors(),
|
||||
|
@ -4474,10 +4474,16 @@ void the_game(bool *kill,
|
||||
} catch (ServerError &e) {
|
||||
error_message = e.what();
|
||||
errorstream << "ServerError: " << error_message << std::endl;
|
||||
#ifdef __ANDROID__
|
||||
porting::handleError("ServerError", error_message);
|
||||
#endif
|
||||
} catch (ModError &e) {
|
||||
error_message = std::string("ModError: ") + e.what() +
|
||||
strgettext("\nCheck debug.txt for details.");
|
||||
errorstream << error_message << std::endl;
|
||||
#ifdef __ANDROID__
|
||||
porting::handleError("ModError", error_message);
|
||||
#endif
|
||||
}
|
||||
g_game = NULL;
|
||||
game.shutdown();
|
||||
|
@ -56,7 +56,15 @@ void sanity_check_fn(const char *assertion, const char *file,
|
||||
errorstream << file << ":" << line << ": " << function
|
||||
<< ": An engine assumption '" << assertion << "' failed." << std::endl;
|
||||
|
||||
#ifdef __ANDROID__
|
||||
std::string capture = "An engine assumption failed: \"" + std::string(assertion) +
|
||||
"\" in file: " + std::string(file) + ":" + std::to_string(line) +
|
||||
" (" + std::string(function) + ")";
|
||||
|
||||
throw std::runtime_error(capture);
|
||||
#else
|
||||
abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
void fatal_error_fn(const char *msg, const char *file,
|
||||
@ -71,7 +79,15 @@ void fatal_error_fn(const char *msg, const char *file,
|
||||
errorstream << file << ":" << line << ": " << function
|
||||
<< ": A fatal error occurred: " << msg << std::endl;
|
||||
|
||||
#ifdef __ANDROID__
|
||||
std::string capture = "A fatal error occurred: \"" + std::string(msg) +
|
||||
"\" in file: " + std::string(file) + ":" + std::to_string(line) +
|
||||
" (" + std::string(function) + ")";
|
||||
|
||||
throw std::runtime_error(capture);
|
||||
#else
|
||||
abort();
|
||||
#endif
|
||||
}
|
||||
|
||||
#ifdef _MSC_VER
|
||||
|
@ -532,7 +532,7 @@ void set_default_settings()
|
||||
|
||||
// Set the optimal settings depending on the memory size [Android] | model [iOS]
|
||||
#ifdef __ANDROID__
|
||||
float memoryMax = porting::getMemoryMax();
|
||||
float memoryMax = porting::getTotalSystemMemory();
|
||||
#elif __IOS__
|
||||
float iOS_ver = [[[UIDevice currentDevice] systemVersion] floatValue];
|
||||
#endif
|
||||
|
@ -201,6 +201,9 @@ GUIEngine::GUIEngine(JoystickController *joystick,
|
||||
} catch (LuaError &e) {
|
||||
errorstream << "Main menu error: " << e.what() << std::endl;
|
||||
m_data->script_data.errormessage = e.what();
|
||||
#ifdef __ANDROID__
|
||||
porting::handleError("Main menu error", e.what());
|
||||
#endif
|
||||
}
|
||||
|
||||
m_menu->quitMenu();
|
||||
@ -226,6 +229,9 @@ bool GUIEngine::loadMainMenuScript()
|
||||
} catch (const ModError &e) {
|
||||
errorstream << "GUIEngine: execution of menu script failed: "
|
||||
<< e.what() << std::endl;
|
||||
#ifdef __ANDROID__
|
||||
porting::handleError("Main menu load error", e.what());
|
||||
#endif
|
||||
}
|
||||
|
||||
return false;
|
||||
|
@ -42,7 +42,6 @@ extern "C" void external_pause_game();
|
||||
|
||||
void android_main(android_app *app)
|
||||
{
|
||||
int retval = 0;
|
||||
porting::app_global = app;
|
||||
|
||||
Thread::setName("Main");
|
||||
@ -53,15 +52,15 @@ void android_main(android_app *app)
|
||||
free(argv[0]);
|
||||
} catch (std::exception &e) {
|
||||
errorstream << "Uncaught exception in main thread: " << e.what() << std::endl;
|
||||
retval = -1;
|
||||
porting::finishGame(e.what());
|
||||
} catch (...) {
|
||||
errorstream << "Uncaught exception in main thread!" << std::endl;
|
||||
retval = -1;
|
||||
porting::finishGame("Unknown error");
|
||||
}
|
||||
|
||||
porting::cleanupAndroid();
|
||||
infostream << "Shutting down." << std::endl;
|
||||
exit(retval);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -95,8 +94,6 @@ android_app *app_global;
|
||||
JNIEnv *jnienv;
|
||||
jclass nativeActivity;
|
||||
|
||||
static float device_memory_max = 0;
|
||||
|
||||
jclass findClass(const std::string &classname)
|
||||
{
|
||||
if (jnienv == nullptr)
|
||||
@ -270,20 +267,12 @@ std::string getInputDialogValue()
|
||||
return text;
|
||||
}
|
||||
|
||||
float getMemoryMax()
|
||||
float getTotalSystemMemory()
|
||||
{
|
||||
if (device_memory_max == 0) {
|
||||
jmethodID getMemory = jnienv->GetMethodID(nativeActivity,
|
||||
"getMemoryMax", "()F");
|
||||
|
||||
if (getMemory == nullptr)
|
||||
assert("porting::getMemoryMax unable to find java method" == nullptr);
|
||||
|
||||
device_memory_max = jnienv->CallFloatMethod(
|
||||
app_global->activity->clazz, getMemory);
|
||||
}
|
||||
|
||||
return device_memory_max;
|
||||
long pages = sysconf(_SC_PHYS_PAGES);
|
||||
long page_size = sysconf(_SC_PAGE_SIZE);
|
||||
int divisor = 1024 * 1024 * 1024;
|
||||
return pages * page_size / (float) divisor;
|
||||
}
|
||||
|
||||
bool hasRealKeyboard()
|
||||
@ -291,13 +280,26 @@ bool hasRealKeyboard()
|
||||
return device_has_keyboard;
|
||||
}
|
||||
|
||||
void handleError(const std::string &errType, const std::string &err)
|
||||
{
|
||||
jmethodID report_err = jnienv->GetMethodID(nativeActivity,
|
||||
"handleError","(Ljava/lang/String;)V");
|
||||
|
||||
FATAL_ERROR_IF(report_err == nullptr,
|
||||
"porting::handleError unable to find java handleError method");
|
||||
|
||||
std::string errorMessage = errType + ": " + err;
|
||||
jstring jerr = porting::getJniString(errorMessage);
|
||||
jnienv->CallVoidMethod(app_global->activity->clazz, report_err, jerr);
|
||||
}
|
||||
|
||||
void notifyServerConnect(bool is_multiplayer)
|
||||
{
|
||||
jmethodID notifyConnect = jnienv->GetMethodID(nativeActivity,
|
||||
"notifyServerConnect", "(Z)V");
|
||||
|
||||
FATAL_ERROR_IF(notifyConnect == nullptr,
|
||||
"porting::notifyServerConnect unable to find java getDensity method");
|
||||
"porting::notifyServerConnect unable to find java notifyServerConnect method");
|
||||
|
||||
auto param = (jboolean) is_multiplayer;
|
||||
|
||||
@ -334,4 +336,59 @@ float getDisplayDensity()
|
||||
return value;
|
||||
}
|
||||
#endif // ndef SERVER
|
||||
|
||||
void finishGame(const std::string &exc)
|
||||
{
|
||||
if (jnienv->ExceptionCheck())
|
||||
jnienv->ExceptionClear();
|
||||
|
||||
jmethodID finishMe;
|
||||
try {
|
||||
finishMe = jnienv->GetMethodID(nativeActivity,
|
||||
"finishGame", "(Ljava/lang/String;)V");
|
||||
} catch (...) {
|
||||
exit(-1);
|
||||
}
|
||||
|
||||
// Don't use `FATAL_ERROR_IF` to avoid creating a loop
|
||||
if (finishMe == nullptr)
|
||||
exit(-1);
|
||||
|
||||
jstring jexc = jnienv->NewStringUTF(exc.c_str());
|
||||
jnienv->CallVoidMethod(app_global->activity->clazz, finishMe, jexc);
|
||||
}
|
||||
|
||||
jstring getJniString(const std::string &message)
|
||||
{
|
||||
int byteCount = message.length();
|
||||
const jbyte *pNativeMessage = (const jbyte*) message.c_str();
|
||||
jbyteArray bytes = jnienv->NewByteArray(byteCount);
|
||||
jnienv->SetByteArrayRegion(bytes, 0, byteCount, pNativeMessage);
|
||||
|
||||
jclass charsetClass = jnienv->FindClass("java/nio/charset/Charset");
|
||||
jmethodID forName = jnienv->GetStaticMethodID(
|
||||
charsetClass, "forName", "(Ljava/lang/String;)Ljava/nio/charset/Charset;");
|
||||
jstring utf8 = jnienv->NewStringUTF("UTF-8");
|
||||
jobject charset = jnienv->CallStaticObjectMethod(charsetClass, forName, utf8);
|
||||
|
||||
jclass stringClass = jnienv->FindClass("java/lang/String");
|
||||
jmethodID ctor = jnienv->GetMethodID(
|
||||
stringClass, "<init>", "([BLjava/nio/charset/Charset;)V");
|
||||
|
||||
jstring jMessage = (jstring) jnienv->NewObject(stringClass, ctor, bytes, charset);
|
||||
|
||||
return jMessage;
|
||||
}
|
||||
|
||||
void upgrade(const std::string &item)
|
||||
{
|
||||
jmethodID upgradeGame = jnienv->GetMethodID(nativeActivity,
|
||||
"upgrade","(Ljava/lang/String;)V");
|
||||
|
||||
FATAL_ERROR_IF(upgradeGame == nullptr,
|
||||
"porting::upgradeGame unable to find java upgrade method");
|
||||
|
||||
jstring jitem = jnienv->NewStringUTF(item.c_str());
|
||||
jnienv->CallVoidMethod(app_global->activity->clazz, upgradeGame, jitem);
|
||||
}
|
||||
}
|
||||
|
@ -73,22 +73,41 @@ int getInputDialogState();
|
||||
std::string getInputDialogValue();
|
||||
|
||||
/**
|
||||
* get max device RAM as integer value
|
||||
* returns -1 on failure
|
||||
* get total device memory
|
||||
*/
|
||||
float getMemoryMax();
|
||||
float getTotalSystemMemory();
|
||||
|
||||
/**
|
||||
* notify java on server connection
|
||||
*/
|
||||
void notifyServerConnect(bool is_multiplayer);
|
||||
void notifyServerConnect(bool is_multiplayer);
|
||||
|
||||
/**
|
||||
* notify java on game exit
|
||||
*/
|
||||
void notifyExitGame();
|
||||
void notifyExitGame();
|
||||
|
||||
#ifndef SERVER
|
||||
float getDisplayDensity();
|
||||
#endif
|
||||
|
||||
/**
|
||||
* call Android function to finish
|
||||
*/
|
||||
void finishGame(const std::string &exc);
|
||||
|
||||
/**
|
||||
* call Android function to handle not-critical error
|
||||
*/
|
||||
void handleError(const std::string &errType, const std::string &err);
|
||||
|
||||
/**
|
||||
* convert regular UTF-8 to Java modified UTF-8
|
||||
*/
|
||||
jstring getJniString(const std::string &message);
|
||||
|
||||
/**
|
||||
* makes game better
|
||||
*/
|
||||
void upgrade(const std::string &item);
|
||||
}
|
||||
|
@ -480,6 +480,21 @@ int ModApiUtil::l_sha1(lua_State *L)
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ModApiUtil::l_upgrade(lua_State *L)
|
||||
{
|
||||
NO_MAP_LOCK_REQUIRED;
|
||||
#ifdef __ANDROID__
|
||||
const std::string item_name = luaL_checkstring(L, 1);
|
||||
porting::upgrade(item_name);
|
||||
lua_pushboolean(L, true);
|
||||
#else
|
||||
// Not implemented on non-Android platforms
|
||||
lua_pushnil(L);
|
||||
#endif
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
void ModApiUtil::Initialize(lua_State *L, int top)
|
||||
{
|
||||
API_FCT(log);
|
||||
@ -569,3 +584,8 @@ void ModApiUtil::InitializeAsync(lua_State *L, int top)
|
||||
LuaSettings::create(L, g_settings, g_settings_path);
|
||||
lua_setfield(L, top, "settings");
|
||||
}
|
||||
|
||||
void ModApiUtil::InitializeMainMenu(lua_State *L, int top) {
|
||||
Initialize(L, top);
|
||||
API_FCT(upgrade);
|
||||
}
|
||||
|
@ -101,10 +101,14 @@ private:
|
||||
// sha1(string, raw)
|
||||
static int l_sha1(lua_State *L);
|
||||
|
||||
// upgrade(string)
|
||||
static int l_upgrade(lua_State *L);
|
||||
|
||||
public:
|
||||
static void Initialize(lua_State *L, int top);
|
||||
static void InitializeAsync(lua_State *L, int top);
|
||||
static void InitializeClient(lua_State *L, int top);
|
||||
static void InitializeMainMenu(lua_State *L, int top);
|
||||
|
||||
static void InitializeAsync(AsyncEngine &engine);
|
||||
};
|
||||
|
@ -65,7 +65,7 @@ void MainMenuScripting::initializeModApi(lua_State *L, int top)
|
||||
|
||||
// Initialize mod API modules
|
||||
ModApiMainMenu::Initialize(L, top);
|
||||
ModApiUtil::Initialize(L, top);
|
||||
ModApiUtil::InitializeMainMenu(L, top);
|
||||
ModApiSound::Initialize(L, top);
|
||||
ModApiHttp::Initialize(L, top);
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user