mirror of
https://github.com/OMGeeky/andors-trail.git
synced 2026-02-23 15:38:29 +01:00
Compare commits
259 Commits
OMGeeky-pa
...
savegame-h
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4c2113c58c | ||
|
|
3fbc7cf65f | ||
|
|
dc18289d18 | ||
|
|
6473e231e4 | ||
|
|
33a61b7a57 | ||
|
|
c070a39f7c | ||
|
|
995ec0f697 | ||
|
|
6cba6872c9 | ||
|
|
8812f664e7 | ||
|
|
d9113b2dab | ||
|
|
ad0025ba03 | ||
|
|
984aa17cc0 | ||
|
|
4cad05ce6b | ||
|
|
197ab946be | ||
|
|
e4cdbc1840 | ||
|
|
04f00553ae | ||
|
|
0c02902ceb | ||
|
|
aba93fb15b | ||
|
|
1c8330b99a | ||
|
|
a8de7c2860 | ||
|
|
4ca8bbfc12 | ||
|
|
a5c004e4d4 | ||
|
|
e957e409e0 | ||
|
|
70d6340c11 | ||
|
|
bbbb69b175 | ||
|
|
4d5b7d8667 | ||
|
|
43da08f57d | ||
|
|
7b97367bdd | ||
|
|
e6fb647b99 | ||
|
|
5e4d7aba18 | ||
|
|
a96086b9af | ||
|
|
0566cf899c | ||
|
|
c8e87fb3d0 | ||
|
|
0a56a0ba86 | ||
|
|
026ccde2ff | ||
|
|
7813994b81 | ||
|
|
d3b070844f | ||
|
|
7a879f99b1 | ||
|
|
e810cdb3cb | ||
|
|
398be07c31 | ||
|
|
6db4c7bb3c | ||
|
|
c402824641 | ||
|
|
abc020e8f5 | ||
|
|
82caf260ce | ||
|
|
cbcf5ff8ca | ||
|
|
39d07bf8a8 | ||
|
|
93174f0d65 | ||
|
|
6afbeb9a2a | ||
|
|
a7cbd644f3 | ||
|
|
f674aff07c | ||
|
|
07b89a288c | ||
|
|
0264c418ca | ||
|
|
494b9c47cc | ||
|
|
6ff6c6dd6c | ||
|
|
00ab587265 | ||
|
|
67fa480805 | ||
|
|
91db56e7a7 | ||
|
|
36d52bedad | ||
|
|
c36b676720 | ||
|
|
5e0a999249 | ||
|
|
8fff4aff60 | ||
|
|
8c5344ff37 | ||
|
|
91e49b6c4a | ||
|
|
52cfb37b21 | ||
|
|
87886f08bb | ||
|
|
a31d7f9589 | ||
|
|
5600957f32 | ||
|
|
d6840a83c9 | ||
|
|
06fdd39648 | ||
|
|
b5763e7f76 | ||
|
|
75f01f20b9 | ||
|
|
dd366ab69e | ||
|
|
6ab443ec2c | ||
|
|
e0056cbf5c | ||
|
|
9f9397e1f3 | ||
|
|
d5a43cc7e1 | ||
|
|
408d8aa8b8 | ||
|
|
1e663069e8 | ||
|
|
dbcec1a199 | ||
|
|
04b4193548 | ||
|
|
058803184f | ||
|
|
5b5912c5bc | ||
|
|
759e632c07 | ||
|
|
6e311ecb64 | ||
|
|
b480fd9173 | ||
|
|
226459ddb8 | ||
|
|
92de033bc8 | ||
|
|
faf0dd061c | ||
|
|
9eaf9ea2ed | ||
|
|
00c4f77251 | ||
|
|
96ef9eedbb | ||
|
|
a5d94c03e2 | ||
|
|
9d15d380a3 | ||
|
|
bff780c837 | ||
|
|
0c493952c8 | ||
|
|
a1f6e1d29c | ||
|
|
fc71f43755 | ||
|
|
16afcf4886 | ||
|
|
b64a3c2109 | ||
|
|
5c0dc66183 | ||
|
|
3047f653bd | ||
|
|
393a478d13 | ||
|
|
560cb326f9 | ||
|
|
3fe2d7260f | ||
|
|
2cd4bc7ee5 | ||
|
|
19468b591d | ||
|
|
903117d32f | ||
|
|
f5bfc98c62 | ||
|
|
3274feb1e9 | ||
|
|
392b4d8577 | ||
|
|
92e4afde4b | ||
|
|
0c7724fe33 | ||
|
|
ca5be34fc2 | ||
|
|
28c3c7a0ec | ||
|
|
7f39cf1a6f | ||
|
|
365839571a | ||
|
|
5c3a04ca77 | ||
|
|
758a580063 | ||
|
|
ad5dbc9f9d | ||
|
|
4a86680928 | ||
|
|
ece63cf442 | ||
|
|
b487140a1b | ||
|
|
ad72bf8895 | ||
|
|
5919c429d2 | ||
|
|
0b6580e7c9 | ||
|
|
6efb2b3860 | ||
|
|
7ae084073f | ||
|
|
36df0b1732 | ||
|
|
b8fb100bd5 | ||
|
|
82b904d176 | ||
|
|
111aca868c | ||
|
|
2171c16d47 | ||
|
|
acd4d84783 | ||
|
|
cc25cc97f1 | ||
|
|
93ecebc448 | ||
|
|
f5713a3eb2 | ||
|
|
90001bb4d6 | ||
|
|
357cab9b1e | ||
|
|
5ea272f286 | ||
|
|
0c876bd1c5 | ||
|
|
0ac2999694 | ||
|
|
49af3c4b6d | ||
|
|
2a54b31d31 | ||
|
|
64766ce50a | ||
|
|
311accfdd3 | ||
|
|
2b5bf2fa4a | ||
|
|
64342c96d7 | ||
|
|
f8649bb0a5 | ||
|
|
fde6608c26 | ||
|
|
3f339c14a2 | ||
|
|
922db05c4d | ||
|
|
b849de8b66 | ||
|
|
f798b29729 | ||
|
|
e58e7a2588 | ||
|
|
a1ef339831 | ||
|
|
2002d51f6b | ||
|
|
025283b70b | ||
|
|
577b1aa034 | ||
|
|
da637c0cc8 | ||
|
|
d026ff690a | ||
|
|
d14ed56669 | ||
|
|
64cfacb7ff | ||
|
|
98a800e070 | ||
|
|
35219c8e88 | ||
|
|
b636cad347 | ||
|
|
733328cd29 | ||
|
|
36db28f805 | ||
|
|
6d4c1c3c14 | ||
|
|
eadb95f8e8 | ||
|
|
014f67f270 | ||
|
|
cd8657adb4 | ||
|
|
c007fc4d1c | ||
|
|
7e6c864ba3 | ||
|
|
f2da8f767a | ||
|
|
bd856541d6 | ||
|
|
bdde2176d9 | ||
|
|
171893a2c1 | ||
|
|
c6c1d6d03d | ||
|
|
ec8b114782 | ||
|
|
aaecb8ae4a | ||
|
|
4e2e3b370c | ||
|
|
c14f8f84a0 | ||
|
|
13c8012710 | ||
|
|
3806d77b26 | ||
|
|
af94220715 | ||
|
|
af07c47832 | ||
|
|
322007e5ac | ||
|
|
af5cdb9d49 | ||
|
|
3ada8ceaa7 | ||
|
|
68fa0068dc | ||
|
|
7b5fc79375 | ||
|
|
5dfa750227 | ||
|
|
cbe0773310 | ||
|
|
72a19eeb80 | ||
|
|
a993cc5a08 | ||
|
|
83724ba408 | ||
|
|
a4cd8f7460 | ||
|
|
7a52bbb9f3 | ||
|
|
3552ff8a9f | ||
|
|
0e081f3319 | ||
|
|
1d94519e1c | ||
|
|
0bbc6adb4b | ||
|
|
b48ddd4999 | ||
|
|
be8dad981d | ||
|
|
f9708f48a4 | ||
|
|
155b01bdea | ||
|
|
19810b2099 | ||
|
|
c6886f7a3e | ||
|
|
3bea24f9cc | ||
|
|
4b8f5c4908 | ||
|
|
66d9618b1b | ||
|
|
488d6347d0 | ||
|
|
51fd0d0994 | ||
|
|
50833af145 | ||
|
|
ca7c2388aa | ||
|
|
8e7d6adca5 | ||
|
|
17edb96ff8 | ||
|
|
3f3869916c | ||
|
|
1d2fc7ade7 | ||
|
|
aa84e5a73d | ||
|
|
4ecf7d2dda | ||
|
|
dca1cb676c | ||
|
|
9a4f41eac2 | ||
|
|
23012b0d40 | ||
|
|
916134bd9b | ||
|
|
1d6777daae | ||
|
|
4793751ba8 | ||
|
|
185c0eaf7c | ||
|
|
4b50d13149 | ||
|
|
23b58c3e7c | ||
|
|
2d5ebc3b13 | ||
|
|
59e2e3035c | ||
|
|
6d5ddfdbfa | ||
|
|
f8ae18721f | ||
|
|
63bc7c3a4e | ||
|
|
8e72763314 | ||
|
|
9310d53362 | ||
|
|
a71dcc13a3 | ||
|
|
ea95f4ff87 | ||
|
|
f35167d112 | ||
|
|
9f935190f2 | ||
|
|
c11430cf6b | ||
|
|
8f97a27ab7 | ||
|
|
9e36f848dc | ||
|
|
b24d52b1da | ||
|
|
e2a9307560 | ||
|
|
e3ac804f61 | ||
|
|
fd504d2df5 | ||
|
|
0e615d3f11 | ||
|
|
47646457ab | ||
|
|
8e393b93d8 | ||
|
|
3289bd6fb1 | ||
|
|
23a331d655 | ||
|
|
112301c444 | ||
|
|
f50e4f1d38 | ||
|
|
d623c22b38 | ||
|
|
d11bf5b0aa | ||
|
|
e30f67e327 | ||
|
|
96a1a5760a |
34
.github/workflows/gradle.yml
vendored
34
.github/workflows/gradle.yml
vendored
@@ -1,34 +0,0 @@
|
||||
# This workflow uses actions that are not certified by GitHub.
|
||||
# They are provided by a third-party and are governed by
|
||||
# separate terms of service, privacy policy, and support
|
||||
# documentation.
|
||||
# This workflow will build a Java project with Gradle and cache/restore any dependencies to improve the workflow execution time
|
||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
|
||||
|
||||
name: Check if Gradle Build works
|
||||
|
||||
on: pull_request
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up JDK 11
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: '11'
|
||||
distribution: 'temurin'
|
||||
- name: Validate Gradle wrapper
|
||||
uses: gradle/wrapper-validation-action@v1.0.4
|
||||
- name: Make gradle wrapper executable
|
||||
run: chmod +x ./AndorsTrail/gradlew
|
||||
- name: Build with Gradle
|
||||
uses: gradle/gradle-build-action@v2.3.2
|
||||
with:
|
||||
arguments: build
|
||||
build-root-directory: ./AndorsTrail
|
||||
34
.github/workflows/gradle2.yml
vendored
34
.github/workflows/gradle2.yml
vendored
@@ -1,34 +0,0 @@
|
||||
# This workflow uses actions that are not certified by GitHub.
|
||||
# They are provided by a third-party and are governed by
|
||||
# separate terms of service, privacy policy, and support
|
||||
# documentation.
|
||||
# This workflow will build a Java project with Gradle and cache/restore any dependencies to improve the workflow execution time
|
||||
# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-gradle
|
||||
|
||||
name: Build Gradle
|
||||
|
||||
on: workflow_dispatch
|
||||
|
||||
permissions:
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Set up JDK 11
|
||||
uses: actions/setup-java@v3
|
||||
with:
|
||||
java-version: '11'
|
||||
distribution: 'temurin'
|
||||
- name: Validate Gradle wrapper
|
||||
uses: gradle/wrapper-validation-action@v1.0.4
|
||||
- name: Make gradle wrapper executable
|
||||
run: chmod +x ./AndorsTrail/gradlew
|
||||
- name: Build with Gradle
|
||||
uses: gradle/gradle-build-action@v2.3.2
|
||||
with:
|
||||
arguments: build
|
||||
build-root-directory: ./AndorsTrail
|
||||
3
AndorsTrail/.gitignore
vendored
3
AndorsTrail/.gitignore
vendored
@@ -40,9 +40,6 @@ gradle-app.setting
|
||||
# Cache of project
|
||||
.gradletasknamecache
|
||||
|
||||
|
||||
local.properties
|
||||
|
||||
# Eclipse Gradle plugin generated files
|
||||
# Eclipse Core
|
||||
.project
|
||||
|
||||
Binary file not shown.
Binary file not shown.
@@ -1,20 +1,25 @@
|
||||
apply plugin: 'com.android.application'
|
||||
|
||||
android {
|
||||
compileSdkVersion 30
|
||||
compileSdkVersion 31
|
||||
buildToolsVersion "30.0.3"
|
||||
|
||||
defaultConfig {
|
||||
applicationId "com.gpl.rpg.AndorsTrail"
|
||||
minSdkVersion 14
|
||||
targetSdkVersion 30
|
||||
targetSdkVersion 31
|
||||
}
|
||||
|
||||
buildTypes {
|
||||
release {
|
||||
manifestPlaceholders icon_name: 'icon', fileproviderPath: 'AndorsTrail'
|
||||
minifyEnabled false
|
||||
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.txt'
|
||||
}
|
||||
debug {
|
||||
manifestPlaceholders icon_name: 'icon_beta', fileproviderPath: 'AndorsTrail.beta2'
|
||||
applicationIdSuffix 'beta2'
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -3,12 +3,11 @@
|
||||
<manifest
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
package="com.gpl.rpg.AndorsTrail"
|
||||
android:versionCode="66"
|
||||
android:versionName="0.8.2"
|
||||
android:versionCode="70"
|
||||
android:versionName="0.8.5"
|
||||
android:installLocation="auto"
|
||||
>
|
||||
|
||||
|
||||
<supports-screens
|
||||
android:smallScreens="true"
|
||||
android:normalScreens="true"
|
||||
@@ -24,7 +23,7 @@
|
||||
<application
|
||||
android:name="com.gpl.rpg.AndorsTrail.AndorsTrailApplication"
|
||||
android:label="@string/app_name"
|
||||
android:icon="@drawable/icon"
|
||||
android:icon="@drawable/${icon_name}"
|
||||
android:description="@string/app_description"
|
||||
android:allowBackup="true"
|
||||
android:theme="@style/AndorsTrailTheme_Blue"
|
||||
@@ -34,8 +33,9 @@
|
||||
>
|
||||
<activity
|
||||
android:name="com.gpl.rpg.AndorsTrail.activity.StartScreenActivity"
|
||||
android:exported="true"
|
||||
android:clearTaskOnLaunch="true"
|
||||
android:exported="true">
|
||||
>
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
@@ -43,6 +43,7 @@
|
||||
</activity>
|
||||
<activity
|
||||
android:name="com.gpl.rpg.AndorsTrail.activity.MainActivity"
|
||||
android:label="@string/app_name"
|
||||
android:theme="@style/AndorsTrailTheme_Blue.NoBackground"
|
||||
/>
|
||||
<activity android:name="com.gpl.rpg.AndorsTrail.activity.HeroinfoActivity" />
|
||||
@@ -63,7 +64,7 @@
|
||||
|
||||
<provider
|
||||
android:name="android.support.v4.content.FileProvider"
|
||||
android:authorities="com.gpl.rpg.AndorsTrail.fileprovider"
|
||||
android:authorities="${applicationId}.fileprovider"
|
||||
android:grantUriPermissions="true"
|
||||
android:exported="false">
|
||||
<meta-data
|
||||
|
||||
@@ -28,11 +28,11 @@ public final class AndorsTrailApplication extends Application {
|
||||
public static final boolean DEVELOPMENT_FASTSPEED = false;
|
||||
public static final boolean DEVELOPMENT_VALIDATEDATA = false;
|
||||
public static final boolean DEVELOPMENT_DEBUGMESSAGES = false;
|
||||
public static final String CURRENT_VERSION_DISPLAY = "0.8.2";
|
||||
public static final String CURRENT_VERSION_DISPLAY = "0.8.5";
|
||||
public static final boolean IS_RELEASE_VERSION = !CURRENT_VERSION_DISPLAY.matches(".*[a-d].*");
|
||||
public static final boolean DEVELOPMENT_INCOMPATIBLE_SAVEGAMES = DEVELOPMENT_DEBUGRESOURCES || DEVELOPMENT_DEBUGBUTTONS || DEVELOPMENT_FASTSPEED || !IS_RELEASE_VERSION;
|
||||
public static final int DEVELOPMENT_INCOMPATIBLE_SAVEGAME_VERSION = 999;
|
||||
public static final int CURRENT_VERSION = DEVELOPMENT_INCOMPATIBLE_SAVEGAMES ? DEVELOPMENT_INCOMPATIBLE_SAVEGAME_VERSION : 66;
|
||||
public static final int CURRENT_VERSION = DEVELOPMENT_INCOMPATIBLE_SAVEGAMES ? DEVELOPMENT_INCOMPATIBLE_SAVEGAME_VERSION : 71;
|
||||
|
||||
private final AndorsTrailPreferences preferences = new AndorsTrailPreferences();
|
||||
private WorldContext world = new WorldContext();
|
||||
|
||||
@@ -78,7 +78,7 @@ public final class AndorsTrailPreferences {
|
||||
dest.dpadTransparency = Integer.parseInt(prefs.getString("dpadtransparency", Integer.toString(DPAD_TRANSPARENCY_50_PERCENT)));
|
||||
dest.dpadMinimizeable = prefs.getBoolean("dpadMinimizeable", true);
|
||||
dest.optimizedDrawing = prefs.getBoolean("optimized_drawing", false);
|
||||
dest.highQualityFilters = prefs.getBoolean("high_quality_filters", true);
|
||||
dest.highQualityFilters = prefs.getBoolean("high_quality_filters", false);
|
||||
dest.enableUiAnimations = prefs.getBoolean("enableUiAnimations", true);
|
||||
dest.displayOverwriteSavegame = Integer.parseInt(prefs.getString("display_overwrite_savegame", Integer.toString(CONFIRM_OVERWRITE_SAVEGAME_ALWAYS)));
|
||||
dest.quickslotsPosition = Integer.parseInt(prefs.getString("quickslots_placement", Integer.toString(QUICKSLOTS_POSITION_HORIZONTAL_CENTER_BOTTOM)));
|
||||
|
||||
@@ -46,14 +46,15 @@ import com.gpl.rpg.AndorsTrail.model.item.Loot;
|
||||
import com.gpl.rpg.AndorsTrail.model.map.MapObject;
|
||||
import com.gpl.rpg.AndorsTrail.util.ThemeHelper;
|
||||
import com.gpl.rpg.AndorsTrail.view.CustomDialogFactory;
|
||||
import com.gpl.rpg.AndorsTrail.view.CustomDialogFactory.CustomDialog;
|
||||
import com.gpl.rpg.AndorsTrail.view.ItemContainerAdapter;
|
||||
|
||||
public final class Dialogs {
|
||||
|
||||
private static void showDialogAndPause(Dialog d, final ControllerContext context) {
|
||||
private static void showDialogAndPause(CustomDialog d, final ControllerContext context) {
|
||||
showDialogAndPause(d, context, null);
|
||||
}
|
||||
private static void showDialogAndPause(Dialog d, final ControllerContext context, final OnDismissListener onDismiss) {
|
||||
private static void showDialogAndPause(CustomDialog d, final ControllerContext context, final OnDismissListener onDismiss) {
|
||||
context.gameRoundController.pause();
|
||||
CustomDialogFactory.setDismissListener(d, new OnDismissListener() {
|
||||
@Override
|
||||
@@ -195,7 +196,7 @@ public final class Dialogs {
|
||||
// itemList.setPadding(20, 0, 20, 20);
|
||||
itemList.setAdapter(new ItemContainerAdapter(mainActivity, world.tileManager, combinedLoot.items, world.model.player));
|
||||
|
||||
final Dialog d = CustomDialogFactory.createDialog(mainActivity,
|
||||
final CustomDialog d = CustomDialogFactory.createDialog(mainActivity,
|
||||
mainActivity.getResources().getString(title),
|
||||
mainActivity.getResources().getDrawable(R.drawable.ui_icon_equipment),
|
||||
msg,
|
||||
@@ -249,7 +250,7 @@ public final class Dialogs {
|
||||
}
|
||||
|
||||
public static void showHeroDied(final MainActivity mainActivity, final ControllerContext controllers) {
|
||||
final Dialog d = CustomDialogFactory.createDialog(mainActivity,
|
||||
final CustomDialog d = CustomDialogFactory.createDialog(mainActivity,
|
||||
mainActivity.getResources().getString(R.string.dialog_game_over_title),
|
||||
mainActivity.getResources().getDrawable(R.drawable.ui_icon_combat),
|
||||
mainActivity.getResources().getString(R.string.dialog_game_over_text),
|
||||
@@ -286,7 +287,7 @@ public final class Dialogs {
|
||||
}
|
||||
|
||||
public static void showConfirmRest(final Activity currentActivity, final ControllerContext controllerContext, final MapObject area) {
|
||||
final Dialog d = CustomDialogFactory.createDialog(currentActivity,
|
||||
final CustomDialog d = CustomDialogFactory.createDialog(currentActivity,
|
||||
currentActivity.getResources().getString(R.string.dialog_rest_title),
|
||||
null,
|
||||
currentActivity.getResources().getString(R.string.dialog_rest_confirm_message),
|
||||
@@ -310,7 +311,7 @@ public final class Dialogs {
|
||||
// .setMessage(R.string.dialog_rest_message)
|
||||
// .setNeutralButton(android.R.string.ok, null)
|
||||
// .create();
|
||||
final Dialog d = CustomDialogFactory.createDialog(currentActivity,
|
||||
final CustomDialog d = CustomDialogFactory.createDialog(currentActivity,
|
||||
currentActivity.getResources().getString(R.string.dialog_rest_title),
|
||||
null,
|
||||
currentActivity.getResources().getString(R.string.dialog_rest_message),
|
||||
@@ -336,7 +337,7 @@ public final class Dialogs {
|
||||
text += currentActivity.getResources().getString(R.string.dialog_newversion_permission_information);
|
||||
}
|
||||
|
||||
final Dialog d = CustomDialogFactory.createDialog(currentActivity,
|
||||
final CustomDialog d = CustomDialogFactory.createDialog(currentActivity,
|
||||
currentActivity.getResources().getString(R.string.dialog_newversion_title),
|
||||
null,
|
||||
text,
|
||||
@@ -371,7 +372,7 @@ public final class Dialogs {
|
||||
}
|
||||
|
||||
if (!world.model.statistics.hasUnlimitedSaves()) {
|
||||
final Dialog d = CustomDialogFactory.createDialog(mainActivity,
|
||||
final CustomDialog d = CustomDialogFactory.createDialog(mainActivity,
|
||||
mainActivity.getResources().getString(R.string.menu_save_switch_character_title),
|
||||
null,
|
||||
mainActivity.getResources().getString(R.string.menu_save_switch_character),
|
||||
@@ -460,7 +461,7 @@ public final class Dialogs {
|
||||
itemList.setAdapter(new ArrayAdapter<String>(context, R.layout.combatlog_row, android.R.id.text1, combatLogMessages));
|
||||
view = itemList;
|
||||
|
||||
final Dialog d = CustomDialogFactory.createDialog(context,
|
||||
final CustomDialog d = CustomDialogFactory.createDialog(context,
|
||||
context.getResources().getString(R.string.combat_log_title),
|
||||
context.getResources().getDrawable(R.drawable.ui_icon_combat),
|
||||
null,
|
||||
|
||||
@@ -134,8 +134,9 @@ public final class WorldSetup {
|
||||
onSceneLoadedListener = null;
|
||||
if (o == null) return;
|
||||
|
||||
if (loadResult == Savegames.LoadSavegameResult.success) {
|
||||
o.onSceneLoaded();
|
||||
if (loadResult == Savegames.LoadSavegameResult.success
|
||||
|| loadResult == Savegames.LoadSavegameResult.editDetected) {
|
||||
o.onSceneLoaded(loadResult);
|
||||
} else {
|
||||
o.onSceneLoadFailed(loadResult);
|
||||
}
|
||||
@@ -161,7 +162,7 @@ public final class WorldSetup {
|
||||
|
||||
|
||||
public static interface OnSceneLoadedListener {
|
||||
void onSceneLoaded();
|
||||
void onSceneLoaded(Savegames.LoadSavegameResult loadResult);
|
||||
void onSceneLoadFailed(Savegames.LoadSavegameResult loadResult);
|
||||
}
|
||||
public interface OnResourcesLoadedListener {
|
||||
|
||||
@@ -23,6 +23,7 @@ import com.gpl.rpg.AndorsTrail.controller.ItemController;
|
||||
import com.gpl.rpg.AndorsTrail.model.item.ItemType;
|
||||
import com.gpl.rpg.AndorsTrail.util.ThemeHelper;
|
||||
import com.gpl.rpg.AndorsTrail.view.CustomDialogFactory;
|
||||
import com.gpl.rpg.AndorsTrail.view.CustomDialogFactory.CustomDialog;
|
||||
|
||||
/**
|
||||
* @author ejwessel
|
||||
@@ -206,7 +207,7 @@ public final class BulkSelectionInterface extends AndorsTrailBaseActivity implem
|
||||
// })
|
||||
// .setNegativeButton(android.R.string.no, null)
|
||||
// .show();
|
||||
final Dialog d = CustomDialogFactory.createDialog(v.getContext(),
|
||||
final CustomDialog d = CustomDialogFactory.createDialog(v.getContext(),
|
||||
v.getContext().getResources().getString(R.string.bulkselection_sell_confirmation_title),
|
||||
v.getContext().getResources().getDrawable(android.R.drawable.ic_dialog_info),
|
||||
message,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -20,11 +20,12 @@ import com.gpl.rpg.AndorsTrail.savegames.Savegames;
|
||||
import com.gpl.rpg.AndorsTrail.util.ThemeHelper;
|
||||
import com.gpl.rpg.AndorsTrail.view.CloudsAnimatorView;
|
||||
import com.gpl.rpg.AndorsTrail.view.CustomDialogFactory;
|
||||
import com.gpl.rpg.AndorsTrail.view.CustomDialogFactory.CustomDialog;
|
||||
|
||||
public final class LoadingActivity extends AndorsTrailBaseActivity implements OnResourcesLoadedListener, OnSceneLoadedListener {
|
||||
|
||||
private WorldSetup setup;
|
||||
private Dialog progressDialog;
|
||||
private CustomDialog progressDialog;
|
||||
private CloudsAnimatorView clouds_back, clouds_mid, clouds_front;
|
||||
boolean loaded = false;
|
||||
|
||||
@@ -140,13 +141,18 @@ public final class LoadingActivity extends AndorsTrailBaseActivity implements On
|
||||
|
||||
|
||||
@Override
|
||||
public void onSceneLoaded() {
|
||||
public void onSceneLoaded(Savegames.LoadSavegameResult loadResult) {
|
||||
synchronized (semaphore) {
|
||||
if (progressDialog != null) progressDialog.dismiss();
|
||||
loaded =true;
|
||||
}
|
||||
startActivity(new Intent(this, MainActivity.class));
|
||||
this.finish();
|
||||
|
||||
if (loadResult == Savegames.LoadSavegameResult.editDetected) {
|
||||
showLoadingWarnDialog(R.string.dialog_loading_warning_edit);
|
||||
}else{
|
||||
startActivity(new Intent(this, MainActivity.class));
|
||||
this.finish();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -164,8 +170,21 @@ public final class LoadingActivity extends AndorsTrailBaseActivity implements On
|
||||
}
|
||||
}
|
||||
|
||||
private void showLoadingWarnDialog(int messageResourceID) {
|
||||
final CustomDialog d = CustomDialogFactory.createDialog(this, getResources().getString(R.string.dialog_loading_warning_title), null, getResources().getString(messageResourceID), null, true);
|
||||
CustomDialogFactory.addDismissButton(d, android.R.string.ok);
|
||||
CustomDialogFactory.setDismissListener(d, new OnDismissListener() {
|
||||
@Override
|
||||
public void onDismiss(DialogInterface dialog) {
|
||||
|
||||
startActivity(new Intent(LoadingActivity.this, MainActivity.class));
|
||||
LoadingActivity.this.finish();
|
||||
}
|
||||
});
|
||||
CustomDialogFactory.show(d);
|
||||
}
|
||||
private void showLoadingFailedDialog(int messageResourceID) {
|
||||
final Dialog d = CustomDialogFactory.createDialog(this, getResources().getString(R.string.dialog_loading_failed_title), null, getResources().getString(messageResourceID), null, true);
|
||||
final CustomDialog d = CustomDialogFactory.createDialog(this, getResources().getString(R.string.dialog_loading_failed_title), null, getResources().getString(messageResourceID), null, true);
|
||||
CustomDialogFactory.addDismissButton(d, android.R.string.ok);
|
||||
CustomDialogFactory.setDismissListener(d, new OnDismissListener() {
|
||||
@Override
|
||||
|
||||
@@ -43,6 +43,7 @@ import com.gpl.rpg.AndorsTrail.util.Coord;
|
||||
import com.gpl.rpg.AndorsTrail.util.ThemeHelper;
|
||||
import com.gpl.rpg.AndorsTrail.view.CombatView;
|
||||
import com.gpl.rpg.AndorsTrail.view.CustomDialogFactory;
|
||||
import com.gpl.rpg.AndorsTrail.view.CustomDialogFactory.CustomDialog;
|
||||
import com.gpl.rpg.AndorsTrail.view.DisplayActiveActorConditionIcons;
|
||||
import com.gpl.rpg.AndorsTrail.view.ItemContainerAdapter;
|
||||
import com.gpl.rpg.AndorsTrail.view.MainView;
|
||||
@@ -247,7 +248,7 @@ public final class MainActivity
|
||||
final ItemContainerAdapter inventoryListAdapter = new QuickslotsItemContainerAdapter(lv.getContext(), world.tileManager, world.model.player.inventory.usableItems(), world.model.player, wornTiles);
|
||||
lv.setAdapter(inventoryListAdapter);
|
||||
|
||||
final Dialog d = CustomDialogFactory.createDialog(v.getContext(),
|
||||
final CustomDialog d = CustomDialogFactory.createDialog(v.getContext(),
|
||||
v.getResources().getString(R.string.inventory_assign),
|
||||
v.getResources().getDrawable(R.drawable.ui_icon_equipment),
|
||||
v.getResources().getString(R.string.inventory_selectitem), view, false);
|
||||
|
||||
@@ -11,6 +11,7 @@ import com.gpl.rpg.AndorsTrail.resource.tiles.TileManager;
|
||||
import com.gpl.rpg.AndorsTrail.util.ThemeHelper;
|
||||
import com.gpl.rpg.AndorsTrail.view.CloudsAnimatorView;
|
||||
import com.gpl.rpg.AndorsTrail.view.CustomDialogFactory;
|
||||
import com.gpl.rpg.AndorsTrail.view.CustomDialogFactory.CustomDialog;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.app.Dialog;
|
||||
@@ -114,7 +115,7 @@ public final class StartScreenActivity extends AndorsTrailBaseFragmentActivity i
|
||||
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
||||
if (grantResults.length > 0 && grantResults[0] != PackageManager.PERMISSION_GRANTED) {
|
||||
|
||||
final Dialog d = CustomDialogFactory.createDialog(this,
|
||||
final CustomDialog d = CustomDialogFactory.createDialog(this,
|
||||
getResources().getString(R.string.dialog_permission_information_title),
|
||||
getResources().getDrawable(android.R.drawable.ic_dialog_info),
|
||||
getResources().getString(R.string.dialog_permission_information),
|
||||
|
||||
@@ -38,25 +38,26 @@ import com.gpl.rpg.AndorsTrail.util.AndroidStorage;
|
||||
import com.gpl.rpg.AndorsTrail.util.L;
|
||||
import com.gpl.rpg.AndorsTrail.util.ThemeHelper;
|
||||
import com.gpl.rpg.AndorsTrail.view.CustomDialogFactory;
|
||||
import com.gpl.rpg.AndorsTrail.view.CustomDialogFactory.CustomDialog;
|
||||
|
||||
public class StartScreenActivity_MainMenu extends Fragment {
|
||||
|
||||
private static final int INTENTREQUEST_PREFERENCES = 7;
|
||||
public static final int INTENTREQUEST_LOADGAME = 9;
|
||||
private static final int INTENTREQUEST_PREFERENCES = 7;
|
||||
public static final int INTENTREQUEST_LOADGAME = 9;
|
||||
|
||||
private boolean hasExistingGame = false;
|
||||
private Button startscreen_continue;
|
||||
private Button startscreen_newgame;
|
||||
private Button startscreen_load;
|
||||
private ViewGroup save_preview_holder;
|
||||
private ImageView save_preview_hero_icon;
|
||||
private TextView save_preview_hero_desc;
|
||||
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
updatePreferences(false);
|
||||
super.onCreateView(inflater, container, savedInstanceState);
|
||||
private boolean hasExistingGame = false;
|
||||
private Button startscreen_continue;
|
||||
private Button startscreen_newgame;
|
||||
private Button startscreen_load;
|
||||
private ViewGroup save_preview_holder;
|
||||
private ImageView save_preview_hero_icon;
|
||||
private TextView save_preview_hero_desc;
|
||||
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
updatePreferences(false);
|
||||
super.onCreateView(inflater, container, savedInstanceState);
|
||||
|
||||
|
||||
if (container != null) {
|
||||
@@ -64,11 +65,11 @@ public class StartScreenActivity_MainMenu extends Fragment {
|
||||
}
|
||||
|
||||
View root = inflater.inflate(R.layout.startscreen_mainmenu, container, false);
|
||||
|
||||
|
||||
save_preview_holder = (ViewGroup) root.findViewById(R.id.save_preview_holder);
|
||||
save_preview_hero_icon = (ImageView) root.findViewById(R.id.save_preview_hero_icon);
|
||||
save_preview_hero_desc = (TextView) root.findViewById(R.id.save_preview_hero_desc);
|
||||
|
||||
|
||||
|
||||
startscreen_continue = (Button) root.findViewById(R.id.startscreen_continue);
|
||||
startscreen_continue.setOnClickListener(new OnClickListener() {
|
||||
@@ -114,7 +115,7 @@ public class StartScreenActivity_MainMenu extends Fragment {
|
||||
AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(getActivity());
|
||||
if (hasExistingGame && app != null && app.getWorld() != null && app.getWorld().model != null
|
||||
&& app.getWorld().model.statistics != null && !app.getWorld().model.statistics.hasUnlimitedSaves()) {
|
||||
final Dialog d = CustomDialogFactory.createDialog(getActivity(),
|
||||
final CustomDialog d = CustomDialogFactory.createDialog(getActivity(),
|
||||
getString(R.string.startscreen_load_game),
|
||||
getResources().getDrawable(android.R.drawable.ic_delete),
|
||||
getString(R.string.startscreen_load_game_confirm),
|
||||
@@ -134,7 +135,7 @@ public class StartScreenActivity_MainMenu extends Fragment {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
if (AndorsTrailApplication.DEVELOPMENT_FORCE_STARTNEWGAME) {
|
||||
if (AndorsTrailApplication.DEVELOPMENT_DEBUGRESOURCES) {
|
||||
@@ -152,14 +153,14 @@ public class StartScreenActivity_MainMenu extends Fragment {
|
||||
checkAndRequestPermissions(getActivity());
|
||||
migrateDataOnDemand(getActivity());
|
||||
}
|
||||
|
||||
|
||||
return root;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
|
||||
|
||||
String playerName;
|
||||
String displayInfo = null;
|
||||
int iconID = TileManager.CHAR_HERO;
|
||||
@@ -189,14 +190,10 @@ public class StartScreenActivity_MainMenu extends Fragment {
|
||||
setCurrentVersionForVersionCheck();
|
||||
checkAndRequestPermissions(getActivity());
|
||||
migrateDataOnDemand(getActivity());
|
||||
boolean hasSavegames = !Savegames.getUsedSavegameSlots(getActivity()).isEmpty();
|
||||
startscreen_load.setEnabled(hasSavegames);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
boolean hasSavegames = !Savegames.getUsedSavegameSlots(getActivity()).isEmpty();
|
||||
startscreen_load.setEnabled(hasSavegames);
|
||||
}
|
||||
|
||||
@TargetApi(29)
|
||||
@@ -204,23 +201,16 @@ public class StartScreenActivity_MainMenu extends Fragment {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
if (activity.getApplicationContext().checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
|
||||
if (AndroidStorage.shouldMigrateToInternalStorage(activity.getApplicationContext())) {
|
||||
final Dialog d = CustomDialogFactory.createDialog(activity,
|
||||
final CustomDialog d = CustomDialogFactory.createDialog(activity,
|
||||
getString(R.string.startscreen_migration_title),
|
||||
activity.getResources().getDrawable(android.R.drawable.ic_dialog_alert),
|
||||
getString(R.string.startscreen_migration_text),
|
||||
null,
|
||||
true);
|
||||
CustomDialogFactory.addDismissButton(d, android.R.string.ok);
|
||||
d.setOnDismissListener(new DialogInterface.OnDismissListener() {
|
||||
@Override
|
||||
public void onDismiss(DialogInterface arg0) {
|
||||
boolean hasSavegames = !Savegames.getUsedSavegameSlots(getActivity()).isEmpty();
|
||||
startscreen_load.setEnabled(hasSavegames);
|
||||
}
|
||||
});
|
||||
CustomDialogFactory.show(d);
|
||||
if (!AndroidStorage.migrateToInternalStorage(activity.getApplicationContext())) {
|
||||
final Dialog errorDlg = CustomDialogFactory.createDialog(activity,
|
||||
final CustomDialog errorDlg = CustomDialogFactory.createDialog(activity,
|
||||
getString(R.string.startscreen_migration_title),
|
||||
activity.getResources().getDrawable(android.R.drawable.ic_dialog_alert),
|
||||
getString(R.string.startscreen_migration_failure),
|
||||
@@ -259,13 +249,13 @@ public class StartScreenActivity_MainMenu extends Fragment {
|
||||
super.onAttach(activity);
|
||||
listener = (OnNewGameRequestedListener) activity;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onDetach() {
|
||||
super.onDetach();
|
||||
listener = null;
|
||||
}
|
||||
|
||||
|
||||
private void setButtonState(final String playerName, final String displayInfo, int iconID, boolean isDead) {
|
||||
startscreen_continue.setEnabled(hasExistingGame && !isDead);
|
||||
startscreen_newgame.setEnabled(true);
|
||||
@@ -305,9 +295,9 @@ public class StartScreenActivity_MainMenu extends Fragment {
|
||||
// .create().show();
|
||||
//
|
||||
//
|
||||
final Dialog d = CustomDialogFactory.createDialog(getActivity(),
|
||||
getString(R.string.startscreen_newgame),
|
||||
getResources().getDrawable(android.R.drawable.ic_delete),
|
||||
final CustomDialog d = CustomDialogFactory.createDialog(getActivity(),
|
||||
getString(R.string.startscreen_newgame),
|
||||
getResources().getDrawable(android.R.drawable.ic_delete),
|
||||
getResources().getString(R.string.startscreen_newgame_confirm),
|
||||
null,
|
||||
true);
|
||||
@@ -318,9 +308,9 @@ public class StartScreenActivity_MainMenu extends Fragment {
|
||||
}
|
||||
});
|
||||
CustomDialogFactory.addDismissButton(d, android.R.string.cancel);
|
||||
|
||||
|
||||
CustomDialogFactory.show(d);
|
||||
|
||||
|
||||
}
|
||||
|
||||
private static final String versionCheck = "lastversion";
|
||||
@@ -337,64 +327,90 @@ public class StartScreenActivity_MainMenu extends Fragment {
|
||||
e.putInt(versionCheck, AndorsTrailApplication.CURRENT_VERSION);
|
||||
e.commit();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
switch (requestCode) {
|
||||
case INTENTREQUEST_LOADGAME:
|
||||
if (resultCode != Activity.RESULT_OK) break;
|
||||
final int slot = data.getIntExtra("slot", 1);
|
||||
continueGame(false, slot, null);
|
||||
break;
|
||||
case INTENTREQUEST_PREFERENCES:
|
||||
updatePreferences(true);
|
||||
break;
|
||||
|
||||
@Override
|
||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
switch (requestCode) {
|
||||
case INTENTREQUEST_LOADGAME:
|
||||
boolean unsuccessful = resultCode != Activity.RESULT_OK;
|
||||
if(data == null) break;
|
||||
|
||||
final boolean wasImportOrExport = data.getBooleanExtra("import_export", false);
|
||||
if (wasImportOrExport) {
|
||||
String message = getImportExportMessage(!unsuccessful, data);
|
||||
Toast.makeText(getActivity(), message, Toast.LENGTH_LONG).show();
|
||||
break;
|
||||
}
|
||||
if (unsuccessful) break;
|
||||
final int slot = data.getIntExtra("slot", 1);
|
||||
continueGame(false, slot, null);
|
||||
break;
|
||||
case INTENTREQUEST_PREFERENCES:
|
||||
updatePreferences(true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
private String getImportExportMessage(boolean successful, Intent data) {
|
||||
String message = "";
|
||||
boolean isImportWorldmap = data.getBooleanExtra("import_worldmap", false);
|
||||
boolean isImportSaves = data.getBooleanExtra("import_savegames", false);
|
||||
boolean isExport = data.getBooleanExtra("export", false);
|
||||
|
||||
if(isImportWorldmap) {
|
||||
message = getString(successful ? R.string.loadsave_import_worldmap_successfull : R.string.loadsave_import_worldmap_unsuccessfull);
|
||||
} else if(isImportSaves) {
|
||||
message = getString(successful ? R.string.loadsave_import_save_successfull : R.string.loadsave_import_save_unsuccessfull);
|
||||
} else if(isExport) {
|
||||
message = getString(successful ? R.string.loadsave_export_successfull : R.string.loadsave_export_unsuccessfull);
|
||||
}
|
||||
|
||||
return message;
|
||||
}
|
||||
|
||||
|
||||
private void updatePreferences(boolean alreadyStartedLoadingResources) {
|
||||
AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(getActivity());
|
||||
AndorsTrailPreferences preferences = app.getPreferences();
|
||||
preferences.read(getActivity());
|
||||
if (app.setLocale(getActivity())) {
|
||||
if (alreadyStartedLoadingResources) {
|
||||
// Changing the locale after having loaded the game requires resources to
|
||||
// be re-loaded. Therefore, we just exit here.
|
||||
Toast.makeText(getActivity(), R.string.change_locale_requires_restart, Toast.LENGTH_LONG).show();
|
||||
doFinish();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (ThemeHelper.changeTheme(preferences.selectedTheme)) {
|
||||
// Changing the theme requires a restart to re-create all activities.
|
||||
Toast.makeText(getActivity(), R.string.change_theme_requires_restart, Toast.LENGTH_LONG).show();
|
||||
doFinish();
|
||||
return;
|
||||
}
|
||||
app.getWorld().tileManager.updatePreferences(preferences);
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
private void doFinish() {
|
||||
//For Lollipop and above
|
||||
((AndorsTrailApplication)getActivity().getApplication()).discardWorld();
|
||||
getActivity().finish();
|
||||
}
|
||||
AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(getActivity());
|
||||
AndorsTrailPreferences preferences = app.getPreferences();
|
||||
preferences.read(getActivity());
|
||||
if (app.setLocale(getActivity())) {
|
||||
if (alreadyStartedLoadingResources) {
|
||||
// Changing the locale after having loaded the game requires resources to
|
||||
// be re-loaded. Therefore, we just exit here.
|
||||
Toast.makeText(getActivity(), R.string.change_locale_requires_restart, Toast.LENGTH_LONG).show();
|
||||
doFinish();
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (ThemeHelper.changeTheme(preferences.selectedTheme)) {
|
||||
// Changing the theme requires a restart to re-create all activities.
|
||||
Toast.makeText(getActivity(), R.string.change_theme_requires_restart, Toast.LENGTH_LONG).show();
|
||||
doFinish();
|
||||
return;
|
||||
}
|
||||
app.getWorld().tileManager.updatePreferences(preferences);
|
||||
}
|
||||
|
||||
@SuppressLint("NewApi")
|
||||
private void doFinish() {
|
||||
//For Lollipop and above
|
||||
((AndorsTrailApplication) getActivity().getApplication()).discardWorld();
|
||||
getActivity().finish();
|
||||
}
|
||||
|
||||
|
||||
|
||||
public interface OnNewGameRequestedListener {
|
||||
public void onNewGameRequested();
|
||||
}
|
||||
|
||||
|
||||
private OnNewGameRequestedListener listener = null;
|
||||
|
||||
|
||||
private void createNewGame() {
|
||||
if (listener != null) {
|
||||
listener.onNewGameRequested();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package com.gpl.rpg.AndorsTrail.context;
|
||||
|
||||
import android.os.Build;
|
||||
import android.support.annotation.RequiresApi;
|
||||
|
||||
import com.gpl.rpg.AndorsTrail.model.ModelContainer;
|
||||
import com.gpl.rpg.AndorsTrail.model.ability.ActorConditionTypeCollection;
|
||||
import com.gpl.rpg.AndorsTrail.model.ability.SkillCollection;
|
||||
@@ -12,6 +15,10 @@ import com.gpl.rpg.AndorsTrail.model.quest.QuestCollection;
|
||||
import com.gpl.rpg.AndorsTrail.resource.ConversationLoader;
|
||||
import com.gpl.rpg.AndorsTrail.resource.VisualEffectCollection;
|
||||
import com.gpl.rpg.AndorsTrail.resource.tiles.TileManager;
|
||||
import com.gpl.rpg.AndorsTrail.util.ByteUtils;
|
||||
|
||||
import java.security.MessageDigest;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
|
||||
public final class WorldContext {
|
||||
//Objectcollections
|
||||
@@ -62,4 +69,13 @@ public final class WorldContext {
|
||||
public void resetForNewGame() {
|
||||
maps.resetForNewGame();
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
|
||||
public String createHash() throws NoSuchAlgorithmException {
|
||||
MessageDigest digest = MessageDigest.getInstance("MD5");
|
||||
this.maps.createHash(digest);
|
||||
this.model.createHash(digest);
|
||||
byte[] hash = digest.digest();
|
||||
return ByteUtils.toHexString(hash);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ import com.gpl.rpg.AndorsTrail.util.ConstRange;
|
||||
import com.gpl.rpg.AndorsTrail.util.Range;
|
||||
|
||||
public final class Constants {
|
||||
public static final int PERCENT_EXP_LOST_WHEN_DIED = 30;
|
||||
public static final int PERCENT_EXP_LOST_WHEN_DIED = 20;
|
||||
public static final int LEVELUP_EFFECT_HEALTH = 5;
|
||||
public static final int LEVELUP_EFFECT_ATK_CH = 5;
|
||||
public static final int LEVELUP_EFFECT_ATK_DMG = 1;
|
||||
@@ -51,6 +51,10 @@ public final class Constants {
|
||||
public static final String CHEAT_DETECTION_FOLDER = "dEAGyGE3YojqXjI3x4x7";
|
||||
public static final String PASSIVE_ACHIEVEMENT_CHECK_PHRASE = "passive_achievement_check";
|
||||
|
||||
public static final String SAVEGAME_FILE_MIME_TYPE = "application/octet-stream";
|
||||
public static final String WORLDMAP_FILE_MIME_TYPE = "image/png";
|
||||
public static final String NO_FILE_EXTENSION_MIME_TYPE = "application/no_file_extension_mime_type";
|
||||
|
||||
public static final Random rnd = new Random();
|
||||
public static int rollValue(final ConstRange r) { return rollValue(r.max, r.current); }
|
||||
public static int rollValue(final ConstRange r, int bias) { return rollValue((r.max + 1) * 100 -1, r.current * 100 + bias)/100; }
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.gpl.rpg.AndorsTrail.model;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
@@ -12,6 +13,8 @@ import java.util.Map.Entry;
|
||||
import java.util.Set;
|
||||
|
||||
import android.content.res.Resources;
|
||||
import android.os.Build;
|
||||
import android.support.annotation.RequiresApi;
|
||||
|
||||
import com.gpl.rpg.AndorsTrail.R;
|
||||
import com.gpl.rpg.AndorsTrail.context.WorldContext;
|
||||
@@ -19,6 +22,7 @@ import com.gpl.rpg.AndorsTrail.model.actor.MonsterType;
|
||||
import com.gpl.rpg.AndorsTrail.model.item.ItemType;
|
||||
import com.gpl.rpg.AndorsTrail.model.map.PredefinedMap;
|
||||
import com.gpl.rpg.AndorsTrail.model.quest.Quest;
|
||||
import com.gpl.rpg.AndorsTrail.util.ByteUtils;
|
||||
import com.gpl.rpg.AndorsTrail.util.HashMapHelper;
|
||||
|
||||
public final class GameStatistics {
|
||||
@@ -214,4 +218,21 @@ public final class GameStatistics {
|
||||
dest.writeInt(startLives);
|
||||
dest.writeBoolean(unlimitedSaves);
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
|
||||
public void createHash(MessageDigest digest) {
|
||||
digest.update(ByteUtils.toBytes(deaths));
|
||||
|
||||
for (Entry<String, Integer> e : killedMonstersByTypeID.entrySet()) {
|
||||
digest.update(ByteUtils.toBytes(e.getKey()));
|
||||
digest.update(ByteUtils.toBytes(e.getValue()));
|
||||
}
|
||||
for (Entry<String, Integer> e : usedItems.entrySet()) {
|
||||
digest.update(ByteUtils.toBytes(e.getKey()));
|
||||
digest.update(ByteUtils.toBytes(e.getValue()));
|
||||
}
|
||||
digest.update(ByteUtils.toBytes(spentGold));
|
||||
digest.update(ByteUtils.toBytes(startLives));
|
||||
digest.update(ByteUtils.toBytes(unlimitedSaves));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,8 +3,10 @@ package com.gpl.rpg.AndorsTrail.model;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.MessageDigest;
|
||||
|
||||
import com.gpl.rpg.AndorsTrail.model.actor.Monster;
|
||||
import com.gpl.rpg.AndorsTrail.util.ByteUtils;
|
||||
import com.gpl.rpg.AndorsTrail.util.Coord;
|
||||
|
||||
public final class InterfaceData {
|
||||
@@ -51,4 +53,12 @@ public final class InterfaceData {
|
||||
}
|
||||
dest.writeUTF(selectedTabHeroInfo);
|
||||
}
|
||||
|
||||
public void createHash(MessageDigest digest) {
|
||||
digest.update(ByteUtils.toBytes(isMainActivityVisible));
|
||||
digest.update(ByteUtils.toBytes(isInCombat));
|
||||
if(selectedPosition != null){
|
||||
selectedPosition.createHash(digest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,12 +1,17 @@
|
||||
package com.gpl.rpg.AndorsTrail.model;
|
||||
|
||||
import android.os.Build;
|
||||
import android.support.annotation.RequiresApi;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.MessageDigest;
|
||||
|
||||
import com.gpl.rpg.AndorsTrail.context.ControllerContext;
|
||||
import com.gpl.rpg.AndorsTrail.context.WorldContext;
|
||||
import com.gpl.rpg.AndorsTrail.model.actor.Player;
|
||||
import com.gpl.rpg.AndorsTrail.util.ByteUtils;
|
||||
|
||||
public final class ModelContainer {
|
||||
|
||||
@@ -49,4 +54,14 @@ public final class ModelContainer {
|
||||
statistics.writeToParcel(dest);
|
||||
worldData.writeToParcel(dest);
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
|
||||
public void createHash(MessageDigest digest) {
|
||||
player.createHash(digest);
|
||||
digest.update(ByteUtils.toBytes(currentMaps.map.name));
|
||||
uiSelections.createHash(digest);
|
||||
statistics.createHash(digest);
|
||||
worldData.createHash(digest);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,14 @@
|
||||
package com.gpl.rpg.AndorsTrail.model;
|
||||
|
||||
import android.os.Build;
|
||||
import android.support.annotation.RequiresApi;
|
||||
|
||||
import com.gpl.rpg.AndorsTrail.util.ByteUtils;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
@@ -56,4 +62,13 @@ public final class WorldData {
|
||||
dest.writeLong(e.getValue());
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
|
||||
public void createHash(MessageDigest digest) {
|
||||
digest.update(ByteUtils.toBytes(worldTime));
|
||||
for (Map.Entry<String, Long> e: timers.entrySet() ) {
|
||||
digest.update(ByteUtils.toBytes(e.getKey()));
|
||||
digest.update(ByteUtils.toBytes(e.getValue()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
package com.gpl.rpg.AndorsTrail.model.ability;
|
||||
|
||||
import android.os.Build;
|
||||
import android.support.annotation.RequiresApi;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.MessageDigest;
|
||||
|
||||
import com.gpl.rpg.AndorsTrail.context.WorldContext;
|
||||
import com.gpl.rpg.AndorsTrail.util.ByteUtils;
|
||||
|
||||
public final class ActorCondition {
|
||||
public static final int MAGNITUDE_REMOVE_ALL = -99;
|
||||
@@ -45,4 +50,12 @@ public final class ActorCondition {
|
||||
dest.writeInt(magnitude);
|
||||
dest.writeInt(duration);
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
|
||||
public void createHash(MessageDigest digest) {
|
||||
digest.update(ByteUtils.toBytes(conditionType.conditionTypeID));
|
||||
digest.update(ByteUtils.toBytes(magnitude));
|
||||
digest.update(ByteUtils.toBytes(duration));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -83,7 +83,7 @@ public final class SkillCollection {
|
||||
public static final int PER_SKILLPOINT_INCREASE_COINFINDER_CHANCE_PERCENT = 30;
|
||||
public static final int PER_SKILLPOINT_INCREASE_MAGICFINDER_CHANCE_PERCENT = 50;
|
||||
public static final int PER_SKILLPOINT_INCREASE_COINFINDER_QUANTITY_PERCENT = 50;
|
||||
public static final int PER_SKILLPOINT_INCREASE_MORE_EXP_PERCENT = 5;
|
||||
public static final int PER_SKILLPOINT_INCREASE_MORE_EXP_PERCENT = 10;
|
||||
public static final int PER_SKILLPOINT_INCREASE_CLEAVE_AP = 3;
|
||||
public static final int PER_SKILLPOINT_INCREASE_EATER_HEALTH = 1;
|
||||
public static final int PER_SKILLPOINT_INCREASE_FORTITUDE_HEALTH = 1;
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
package com.gpl.rpg.AndorsTrail.model.actor;
|
||||
|
||||
import android.os.Build;
|
||||
import android.support.annotation.RequiresApi;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.MessageDigest;
|
||||
|
||||
import com.gpl.rpg.AndorsTrail.context.WorldContext;
|
||||
import com.gpl.rpg.AndorsTrail.controller.Constants;
|
||||
@@ -13,6 +17,7 @@ import com.gpl.rpg.AndorsTrail.model.item.ItemContainer;
|
||||
import com.gpl.rpg.AndorsTrail.model.item.Loot;
|
||||
import com.gpl.rpg.AndorsTrail.model.map.MonsterSpawnArea;
|
||||
import com.gpl.rpg.AndorsTrail.savegames.LegacySavegameFormatReaderForMonster;
|
||||
import com.gpl.rpg.AndorsTrail.util.ByteUtils;
|
||||
import com.gpl.rpg.AndorsTrail.util.Coord;
|
||||
import com.gpl.rpg.AndorsTrail.util.CoordRect;
|
||||
import com.gpl.rpg.AndorsTrail.util.Range;
|
||||
@@ -193,4 +198,28 @@ public final class Monster extends Actor {
|
||||
dest.writeBoolean(false);
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
|
||||
public void createHash(MessageDigest digest) {
|
||||
digest.update(ByteUtils.toBytes(getMonsterTypeID()));
|
||||
digest.update(ByteUtils.toBytes(attackCost));
|
||||
digest.update(ByteUtils.toBytes(attackChance));
|
||||
digest.update(ByteUtils.toBytes(criticalSkill));
|
||||
digest.update(ByteUtils.toBytes(criticalMultiplier));
|
||||
damagePotential.createHash(digest);
|
||||
digest.update(ByteUtils.toBytes(blockChance));
|
||||
digest.update(ByteUtils.toBytes(damageResistance));
|
||||
ap.createHash(digest);
|
||||
health.createHash(digest);
|
||||
position.createHash(digest);
|
||||
for (ActorCondition c: conditions){
|
||||
c.createHash(digest);
|
||||
}
|
||||
|
||||
digest.update(ByteUtils.toBytes(moveCost));
|
||||
digest.update(ByteUtils.toBytes(forceAggressive));
|
||||
if (shopItems != null) {
|
||||
shopItems.createHash(digest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.gpl.rpg.AndorsTrail.model.actor;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@@ -13,6 +14,8 @@ import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.UUID;
|
||||
|
||||
import android.os.Build;
|
||||
import android.support.annotation.RequiresApi;
|
||||
import android.util.SparseIntArray;
|
||||
|
||||
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
|
||||
@@ -27,6 +30,7 @@ import com.gpl.rpg.AndorsTrail.model.item.Loot;
|
||||
import com.gpl.rpg.AndorsTrail.model.quest.Quest;
|
||||
import com.gpl.rpg.AndorsTrail.model.quest.QuestProgress;
|
||||
import com.gpl.rpg.AndorsTrail.savegames.LegacySavegameFormatReaderForPlayer;
|
||||
import com.gpl.rpg.AndorsTrail.util.ByteUtils;
|
||||
import com.gpl.rpg.AndorsTrail.util.Coord;
|
||||
import com.gpl.rpg.AndorsTrail.util.Range;
|
||||
import com.gpl.rpg.AndorsTrail.util.Size;
|
||||
@@ -55,9 +59,11 @@ public final class Player extends Actor {
|
||||
public String id = UUID.randomUUID().toString();
|
||||
public long savedVersion = 1; // the version get's increased for cheat detection everytime a player with limited saves is saved
|
||||
|
||||
public boolean wasEditingDetected;
|
||||
public String hash;
|
||||
|
||||
|
||||
// Unequipped stats
|
||||
// Unequipped stats
|
||||
public static final class PlayerBaseTraits {
|
||||
public int iconID;
|
||||
public int maxAP;
|
||||
@@ -111,7 +117,7 @@ public final class Player extends Actor {
|
||||
baseTraits.criticalSkill = 0;
|
||||
baseTraits.criticalMultiplier = 1;
|
||||
baseTraits.damagePotential.set(1, 1);
|
||||
baseTraits.blockChance = 0;
|
||||
baseTraits.blockChance = 9;
|
||||
baseTraits.damageResistance = 0;
|
||||
baseTraits.useItemCost = 5;
|
||||
baseTraits.reequipCost = 5;
|
||||
@@ -416,6 +422,13 @@ public final class Player extends Actor {
|
||||
this.id = src.readUTF();
|
||||
this.savedVersion = src.readLong();
|
||||
}
|
||||
if (fileversion >= 71){
|
||||
this.hash = src.readUTF();
|
||||
this.wasEditingDetected = src.readBoolean();
|
||||
}else{
|
||||
this.hash = "";
|
||||
this.wasEditingDetected = false;
|
||||
}
|
||||
}
|
||||
|
||||
public void writeToParcel(DataOutputStream dest) throws IOException {
|
||||
@@ -474,6 +487,58 @@ public final class Player extends Actor {
|
||||
}
|
||||
dest.writeUTF(id);
|
||||
dest.writeLong(savedVersion);
|
||||
dest.writeUTF(hash);
|
||||
dest.writeBoolean(wasEditingDetected);
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
|
||||
public void createHash(MessageDigest digest) {
|
||||
//skipping icon ID so that it can be changed without hash difference
|
||||
digest.update(ByteUtils.toBytes(baseTraits.maxAP));
|
||||
digest.update(ByteUtils.toBytes(baseTraits.maxHP));
|
||||
//skipping name so that it can be changed without hash difference
|
||||
digest.update(ByteUtils.toBytes(moveCost));
|
||||
digest.update(ByteUtils.toBytes(baseTraits.attackCost));
|
||||
digest.update(ByteUtils.toBytes(baseTraits.attackChance));
|
||||
digest.update(ByteUtils.toBytes(baseTraits.criticalSkill));
|
||||
digest.update(ByteUtils.toBytes(baseTraits.criticalMultiplier));
|
||||
baseTraits.damagePotential.createHash(digest);
|
||||
digest.update(ByteUtils.toBytes(baseTraits.blockChance));
|
||||
digest.update(ByteUtils.toBytes(baseTraits.damageResistance));
|
||||
digest.update(ByteUtils.toBytes(baseTraits.moveCost));
|
||||
ap.createHash(digest);
|
||||
health.createHash(digest);
|
||||
position.createHash(digest);
|
||||
for(ActorCondition c : conditions){
|
||||
c.createHash(digest);
|
||||
}
|
||||
lastPosition.createHash(digest);
|
||||
nextPosition.createHash(digest);
|
||||
digest.update(ByteUtils.toBytes(level));
|
||||
digest.update(ByteUtils.toBytes(totalExperience));
|
||||
inventory.createHash(digest);
|
||||
digest.update(ByteUtils.toBytes(baseTraits.useItemCost));
|
||||
digest.update(ByteUtils.toBytes(baseTraits.reequipCost));
|
||||
for (int i = 0; i<skillLevels.size(); i++){
|
||||
digest.update(ByteUtils.toBytes(skillLevels.keyAt(i)));
|
||||
digest.update(ByteUtils.toBytes(skillLevels.valueAt(i)));
|
||||
}
|
||||
digest.update(ByteUtils.toBytes(spawnMap));
|
||||
digest.update(ByteUtils.toBytes(spawnPlace));
|
||||
for (Entry<String, LinkedHashSet<Integer> > e:questProgress.entrySet() ) {
|
||||
digest.update(ByteUtils.toBytes(e.getKey()));
|
||||
for(int progress: e.getValue()){
|
||||
digest.update(ByteUtils.toBytes(progress));
|
||||
}
|
||||
}
|
||||
digest.update(ByteUtils.toBytes(availableSkillIncreases));
|
||||
for (Entry<String, Integer> e:alignments.entrySet() ) {
|
||||
digest.update(ByteUtils.toBytes(e.getKey()));
|
||||
digest.update(ByteUtils.toBytes(e.getValue()));
|
||||
}
|
||||
digest.update(ByteUtils.toBytes(id));
|
||||
// digest.update(ByteUtils.toBytes(savedVersion));
|
||||
// digest.update(ByteUtils.toBytes(wasEditingDetected));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
package com.gpl.rpg.AndorsTrail.model.item;
|
||||
|
||||
import android.os.Build;
|
||||
import android.support.annotation.RequiresApi;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
|
||||
import com.gpl.rpg.AndorsTrail.context.WorldContext;
|
||||
import com.gpl.rpg.AndorsTrail.model.actor.Player;
|
||||
import com.gpl.rpg.AndorsTrail.util.ByteUtils;
|
||||
|
||||
public class ItemContainer {
|
||||
public final ArrayList<ItemEntry> items = new ArrayList<ItemEntry>();
|
||||
@@ -23,7 +28,8 @@ public class ItemContainer {
|
||||
return result;
|
||||
}
|
||||
|
||||
public static final class ItemEntry {
|
||||
|
||||
public static final class ItemEntry {
|
||||
public final ItemType itemType;
|
||||
public int quantity;
|
||||
public ItemEntry(ItemType itemType, int initialQuantity) {
|
||||
@@ -42,6 +48,12 @@ public class ItemContainer {
|
||||
dest.writeUTF(itemType.id);
|
||||
dest.writeInt(quantity);
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
|
||||
public void createHash(MessageDigest digest) {
|
||||
digest.update(ByteUtils.toBytes(itemType.id));
|
||||
digest.update(ByteUtils.toBytes(quantity));
|
||||
}
|
||||
}
|
||||
|
||||
public void addItem(ItemType itemType, int quantity) {
|
||||
@@ -280,4 +292,12 @@ public class ItemContainer {
|
||||
e.writeToParcel(dest);
|
||||
}
|
||||
}
|
||||
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
|
||||
public void createHash(MessageDigest digest) {
|
||||
for (ItemEntry e :
|
||||
items) {
|
||||
e.createHash(digest);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,11 +1,16 @@
|
||||
package com.gpl.rpg.AndorsTrail.model.item;
|
||||
|
||||
import android.os.Build;
|
||||
import android.support.annotation.RequiresApi;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.MessageDigest;
|
||||
|
||||
import com.gpl.rpg.AndorsTrail.context.WorldContext;
|
||||
import com.gpl.rpg.AndorsTrail.savegames.LegacySavegameFormatReaderForItemContainer;
|
||||
import com.gpl.rpg.AndorsTrail.util.ByteUtils;
|
||||
import com.gpl.rpg.AndorsTrail.util.Coord;
|
||||
|
||||
public final class Loot {
|
||||
@@ -88,4 +93,13 @@ public final class Loot {
|
||||
position.writeToParcel(dest);
|
||||
dest.writeBoolean(isVisible);
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
|
||||
public void createHash(MessageDigest digest) {
|
||||
digest.update(ByteUtils.toBytes(exp));
|
||||
digest.update(ByteUtils.toBytes(exp));
|
||||
items.createHash(digest);
|
||||
position.createHash(digest);
|
||||
digest.update(ByteUtils.toBytes(isVisible));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
package com.gpl.rpg.AndorsTrail.model.map;
|
||||
|
||||
import android.os.Build;
|
||||
import android.support.annotation.RequiresApi;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
@@ -88,15 +92,27 @@ public final class MapCollection {
|
||||
return false;
|
||||
}
|
||||
|
||||
public void writeToParcel(DataOutputStream dest, WorldContext world) throws IOException {
|
||||
private List<PredefinedMap> getAllSavedMaps(WorldContext world) {
|
||||
List<PredefinedMap> mapsToExport = new ArrayList<PredefinedMap>();
|
||||
for(PredefinedMap map : getAllMaps()) {
|
||||
if (shouldSaveMap(world, map)) mapsToExport.add(map);
|
||||
}
|
||||
return mapsToExport;
|
||||
}
|
||||
|
||||
public void writeToParcel(DataOutputStream dest, WorldContext world) throws IOException {
|
||||
List<PredefinedMap> mapsToExport = getAllSavedMaps(world);
|
||||
dest.writeInt(mapsToExport.size());
|
||||
for(PredefinedMap map : mapsToExport) {
|
||||
dest.writeUTF(map.name);
|
||||
map.writeToParcel(dest, world);
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
|
||||
public void createHash(MessageDigest digest) {
|
||||
for (PredefinedMap map : getAllMaps()) {
|
||||
map.createHash(digest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
package com.gpl.rpg.AndorsTrail.model.map;
|
||||
|
||||
import android.os.Build;
|
||||
import android.support.annotation.RequiresApi;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CopyOnWriteArrayList;
|
||||
|
||||
@@ -10,6 +14,7 @@ import com.gpl.rpg.AndorsTrail.context.WorldContext;
|
||||
import com.gpl.rpg.AndorsTrail.controller.Constants;
|
||||
import com.gpl.rpg.AndorsTrail.model.actor.Monster;
|
||||
import com.gpl.rpg.AndorsTrail.model.actor.MonsterType;
|
||||
import com.gpl.rpg.AndorsTrail.util.ByteUtils;
|
||||
import com.gpl.rpg.AndorsTrail.util.Coord;
|
||||
import com.gpl.rpg.AndorsTrail.util.CoordRect;
|
||||
import com.gpl.rpg.AndorsTrail.util.Range;
|
||||
@@ -140,4 +145,13 @@ public final class MonsterSpawnArea {
|
||||
m.writeToParcel(dest);
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
|
||||
public void createHash(MessageDigest digest) {
|
||||
digest.update(ByteUtils.toBytes(isSpawning));
|
||||
for (Monster m :
|
||||
monsters) {
|
||||
m.createHash(digest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
package com.gpl.rpg.AndorsTrail.model.map;
|
||||
|
||||
import android.os.Build;
|
||||
import android.support.annotation.RequiresApi;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.MessageDigest;
|
||||
import java.util.ArrayList;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
@@ -16,6 +20,7 @@ import com.gpl.rpg.AndorsTrail.model.actor.Monster;
|
||||
import com.gpl.rpg.AndorsTrail.model.item.ItemType;
|
||||
import com.gpl.rpg.AndorsTrail.model.item.Loot;
|
||||
import com.gpl.rpg.AndorsTrail.model.map.MapObject.MapObjectType;
|
||||
import com.gpl.rpg.AndorsTrail.util.ByteUtils;
|
||||
import com.gpl.rpg.AndorsTrail.util.Coord;
|
||||
import com.gpl.rpg.AndorsTrail.util.CoordRect;
|
||||
import com.gpl.rpg.AndorsTrail.util.L;
|
||||
@@ -340,6 +345,7 @@ public final class PredefinedMap {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
currentColorFilter = null;
|
||||
activeMapObjectGroups.clear();
|
||||
activeMapObjectGroups.addAll(initiallyActiveMapObjectGroups);
|
||||
activateMapObjects();
|
||||
@@ -360,16 +366,20 @@ public final class PredefinedMap {
|
||||
}
|
||||
|
||||
public boolean shouldSaveMapData(WorldContext world) {
|
||||
if (!hasResetTemporaryData()) return true;
|
||||
if (this == world.model.currentMaps.map) return true;
|
||||
return mapDataNeedsToBeSaved();
|
||||
}
|
||||
|
||||
private boolean mapDataNeedsToBeSaved() {
|
||||
if (!hasResetTemporaryData()) return true;
|
||||
if (!groundBags.isEmpty()) return true;
|
||||
for (MonsterSpawnArea a : spawnAreas) {
|
||||
if (this.visited && a.isUnique) return true;
|
||||
if (a.isSpawning != a.isSpawningForNewGame) return true;
|
||||
}
|
||||
if (!activeMapObjectGroups.containsAll(initiallyActiveMapObjectGroups)
|
||||
|| !initiallyActiveMapObjectGroups.containsAll(activeMapObjectGroups)) return true;
|
||||
if (currentColorFilter != null) return true;
|
||||
if (!activeMapObjectGroups.containsAll(initiallyActiveMapObjectGroups)
|
||||
|| !initiallyActiveMapObjectGroups.containsAll(activeMapObjectGroups)) return true;
|
||||
if (currentColorFilter != null && !currentColorFilter.equals(initialColorFilter)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -398,4 +408,23 @@ public final class PredefinedMap {
|
||||
dest.writeBoolean(visited);
|
||||
dest.writeUTF(lastSeenLayoutHash);
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
|
||||
public void createHash(MessageDigest digest) {
|
||||
if (mapDataNeedsToBeSaved()) {
|
||||
for (MonsterSpawnArea a : spawnAreas) {
|
||||
a.createHash(digest);
|
||||
}
|
||||
for (String g : activeMapObjectGroups) {
|
||||
digest.update(ByteUtils.toBytes(g));
|
||||
}
|
||||
for (Loot l : groundBags) {
|
||||
l.createHash(digest);
|
||||
}
|
||||
digest.update(ByteUtils.toBytes(currentColorFilter));
|
||||
//skip lastVisitTime since it is too volatile
|
||||
}
|
||||
digest.update( ByteUtils.toBytes(visited));
|
||||
digest.update( ByteUtils.toBytes(lastSeenLayoutHash));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -308,6 +308,7 @@ public final class ResourceLoader {
|
||||
loader.prepareTileset(R.drawable.items_consumables_omi1, "items_consumables_omi1", sz1x1, sz1x1, mTileSize);
|
||||
loader.prepareTileset(R.drawable.items_feygard1, "items_feygard1", new Size(6, 2), sz1x1, mTileSize);
|
||||
loader.prepareTileset(R.drawable.items_omi2, "items_omi2", new Size(6, 5), sz1x1, mTileSize);
|
||||
loader.prepareTileset(R.drawable.items_omgeeky, "items_omgeeky", new Size(10, 3), sz1x1, mTileSize);
|
||||
/*INSERT_ITEMS_TILESETS_HERE*/
|
||||
|
||||
loader.prepareTileset(R.drawable.monsters_armor1, "monsters_armor1", sz1x1, sz1x1, mTileSize);
|
||||
@@ -435,6 +436,7 @@ public final class ResourceLoader {
|
||||
loader.prepareTileset(R.drawable.map_rock_3, "map_rock_3", new Size(6, 5), sz1x1, mTileSize);
|
||||
loader.prepareTileset(R.drawable.map_sign_ladder_omi2, "map_sign_ladder_omi2", new Size(8, 4), sz1x1, mTileSize);
|
||||
loader.prepareTileset(R.drawable.map_transition_6, "map_transition_6", new Size(18, 8), sz1x1, mTileSize);
|
||||
loader.prepareTileset(R.drawable.map_ratdom, "map_ratdom", new Size(18, 6), sz1x1, mTileSize);
|
||||
/*INSERT_MAP_TILESETS_HERE*/
|
||||
|
||||
loader.prepareTileset(R.drawable.effect_blood4, "effect_blood4", new Size(7, 2), sz1x1, mTileSize);
|
||||
|
||||
@@ -12,6 +12,7 @@ import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintWriter;
|
||||
import java.io.StringWriter;
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
@@ -20,6 +21,7 @@ import java.util.regex.Pattern;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Build;
|
||||
import android.os.SystemClock;
|
||||
|
||||
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
|
||||
@@ -42,6 +44,7 @@ public final class Savegames {
|
||||
|
||||
public static enum LoadSavegameResult {
|
||||
success
|
||||
, editDetected
|
||||
, unknownError
|
||||
, savegameIsFromAFutureVersion
|
||||
, cheatingDetected
|
||||
@@ -78,7 +81,7 @@ public final class Savegames {
|
||||
}
|
||||
|
||||
return true;
|
||||
} catch (IOException e) {
|
||||
} catch (IOException | NoSuchAlgorithmException e) {
|
||||
L.log("Error saving world: " + e.toString());
|
||||
return false;
|
||||
}
|
||||
@@ -86,7 +89,7 @@ public final class Savegames {
|
||||
|
||||
private static void writeBackup(Context androidContext, byte[] savegame, String playerId) throws IOException {
|
||||
File cheatDetectionFolder = AndroidStorage.getStorageDirectory(androidContext, Constants.CHEAT_DETECTION_FOLDER);
|
||||
if (!cheatDetectionFolder.exists()) cheatDetectionFolder.mkdir();
|
||||
ensureDirExists(cheatDetectionFolder);
|
||||
File backupFile = new File(cheatDetectionFolder, playerId + "X");
|
||||
FileOutputStream fileOutputStream = new FileOutputStream(backupFile);
|
||||
fileOutputStream.write(savegame);
|
||||
@@ -127,34 +130,33 @@ public final class Savegames {
|
||||
}
|
||||
}
|
||||
|
||||
private static boolean triedToCheat(Context androidContext, FileHeader fh) throws IOException {
|
||||
long savedVersionToCheck = 0;
|
||||
File cheatDetectionFolder = AndroidStorage.getStorageDirectory(androidContext, Constants.CHEAT_DETECTION_FOLDER);
|
||||
if (!cheatDetectionFolder.exists()) cheatDetectionFolder.mkdir();
|
||||
File cheatDetectionFile = new File(cheatDetectionFolder, fh.playerId);
|
||||
if (cheatDetectionFile.exists()) {
|
||||
FileInputStream fileInputStream = new FileInputStream(cheatDetectionFile);
|
||||
DataInputStream dataInputStream = new DataInputStream(fileInputStream);
|
||||
final CheatDetection cheatDetection = new CheatDetection(dataInputStream);
|
||||
savedVersionToCheck = cheatDetection.savedVersion;
|
||||
dataInputStream.close();
|
||||
fileInputStream.close();
|
||||
}
|
||||
private static boolean triedToCheat(Context androidContext, FileHeader fh) throws IOException {
|
||||
long savedVersionToCheck = 0;
|
||||
File cheatDetectionFolder = AndroidStorage.getStorageDirectory(androidContext, Constants.CHEAT_DETECTION_FOLDER);
|
||||
ensureDirExists(cheatDetectionFolder);
|
||||
File cheatDetectionFile = new File(cheatDetectionFolder, fh.playerId);
|
||||
if (cheatDetectionFile.exists()) {
|
||||
FileInputStream fileInputStream = new FileInputStream(cheatDetectionFile);
|
||||
DataInputStream dataInputStream = new DataInputStream(fileInputStream);
|
||||
final CheatDetection cheatDetection = new CheatDetection(dataInputStream);
|
||||
savedVersionToCheck = cheatDetection.savedVersion;
|
||||
dataInputStream.close();
|
||||
fileInputStream.close();
|
||||
}
|
||||
|
||||
if (savedVersionToCheck == DENY_LOADING_BECAUSE_GAME_IS_CURRENTLY_PLAYED) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (androidContext.getFileStreamPath(fh.playerId).exists()) {
|
||||
FileInputStream fileInputStream = androidContext.openFileInput(fh.playerId);
|
||||
DataInputStream dataInputStream = new DataInputStream(fileInputStream);
|
||||
final CheatDetection cheatDetection = new CheatDetection(dataInputStream);
|
||||
if (cheatDetection.savedVersion == DENY_LOADING_BECAUSE_GAME_IS_CURRENTLY_PLAYED) {
|
||||
savedVersionToCheck = DENY_LOADING_BECAUSE_GAME_IS_CURRENTLY_PLAYED;
|
||||
}
|
||||
else if (cheatDetection.savedVersion > savedVersionToCheck) {
|
||||
savedVersionToCheck = cheatDetection.savedVersion;
|
||||
}
|
||||
if (androidContext.getFileStreamPath(fh.playerId).exists()) {
|
||||
FileInputStream fileInputStream = androidContext.openFileInput(fh.playerId);
|
||||
DataInputStream dataInputStream = new DataInputStream(fileInputStream);
|
||||
final CheatDetection cheatDetection = new CheatDetection(dataInputStream);
|
||||
if (cheatDetection.savedVersion == DENY_LOADING_BECAUSE_GAME_IS_CURRENTLY_PLAYED) {
|
||||
savedVersionToCheck = DENY_LOADING_BECAUSE_GAME_IS_CURRENTLY_PLAYED;
|
||||
} else if (cheatDetection.savedVersion > savedVersionToCheck) {
|
||||
savedVersionToCheck = cheatDetection.savedVersion;
|
||||
}
|
||||
|
||||
if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) {
|
||||
L.log("Internal cheatcheck file savedVersion: " + cheatDetection.savedVersion);
|
||||
@@ -167,50 +169,72 @@ public final class Savegames {
|
||||
return (savedVersionToCheck == DENY_LOADING_BECAUSE_GAME_IS_CURRENTLY_PLAYED || fh.savedVersion < savedVersionToCheck);
|
||||
}
|
||||
|
||||
private static FileOutputStream getOutputFile(Context androidContext, int slot) throws IOException {
|
||||
if (slot == SLOT_QUICKSAVE) {
|
||||
return androidContext.openFileOutput(Constants.FILENAME_SAVEGAME_QUICKSAVE, Context.MODE_PRIVATE);
|
||||
} else {
|
||||
ensureSavegameDirectoryExists(androidContext);
|
||||
return new FileOutputStream(getSlotFile(slot, androidContext));
|
||||
}
|
||||
}
|
||||
private static void ensureSavegameDirectoryExists(Context context) {
|
||||
File dir = AndroidStorage.getStorageDirectory(context, Constants.FILENAME_SAVEGAME_DIRECTORY);
|
||||
if (!dir.exists()) dir.mkdir();
|
||||
}
|
||||
private static FileInputStream getInputFile(Context androidContext, int slot) throws IOException {
|
||||
if (slot == SLOT_QUICKSAVE) {
|
||||
return androidContext.openFileInput(Constants.FILENAME_SAVEGAME_QUICKSAVE);
|
||||
} else {
|
||||
return new FileInputStream(getSlotFile(slot, androidContext));
|
||||
}
|
||||
}
|
||||
private static FileOutputStream getOutputFile(Context androidContext, int slot) throws IOException {
|
||||
if (slot == SLOT_QUICKSAVE) {
|
||||
return androidContext.openFileOutput(Constants.FILENAME_SAVEGAME_QUICKSAVE, Context.MODE_PRIVATE);
|
||||
} else {
|
||||
ensureSavegameDirectoryExists(androidContext);
|
||||
return new FileOutputStream(getSlotFile(slot, androidContext));
|
||||
}
|
||||
}
|
||||
|
||||
public static File getSlotFile(int slot, Context context) {
|
||||
File root = AndroidStorage.getStorageDirectory(context, Constants.FILENAME_SAVEGAME_DIRECTORY);
|
||||
return new File(root, Constants.FILENAME_SAVEGAME_FILENAME_PREFIX + slot);
|
||||
}
|
||||
private static void ensureSavegameDirectoryExists(Context context) {
|
||||
File dir = AndroidStorage.getStorageDirectory(context, Constants.FILENAME_SAVEGAME_DIRECTORY);
|
||||
ensureDirExists(dir);
|
||||
}
|
||||
|
||||
public static boolean ensureDirExists(File dir) {
|
||||
if (!dir.exists()) {
|
||||
boolean worked = dir.mkdir();
|
||||
return worked;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private static FileInputStream getInputFile(Context androidContext, int slot) throws IOException {
|
||||
if (slot == SLOT_QUICKSAVE) {
|
||||
return androidContext.openFileInput(Constants.FILENAME_SAVEGAME_QUICKSAVE);
|
||||
} else {
|
||||
return new FileInputStream(getSlotFile(slot, androidContext));
|
||||
}
|
||||
}
|
||||
|
||||
public static File getSlotFile(int slot, Context context) {
|
||||
File root = AndroidStorage.getStorageDirectory(context, Constants.FILENAME_SAVEGAME_DIRECTORY);
|
||||
return getSlotFile(slot, root);
|
||||
}
|
||||
|
||||
public static File getSlotFile(int slot, File directory) {
|
||||
return new File(directory, getSlotFileName(slot));
|
||||
}
|
||||
|
||||
public static String getSlotFileName(int slot) {
|
||||
return Constants.FILENAME_SAVEGAME_FILENAME_PREFIX + slot;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static void saveWorld(WorldContext world, OutputStream outStream, String displayInfo) throws IOException {
|
||||
public static void saveWorld(WorldContext world, OutputStream outStream, String displayInfo) throws IOException, NoSuchAlgorithmException {
|
||||
DataOutputStream dest = new DataOutputStream(outStream);
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
|
||||
world.model.player.hash = world.createHash();
|
||||
}
|
||||
FileHeader.writeToParcel(dest, world.model.player.getName(),
|
||||
displayInfo, world.model.player.iconID,
|
||||
world.model.statistics.isDead(),
|
||||
world.model.statistics.hasUnlimitedSaves(),
|
||||
world.model.player.id,
|
||||
world.model.player.savedVersion);
|
||||
world.model.player.savedVersion,
|
||||
world.model.player.wasEditingDetected);
|
||||
world.maps.writeToParcel(dest, world);
|
||||
world.model.writeToParcel(dest);
|
||||
dest.close();
|
||||
}
|
||||
|
||||
public static LoadSavegameResult loadWorld(Resources res, WorldContext world, ControllerContext controllers, InputStream inState, FileHeader fh) throws IOException {
|
||||
DataInputStream src = new DataInputStream(inState);
|
||||
final FileHeader header = new FileHeader(src, fh.skipIcon);
|
||||
if (header.fileversion > AndorsTrailApplication.CURRENT_VERSION) return LoadSavegameResult.savegameIsFromAFutureVersion;
|
||||
public static LoadSavegameResult loadWorld(Resources res, WorldContext world, ControllerContext controllers, InputStream inState, FileHeader fh) throws IOException {
|
||||
DataInputStream src = new DataInputStream(inState);
|
||||
final FileHeader header = new FileHeader(src, fh.skipIcon);
|
||||
if (header.fileversion > AndorsTrailApplication.CURRENT_VERSION)
|
||||
return LoadSavegameResult.savegameIsFromAFutureVersion;
|
||||
|
||||
world.maps.readFromParcel(src, world, controllers, header.fileversion);
|
||||
world.model = new ModelContainer(src, world, controllers, header.fileversion);
|
||||
@@ -222,6 +246,15 @@ public final class Savegames {
|
||||
|
||||
onWorldLoaded(res, world, controllers);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
|
||||
try {
|
||||
String worldHash = world.createHash();
|
||||
if(!worldHash.equals(world.model.player.hash)){
|
||||
world.model.player.wasEditingDetected = true;
|
||||
return LoadSavegameResult.editDetected;
|
||||
}
|
||||
} catch (NoSuchAlgorithmException ignored) { }
|
||||
}
|
||||
return LoadSavegameResult.success;
|
||||
}
|
||||
|
||||
@@ -249,15 +282,15 @@ public final class Savegames {
|
||||
}
|
||||
}
|
||||
|
||||
private static void writeCheatCheck(Context androidContext, long savedVersion, String playerId) throws IOException {
|
||||
File cheatDetectionFolder = AndroidStorage.getStorageDirectory(androidContext, Constants.CHEAT_DETECTION_FOLDER);
|
||||
if (!cheatDetectionFolder.exists()) cheatDetectionFolder.mkdir();
|
||||
File cheatDetectionFile = new File(cheatDetectionFolder, playerId);
|
||||
FileOutputStream fileOutputStream = new FileOutputStream(cheatDetectionFile);
|
||||
DataOutputStream dataOutputStream = new DataOutputStream(fileOutputStream);
|
||||
CheatDetection.writeToParcel(dataOutputStream, savedVersion);
|
||||
dataOutputStream.close();
|
||||
fileOutputStream.close();
|
||||
private static void writeCheatCheck(Context androidContext, long savedVersion, String playerId) throws IOException {
|
||||
File cheatDetectionFolder = AndroidStorage.getStorageDirectory(androidContext, Constants.CHEAT_DETECTION_FOLDER);
|
||||
ensureDirExists(cheatDetectionFolder);
|
||||
File cheatDetectionFile = new File(cheatDetectionFolder, playerId);
|
||||
FileOutputStream fileOutputStream = new FileOutputStream(cheatDetectionFile);
|
||||
DataOutputStream dataOutputStream = new DataOutputStream(fileOutputStream);
|
||||
CheatDetection.writeToParcel(dataOutputStream, savedVersion);
|
||||
dataOutputStream.close();
|
||||
fileOutputStream.close();
|
||||
|
||||
fileOutputStream = androidContext.openFileOutput(playerId, Context.MODE_PRIVATE);
|
||||
dataOutputStream = new DataOutputStream(fileOutputStream);
|
||||
@@ -268,26 +301,26 @@ public final class Savegames {
|
||||
|
||||
private static final Pattern savegameFilenamePattern = Pattern.compile(Constants.FILENAME_SAVEGAME_FILENAME_PREFIX + "(\\d+)");
|
||||
|
||||
public static List<Integer> getUsedSavegameSlots(Context context) {
|
||||
try {
|
||||
final List<Integer> result = new ArrayList<Integer>();
|
||||
AndroidStorage.getStorageDirectory(context, Constants.FILENAME_SAVEGAME_DIRECTORY).listFiles(new FilenameFilter() {
|
||||
@Override
|
||||
public boolean accept(File f, String filename) {
|
||||
Matcher m = savegameFilenamePattern.matcher(filename);
|
||||
if (m != null && m.matches()) {
|
||||
result.add(Integer.parseInt(m.group(1)));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
Collections.sort(result);
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public static List<Integer> getUsedSavegameSlots(Context context) {
|
||||
try {
|
||||
final List<Integer> result = new ArrayList<Integer>();
|
||||
AndroidStorage.getStorageDirectory(context, Constants.FILENAME_SAVEGAME_DIRECTORY).listFiles(new FilenameFilter() {
|
||||
@Override
|
||||
public boolean accept(File f, String filename) {
|
||||
Matcher m = savegameFilenamePattern.matcher(filename);
|
||||
if (m != null && m.matches()) {
|
||||
result.add(Integer.parseInt(m.group(1)));
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
Collections.sort(result);
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
return new ArrayList<Integer>();
|
||||
}
|
||||
}
|
||||
|
||||
private static final class CheatDetection {
|
||||
public final int fileversion;
|
||||
@@ -307,17 +340,17 @@ public final class Savegames {
|
||||
}
|
||||
|
||||
|
||||
|
||||
public static final class FileHeader {
|
||||
public final int fileversion;
|
||||
public final String playerName;
|
||||
public final String displayInfo;
|
||||
public final int iconID;
|
||||
public boolean skipIcon = false;
|
||||
public final boolean isDead;
|
||||
public final boolean hasUnlimitedSaves;
|
||||
public final String playerId;
|
||||
public final long savedVersion;
|
||||
public static final class FileHeader {
|
||||
public final int fileversion;
|
||||
public final String playerName;
|
||||
public final String displayInfo;
|
||||
public final int iconID;
|
||||
public boolean skipIcon = false;
|
||||
public final boolean isDead;
|
||||
public final boolean hasUnlimitedSaves;
|
||||
public final String playerId;
|
||||
public final long savedVersion;
|
||||
public final boolean wasEditingDetected;
|
||||
|
||||
public String describe() {
|
||||
return (fileversion == AndorsTrailApplication.DEVELOPMENT_INCOMPATIBLE_SAVEGAME_VERSION ? "(D) " : "") + playerName + ", " + displayInfo;
|
||||
@@ -326,17 +359,18 @@ public final class Savegames {
|
||||
|
||||
// ====== PARCELABLE ===================================================================
|
||||
|
||||
public FileHeader(DataInputStream src, boolean skipIcon) throws IOException {
|
||||
int fileversion = src.readInt();
|
||||
if (fileversion == 11) fileversion = 5; // Fileversion 5 had no version identifier, but the first byte was 11.
|
||||
this.fileversion = fileversion;
|
||||
if (fileversion >= 14) { // Before fileversion 14 (0.6.7), we had no file header.
|
||||
this.playerName = src.readUTF();
|
||||
this.displayInfo = src.readUTF();
|
||||
} else {
|
||||
this.playerName = null;
|
||||
this.displayInfo = null;
|
||||
}
|
||||
public FileHeader(DataInputStream src, boolean skipIcon) throws IOException {
|
||||
int fileversion = src.readInt();
|
||||
if (fileversion == 11)
|
||||
fileversion = 5; // Fileversion 5 had no version identifier, but the first byte was 11.
|
||||
this.fileversion = fileversion;
|
||||
if (fileversion >= 14) { // Before fileversion 14 (0.6.7), we had no file header.
|
||||
this.playerName = src.readUTF();
|
||||
this.displayInfo = src.readUTF();
|
||||
} else {
|
||||
this.playerName = null;
|
||||
this.displayInfo = null;
|
||||
}
|
||||
|
||||
if (fileversion >= 43) {
|
||||
int id = src.readInt();
|
||||
@@ -361,9 +395,14 @@ public final class Savegames {
|
||||
this.playerId = "";
|
||||
this.savedVersion = 0;
|
||||
}
|
||||
if (fileversion >= 70){
|
||||
this.wasEditingDetected = src.readBoolean();
|
||||
}else{
|
||||
this.wasEditingDetected = false;
|
||||
}
|
||||
}
|
||||
|
||||
public static void writeToParcel(DataOutputStream dest, String playerName, String displayInfo, int iconID, boolean isDead, boolean hasUnlimitedSaves, String playerId, long savedVersion) throws IOException {
|
||||
public static void writeToParcel(DataOutputStream dest, String playerName, String displayInfo, int iconID, boolean isDead, boolean hasUnlimitedSaves, String playerId, long savedVersion, boolean wasEditingDetected) throws IOException {
|
||||
dest.writeInt(AndorsTrailApplication.CURRENT_VERSION);
|
||||
dest.writeUTF(playerName);
|
||||
dest.writeUTF(displayInfo);
|
||||
@@ -372,6 +411,7 @@ public final class Savegames {
|
||||
dest.writeBoolean(hasUnlimitedSaves);
|
||||
dest.writeUTF(playerId);
|
||||
dest.writeLong(savedVersion);
|
||||
dest.writeBoolean(wasEditingDetected);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,42 +1,58 @@
|
||||
package com.gpl.rpg.AndorsTrail.util;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
import android.support.annotation.RequiresApi;
|
||||
import android.support.v4.content.FileProvider;
|
||||
import android.support.v4.provider.DocumentFile;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
|
||||
import com.gpl.rpg.AndorsTrail.R;
|
||||
import com.gpl.rpg.AndorsTrail.controller.Constants;
|
||||
import com.gpl.rpg.AndorsTrail.util.BackgroundWorker.BackgroundWorkerCallback;
|
||||
import com.gpl.rpg.AndorsTrail.view.CustomDialogFactory;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.util.concurrent.CancellationException;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipInputStream;
|
||||
import java.util.zip.ZipOutputStream;
|
||||
|
||||
public final class AndroidStorage {
|
||||
public static File getStorageDirectory(Context context, String name) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
return context.getExternalFilesDir(name);
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
File root = Environment.getExternalStorageDirectory();
|
||||
return new File(root, name);
|
||||
}
|
||||
}
|
||||
|
||||
public static boolean shouldMigrateToInternalStorage(Context context) {
|
||||
boolean ret = false;
|
||||
File externalSaveGameDirectory = new File(Environment.getExternalStorageDirectory(), Constants.FILENAME_SAVEGAME_DIRECTORY);
|
||||
File externalSaveGameDirectory = new File(Environment.getExternalStorageDirectory(),
|
||||
Constants.FILENAME_SAVEGAME_DIRECTORY);
|
||||
File internalSaveGameDirectory = getStorageDirectory(context, Constants.FILENAME_SAVEGAME_DIRECTORY);
|
||||
|
||||
if (externalSaveGameDirectory.exists()
|
||||
&& externalSaveGameDirectory.isDirectory()
|
||||
&& externalSaveGameDirectory.listFiles().length > 0
|
||||
&& (
|
||||
!internalSaveGameDirectory.exists()
|
||||
|| internalSaveGameDirectory.isDirectory() && internalSaveGameDirectory.listFiles().length < 2)
|
||||
) {
|
||||
&& externalSaveGameDirectory.isDirectory()
|
||||
&& externalSaveGameDirectory.listFiles().length > 0
|
||||
&& (!internalSaveGameDirectory.exists()
|
||||
|| internalSaveGameDirectory.isDirectory()
|
||||
&& internalSaveGameDirectory.listFiles().length < 2)) {
|
||||
ret = true;
|
||||
}
|
||||
return ret;
|
||||
@@ -45,11 +61,11 @@ public final class AndroidStorage {
|
||||
public static boolean migrateToInternalStorage(Context context) {
|
||||
try {
|
||||
copy(new File(Environment.getExternalStorageDirectory(), Constants.CHEAT_DETECTION_FOLDER),
|
||||
getStorageDirectory(context, Constants.CHEAT_DETECTION_FOLDER));
|
||||
getStorageDirectory(context, Constants.CHEAT_DETECTION_FOLDER));
|
||||
copy(new File(Environment.getExternalStorageDirectory(), Constants.FILENAME_SAVEGAME_DIRECTORY),
|
||||
getStorageDirectory(context, Constants.FILENAME_SAVEGAME_DIRECTORY));
|
||||
getStorageDirectory(context, Constants.FILENAME_SAVEGAME_DIRECTORY));
|
||||
} catch (IOException e) {
|
||||
L.log("Error migrating data: " + e.toString());
|
||||
L.log("Error migrating data: " + e);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
@@ -76,33 +92,381 @@ public final class AndroidStorage {
|
||||
}
|
||||
}
|
||||
|
||||
private static void copyFile(File source, File target) throws IOException {
|
||||
InputStream in = null;
|
||||
OutputStream out = null;
|
||||
try {
|
||||
in = new FileInputStream(source);
|
||||
out = new FileOutputStream(target);
|
||||
byte[] buf = new byte[1024];
|
||||
int length;
|
||||
while ((length = in.read(buf)) > 0) {
|
||||
out.write(buf, 0, length);
|
||||
public static void copyFile(File source, File target) throws IOException {
|
||||
try (InputStream in = new FileInputStream(source); OutputStream out = new FileOutputStream(target)) {
|
||||
copyStream(in, out);
|
||||
}
|
||||
}
|
||||
|
||||
public static void copyStream(InputStream in, OutputStream out) throws IOException {
|
||||
byte[] buf = new byte[1024];
|
||||
int length;
|
||||
while ((length = in.read(buf)) > 0) {
|
||||
out.write(buf, 0, length);
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.P)
|
||||
public static void createZipDocumentFileFromFilesAsync(File[] files,
|
||||
Context context,
|
||||
DocumentFile targetDirectory,
|
||||
String fileName,
|
||||
String loadingMessage,
|
||||
Consumer<Boolean> callback) {
|
||||
|
||||
BackgroundWorker<Boolean> worker = new BackgroundWorker<>();
|
||||
CustomDialogFactory.CustomDialog progressDialog = getLoadingDialog(context, loadingMessage);
|
||||
progressDialog.setOnCancelListener(dialog -> worker.cancel());
|
||||
ContentResolver resolver = context.getContentResolver();
|
||||
Handler handler = Handler.createAsync(Looper.getMainLooper());
|
||||
|
||||
|
||||
worker.setTask(workerCallback -> {
|
||||
try {
|
||||
workerCallback.onInitialize();
|
||||
|
||||
//region create zip file
|
||||
File zip = File.createTempFile("temp_worldmap", ".zip");
|
||||
try (OutputStream out = new FileOutputStream(zip)) {
|
||||
ZipOutputStream zipOut = new ZipOutputStream(out);
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
File file = files[i];
|
||||
try (FileInputStream fis = new FileInputStream(file)) {
|
||||
workerCallback.onProgress((float) i / files.length);
|
||||
zipOut.putNextEntry(new ZipEntry(file.getName()));
|
||||
copyStream(fis, zipOut);
|
||||
zipOut.closeEntry();
|
||||
}
|
||||
}
|
||||
zipOut.close();
|
||||
}
|
||||
//endregion
|
||||
|
||||
DocumentFile worldmapZip = DocumentFile.fromFile(zip);
|
||||
DocumentFile worldmapTarget = targetDirectory.createFile("application/zip", fileName);
|
||||
if (worldmapTarget != null && worldmapTarget.exists()) {
|
||||
AndroidStorage.copyDocumentFile(worldmapZip, resolver, worldmapTarget);
|
||||
workerCallback.onComplete(true);
|
||||
} else {
|
||||
throw new FileNotFoundException("Could not create File");
|
||||
}
|
||||
} catch (NullPointerException e) {
|
||||
if (worker.isCancelled()) {
|
||||
workerCallback.onFailure(new CancellationException("Cancelled"));
|
||||
} else {
|
||||
workerCallback.onFailure(e);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
workerCallback.onFailure(e);
|
||||
}
|
||||
} finally {
|
||||
if (in != null) {
|
||||
in.close();
|
||||
});
|
||||
|
||||
worker.setCallback(getDefaultBackgroundWorkerCallback(handler, progressDialog, callback));
|
||||
worker.run();
|
||||
|
||||
|
||||
}
|
||||
|
||||
public static void unzipToDirectory(File zipFile,
|
||||
File targetDirectory,
|
||||
boolean overwriteNotSkip) throws IOException {
|
||||
|
||||
try (ZipInputStream zis = new ZipInputStream(new FileInputStream(zipFile))) {
|
||||
unzipStreamToDirectory(targetDirectory, overwriteNotSkip, zis);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.P)
|
||||
public static void unzipDocumentFileToDirectoryAsync(DocumentFile zipFile,
|
||||
Context context,
|
||||
File targetDirectory,
|
||||
boolean overwriteNotSkip,
|
||||
String loadingMessage,
|
||||
Consumer<Boolean> callback) {
|
||||
|
||||
BackgroundWorker<Boolean> worker = new BackgroundWorker<>();
|
||||
CustomDialogFactory.CustomDialog progressDialog = getLoadingDialog(context, loadingMessage);
|
||||
progressDialog.setOnCancelListener(dialog -> worker.cancel());
|
||||
ContentResolver resolver = context.getContentResolver();
|
||||
Handler handler = Handler.createAsync(Looper.getMainLooper());
|
||||
|
||||
worker.setTask(workerCallback -> {
|
||||
try {
|
||||
workerCallback.onInitialize();
|
||||
workerCallback.onProgress(-1);//set dummy progress since we don't know the
|
||||
// progress of the unzip
|
||||
unzipDocumentFileToDirectory(zipFile, resolver, targetDirectory, overwriteNotSkip);
|
||||
workerCallback.onComplete(true);
|
||||
} catch (IOException e) {
|
||||
workerCallback.onFailure(e);
|
||||
}
|
||||
if (out != null) {
|
||||
out.close();
|
||||
});
|
||||
|
||||
worker.setCallback(getDefaultBackgroundWorkerCallback(handler, progressDialog, callback));
|
||||
worker.run();
|
||||
|
||||
}
|
||||
|
||||
public static void unzipDocumentFileToDirectory(DocumentFile zipFile,
|
||||
ContentResolver resolver,
|
||||
File targetDirectory,
|
||||
boolean overwriteNotSkip) throws IOException {
|
||||
try (ZipInputStream zis = new ZipInputStream(resolver.openInputStream(zipFile.getUri()))) {
|
||||
unzipStreamToDirectory(targetDirectory, overwriteNotSkip, zis);
|
||||
}
|
||||
}
|
||||
|
||||
private static void unzipStreamToDirectory(File targetDirectory,
|
||||
boolean overwriteNotSkip,
|
||||
ZipInputStream zis) throws IOException {
|
||||
ZipEntry entry;
|
||||
while ((entry = zis.getNextEntry()) != null) {
|
||||
File file = new File(targetDirectory, entry.getName());
|
||||
|
||||
if (entry.isDirectory()) {
|
||||
file.mkdirs();
|
||||
} else {
|
||||
file.getParentFile().mkdirs();
|
||||
if (file.exists() && !overwriteNotSkip) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try (FileOutputStream fos = new FileOutputStream(file)) {
|
||||
copyStream(zis, fos);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static void copyDocumentFileToNewOrExistingFile(DocumentFile sourceFile,
|
||||
ContentResolver resolver,
|
||||
DocumentFile targetFolder) throws IOException {
|
||||
copyDocumentFileToNewOrExistingFile(sourceFile,
|
||||
resolver,
|
||||
targetFolder,
|
||||
Constants.NO_FILE_EXTENSION_MIME_TYPE);
|
||||
}
|
||||
|
||||
|
||||
public static void copyDocumentFileToNewOrExistingFile(DocumentFile sourceFile,
|
||||
ContentResolver resolver,
|
||||
DocumentFile targetFolder,
|
||||
String mimeType) throws IOException {
|
||||
String fileName = sourceFile.getName();
|
||||
DocumentFile file = targetFolder.findFile(fileName);
|
||||
if (file == null) {
|
||||
file = targetFolder.createFile(mimeType, fileName);
|
||||
}
|
||||
if (file == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
AndroidStorage.copyDocumentFile(sourceFile, resolver, file);
|
||||
}
|
||||
|
||||
public static void copyDocumentFile(DocumentFile sourceFile,
|
||||
ContentResolver resolver,
|
||||
DocumentFile targetFile) throws IOException {
|
||||
try (OutputStream outputStream = resolver.openOutputStream(targetFile.getUri());
|
||||
InputStream inputStream = resolver.openInputStream(sourceFile.getUri())) {
|
||||
copyStream(inputStream, outputStream);
|
||||
}
|
||||
}
|
||||
|
||||
public static String getUrlForFile(Context context, File worldmap) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO && Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
Uri uri = FileProvider.getUriForFile(context, "com.gpl.rpg.AndorsTrail.fileprovider", worldmap);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
String applicationId = context.getPackageName();
|
||||
Uri uri = FileProvider.getUriForFile(context, applicationId + ".fileprovider", worldmap);
|
||||
return uri.toString();
|
||||
} else {
|
||||
return "file://" + worldmap.getAbsolutePath();
|
||||
}
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||
public static Intent getNewOpenDirectoryIntent() {
|
||||
return new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||
public static Intent getNewSelectMultipleSavegameFilesIntent() {
|
||||
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
intent.putExtra(Intent.EXTRA_ALLOW_MULTIPLE, true);
|
||||
intent.setType(Constants.SAVEGAME_FILE_MIME_TYPE);
|
||||
return intent;
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||
public static Intent getNewSelectZipIntent() {
|
||||
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
|
||||
intent.addCategory(Intent.CATEGORY_OPENABLE);
|
||||
intent.setType("application/zip");
|
||||
return intent;
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.P)
|
||||
public static void copyDocumentFilesFromToAsync(DocumentFile[] sources,
|
||||
Context context,
|
||||
DocumentFile[] targets,
|
||||
String loadingMessage,
|
||||
Consumer<Boolean> callback) {
|
||||
if (sources.length != targets.length) {
|
||||
throw new IllegalArgumentException("Both arrays, target & source have to have the same size");
|
||||
}
|
||||
|
||||
BackgroundWorker<Boolean> worker = new BackgroundWorker<>();
|
||||
|
||||
CustomDialogFactory.CustomDialog progressDialog = getLoadingDialog(context, loadingMessage);
|
||||
progressDialog.setOnCancelListener(dialog -> worker.cancel());
|
||||
|
||||
ContentResolver resolver = context.getContentResolver();
|
||||
Handler handler = Handler.createAsync(Looper.getMainLooper());
|
||||
|
||||
worker.setTask(workerCallback -> {
|
||||
try {
|
||||
workerCallback.onInitialize();
|
||||
for (int i = 0; i < sources.length; i++) {
|
||||
if (worker.isCancelled()) {
|
||||
workerCallback.onFailure(new CancellationException("Cancelled"));
|
||||
return;
|
||||
}
|
||||
DocumentFile source = sources[i];
|
||||
DocumentFile target = targets[i];
|
||||
|
||||
if (source == null || target == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
copyDocumentFile(source, resolver, target);
|
||||
float progress = i / (float) sources.length;
|
||||
workerCallback.onProgress(progress);
|
||||
}
|
||||
workerCallback.onComplete(true);
|
||||
} catch (NullPointerException e) {
|
||||
if (worker.isCancelled()) {
|
||||
workerCallback.onFailure(new CancellationException("Cancelled"));
|
||||
return;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
workerCallback.onFailure(e);
|
||||
}
|
||||
});
|
||||
worker.setCallback(getDefaultBackgroundWorkerCallback(handler, progressDialog, callback));
|
||||
worker.run();
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.P)
|
||||
public static void copyDocumentFilesToDirAsync(DocumentFile[] files,
|
||||
Context context,
|
||||
DocumentFile targetDirectory,
|
||||
String loadingMessage,
|
||||
Consumer<Boolean> callback) {
|
||||
BackgroundWorker<Boolean> worker = new BackgroundWorker<>();
|
||||
CustomDialogFactory.CustomDialog progressDialog = getLoadingDialog(context, loadingMessage);
|
||||
progressDialog.setOnCancelListener(dialog -> worker.cancel());
|
||||
ContentResolver resolver = context.getContentResolver();
|
||||
Handler handler = Handler.createAsync(Looper.getMainLooper());
|
||||
|
||||
worker.setTask(workerCallback -> {
|
||||
try {
|
||||
workerCallback.onInitialize();
|
||||
for (int i = 0; i < files.length; i++) {
|
||||
if (worker.isCancelled()) {
|
||||
workerCallback.onFailure(new CancellationException("Cancelled"));
|
||||
return;
|
||||
}
|
||||
DocumentFile file = files[i];
|
||||
if (file == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
copyDocumentFileToNewOrExistingFile(file, resolver, targetDirectory);
|
||||
float progress = i / (float) files.length;
|
||||
workerCallback.onProgress(progress);
|
||||
}
|
||||
workerCallback.onComplete(true);
|
||||
} catch (NullPointerException e) {
|
||||
if (worker.isCancelled()) {
|
||||
workerCallback.onFailure(new CancellationException("Cancelled"));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
workerCallback.onFailure(e);
|
||||
}
|
||||
});
|
||||
worker.setCallback(getDefaultBackgroundWorkerCallback(handler, progressDialog, callback));
|
||||
worker.run();
|
||||
}
|
||||
|
||||
private static BackgroundWorkerCallback<Boolean> getDefaultBackgroundWorkerCallback(Handler handler,
|
||||
CustomDialogFactory.CustomDialog progressDialog,
|
||||
Consumer<Boolean> callback) {
|
||||
return new BackgroundWorkerCallback<Boolean>() {
|
||||
private int progress = -1;
|
||||
|
||||
@Override
|
||||
public void onInitialize() {
|
||||
handler.post(() -> {
|
||||
CustomDialogFactory.show(progressDialog);
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProgress(float progress) {
|
||||
handler.post(() -> {
|
||||
int intProgress = (int) (progress * 100);
|
||||
if (this.progress == intProgress) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.progress = intProgress;
|
||||
|
||||
if (progress == -1) {
|
||||
CustomDialogFactory.setDesc(progressDialog, null);
|
||||
return;
|
||||
}
|
||||
|
||||
CustomDialogFactory.setDesc(progressDialog, intProgress + "%");
|
||||
});
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.N)
|
||||
@Override
|
||||
public void onFailure(Exception e) {
|
||||
this.onComplete(false);
|
||||
}
|
||||
|
||||
@RequiresApi(api = Build.VERSION_CODES.N)
|
||||
@Override
|
||||
public void onComplete(Boolean result) {
|
||||
handler.post(() -> {
|
||||
progressDialog.dismiss();
|
||||
callback.accept(result);
|
||||
});
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private static CustomDialogFactory.CustomDialog getLoadingDialog(Context context) {
|
||||
return getLoadingDialog(context, null);
|
||||
}
|
||||
|
||||
private static CustomDialogFactory.CustomDialog getLoadingDialog(Context context, String message) {
|
||||
if (message == null) {
|
||||
message = context.getResources().getString(R.string.dialog_loading_message);
|
||||
}
|
||||
|
||||
CustomDialogFactory.CustomDialog dialog = CustomDialogFactory.createDialog(context,
|
||||
message,
|
||||
context.getResources()
|
||||
.getDrawable(R.drawable.loading_anim),
|
||||
null,
|
||||
null,
|
||||
true,
|
||||
false);
|
||||
CustomDialogFactory.addCancelButton(dialog, android.R.string.no);
|
||||
return dialog;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
package com.gpl.rpg.AndorsTrail.util;
|
||||
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public final class BackgroundWorker<T> {
|
||||
boolean cancelled = false;
|
||||
worker<T> task;
|
||||
BackgroundWorkerCallback<T> callback;
|
||||
|
||||
public void setTask(worker<T> task) {
|
||||
this.task = task;
|
||||
}
|
||||
|
||||
public void setCallback(BackgroundWorkerCallback<T> callback) {
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
public void cancel() {
|
||||
cancelled = true;
|
||||
}
|
||||
|
||||
interface worker<T> {
|
||||
void doWork(BackgroundWorkerCallback<T> callback);
|
||||
}
|
||||
|
||||
interface BackgroundWorkerCallback<T> {
|
||||
void onInitialize();
|
||||
|
||||
default void onProgress(float progress) {
|
||||
}
|
||||
|
||||
void onFailure(Exception e);
|
||||
|
||||
void onComplete(T result);
|
||||
}
|
||||
|
||||
public void run() {
|
||||
Executors.newSingleThreadExecutor().execute(() -> {
|
||||
task.doWork(callback);
|
||||
});
|
||||
}
|
||||
|
||||
public boolean isCancelled() {
|
||||
return cancelled;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,17 @@
|
||||
package com.gpl.rpg.AndorsTrail.util;
|
||||
|
||||
import android.os.Build;
|
||||
import android.support.annotation.RequiresApi;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
public final class ByteUtils {
|
||||
|
||||
private static int bytes;
|
||||
|
||||
public static String toHexString(byte[] bytes) { return toHexString(bytes, bytes.length); }
|
||||
public static String toHexString(byte[] bytes, int numBytes) {
|
||||
if (bytes == null) return "";
|
||||
@@ -21,4 +32,57 @@ public final class ByteUtils {
|
||||
array[i] ^= mask[i];
|
||||
}
|
||||
}
|
||||
|
||||
public static byte[] toBytes(long l){
|
||||
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
|
||||
bytes = Long.BYTES;
|
||||
}else{
|
||||
bytes = 8;
|
||||
}
|
||||
ByteBuffer buffer = ByteBuffer.allocate(bytes);
|
||||
buffer.putLong(l);
|
||||
return buffer.array();
|
||||
}
|
||||
|
||||
public static byte[] toBytes(int i){
|
||||
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
|
||||
bytes = Integer.BYTES;
|
||||
}else{
|
||||
bytes = 4;
|
||||
}
|
||||
ByteBuffer buffer = ByteBuffer.allocate(bytes);
|
||||
buffer.putInt(i);
|
||||
return buffer.array();
|
||||
}
|
||||
|
||||
public static byte[] toBytes(float f) {
|
||||
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.N) {
|
||||
bytes = Float.BYTES;
|
||||
}else{
|
||||
bytes = 4;
|
||||
}
|
||||
ByteBuffer buffer = ByteBuffer.allocate(bytes);
|
||||
buffer.putFloat(f);
|
||||
return buffer.array();
|
||||
}
|
||||
public static byte[] toBytes(boolean bool){
|
||||
byte b;
|
||||
if(bool){
|
||||
b = 0;
|
||||
}else{
|
||||
b = 1;
|
||||
}
|
||||
return new byte[] {b};
|
||||
}
|
||||
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
|
||||
public static byte[] toBytes(String x) {
|
||||
if (x == null) {
|
||||
return new byte[]{};
|
||||
}
|
||||
return x.getBytes(StandardCharsets.UTF_8);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@ package com.gpl.rpg.AndorsTrail.util;
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.MessageDigest;
|
||||
|
||||
public final class Coord {
|
||||
public int x;
|
||||
@@ -47,4 +48,9 @@ public final class Coord {
|
||||
dest.writeInt(x);
|
||||
dest.writeInt(y);
|
||||
}
|
||||
|
||||
public void createHash(MessageDigest digest) {
|
||||
digest.update(ByteUtils.toBytes(x));
|
||||
digest.update(ByteUtils.toBytes(y));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package com.gpl.rpg.AndorsTrail.util;
|
||||
|
||||
import com.gpl.rpg.AndorsTrail.context.WorldContext;
|
||||
|
||||
import java.io.DataInputStream;
|
||||
import java.io.DataOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.security.MessageDigest;
|
||||
|
||||
public final class Range {
|
||||
public int max;
|
||||
@@ -99,4 +102,9 @@ public final class Range {
|
||||
dest.writeInt(max);
|
||||
dest.writeInt(current);
|
||||
}
|
||||
|
||||
public void createHash(MessageDigest digest) {
|
||||
digest.update(ByteUtils.toBytes(max));
|
||||
digest.update(ByteUtils.toBytes(current));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
package com.gpl.rpg.AndorsTrail.view;
|
||||
|
||||
import android.app.Dialog;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface.OnDismissListener;
|
||||
import android.content.DialogInterface.OnCancelListener;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.AnimationDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
@@ -22,25 +22,33 @@ import com.gpl.rpg.AndorsTrail.R;
|
||||
import com.gpl.rpg.AndorsTrail.util.ThemeHelper;
|
||||
|
||||
public class CustomDialogFactory {
|
||||
|
||||
public static class CustomDialog extends Dialog {
|
||||
|
||||
public static class CustomDialog extends android.app.Dialog {
|
||||
public CustomDialog(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
boolean verticalButtons = false;
|
||||
}
|
||||
|
||||
public static CustomDialog createDialog(final Context context, String title, Drawable icon, String desc, View content, boolean hasButtons) {
|
||||
|
||||
public static CustomDialog createDialog(final Context context, String title, Drawable icon,
|
||||
String desc, View content, boolean hasButtons, boolean canDismiss) {
|
||||
return createDialog(context, title, icon, desc, content, hasButtons, canDismiss, false);
|
||||
}
|
||||
|
||||
public static CustomDialog createDialog(final Context context, String title, Drawable icon,
|
||||
String desc, View content, boolean hasButtons) {
|
||||
return createDialog(context, title, icon, desc, content, hasButtons, true);
|
||||
}
|
||||
|
||||
public static CustomDialog createDialog(final Context context, String title, Drawable icon, String desc, View content, boolean hasButtons, final boolean canDismiss) {
|
||||
|
||||
public static CustomDialog createDialog(final Context context, String title, Drawable icon,
|
||||
String desc, View content, boolean hasButtons,
|
||||
final boolean canDismiss, final boolean verticalButtons) {
|
||||
final CustomDialog dialog = new CustomDialog(new ContextThemeWrapper(context, ThemeHelper.getDialogTheme())) {
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent event) {
|
||||
Rect r = new Rect();
|
||||
this.getWindow().getDecorView().findViewById(R.id.dialog_hitrect).getHitRect(r);
|
||||
|
||||
|
||||
if (r.contains((int)event.getX(), (int)event.getY())) {
|
||||
return super.onTouchEvent(event);
|
||||
} else {
|
||||
@@ -51,7 +59,7 @@ public class CustomDialogFactory {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onWindowFocusChanged(boolean hasFocus) {
|
||||
super.onWindowFocusChanged(hasFocus);
|
||||
@@ -63,7 +71,8 @@ public class CustomDialogFactory {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
dialog.verticalButtons = verticalButtons;
|
||||
|
||||
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
|
||||
dialog.setContentView(R.layout.custom_dialog_title_icon);
|
||||
dialog.getWindow().setBackgroundDrawableResource(android.R.color.transparent);
|
||||
@@ -72,23 +81,37 @@ public class CustomDialogFactory {
|
||||
} else {
|
||||
dialog.getWindow().setFlags(0, WindowManager.LayoutParams.FLAG_FULLSCREEN);
|
||||
}
|
||||
|
||||
|
||||
setTitle(dialog, title, icon);
|
||||
|
||||
|
||||
setDesc(dialog, desc);
|
||||
|
||||
|
||||
setContent(dialog, content);
|
||||
|
||||
ViewGroup buttonsHolder = (ViewGroup) dialog.findViewById(R.id.dialog_button_container);
|
||||
|
||||
ViewGroup buttonsHolder = getButtonContainer(dialog);
|
||||
ViewGroup unusedButtonsHolder = getUnusedButtonContainer(dialog);
|
||||
|
||||
unusedButtonsHolder.setVisibility(View.GONE);
|
||||
if (hasButtons) {
|
||||
buttonsHolder.setVisibility(View.VISIBLE);
|
||||
} else {
|
||||
buttonsHolder.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
|
||||
public static CustomDialog createErrorDialog(final Context context, String title, String description) {
|
||||
final CustomDialog d = createDialog(context,
|
||||
title,
|
||||
context.getResources().getDrawable(android.R.drawable.ic_dialog_alert),
|
||||
description,
|
||||
null,
|
||||
true);
|
||||
CustomDialogFactory.addDismissButton(d, android.R.string.ok);
|
||||
return d;
|
||||
}
|
||||
|
||||
public static CustomDialog setTitle(final CustomDialog dialog, String title, Drawable icon) {
|
||||
TextView titleView = (TextView) dialog.findViewById(R.id.dialog_title);
|
||||
if (title != null || icon != null) {
|
||||
@@ -100,7 +123,7 @@ public class CustomDialogFactory {
|
||||
}
|
||||
return dialog;
|
||||
}
|
||||
|
||||
|
||||
public static CustomDialog setDesc(final CustomDialog dialog, String desc) {
|
||||
TextView descView = (TextView) dialog.findViewById(R.id.dialog_description);
|
||||
ViewGroup descHolder = (ViewGroup) dialog.findViewById(R.id.dialog_description_container);
|
||||
@@ -113,7 +136,7 @@ public class CustomDialogFactory {
|
||||
}
|
||||
return dialog;
|
||||
}
|
||||
|
||||
|
||||
public static CustomDialog setContent(final CustomDialog dialog, View content) {
|
||||
ViewGroup contentHolder = (ViewGroup) dialog.findViewById(R.id.dialog_content_container);
|
||||
if (content != null) {
|
||||
@@ -124,54 +147,101 @@ public class CustomDialogFactory {
|
||||
}
|
||||
return dialog;
|
||||
}
|
||||
|
||||
public static Dialog addButton(final Dialog dialog, int textId, final OnClickListener listener) {
|
||||
|
||||
Button template = (Button) dialog.findViewById(R.id.dialog_template_button);
|
||||
|
||||
public static CustomDialog addButton(final CustomDialog dialog, String text, final OnClickListener listener) {
|
||||
return addButton(dialog, -1, text, listener);
|
||||
}
|
||||
public static CustomDialog addButton(final CustomDialog dialog, int textId, final OnClickListener listener) {
|
||||
return addButton(dialog, textId, null, listener);
|
||||
}
|
||||
public static CustomDialog addButton(final CustomDialog dialog, int textId, String text, final OnClickListener listener) {
|
||||
Button template = getButtonTemplate(dialog);
|
||||
LayoutParams params = template.getLayoutParams();
|
||||
ViewGroup buttonsHolder = (ViewGroup) dialog.findViewById(R.id.dialog_button_container);
|
||||
|
||||
ViewGroup buttonsHolder = getButtonContainer(dialog);
|
||||
|
||||
Button b = new Button(dialog.getContext());
|
||||
b.setLayoutParams(params);
|
||||
//Old android versions need this "reminder"
|
||||
b.setBackgroundDrawable(ThemeHelper.getThemeDrawable(dialog.getContext(), R.attr.ui_theme_textbutton_drawable));
|
||||
b.setTextColor(ThemeHelper.getThemeColor(dialog.getContext(), R.attr.ui_theme_dialogue_light_color));
|
||||
|
||||
b.setText(textId);
|
||||
|
||||
if(textId != -1) {
|
||||
b.setText(textId);
|
||||
} else {
|
||||
b.setText(text);
|
||||
}
|
||||
|
||||
b.setOnClickListener(new OnClickListener() {
|
||||
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
listener.onClick(v);
|
||||
dialog.dismiss();
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
buttonsHolder.addView(b, params);
|
||||
return dialog;
|
||||
}
|
||||
|
||||
public static Dialog addDismissButton(final Dialog dialog, int textId) {
|
||||
|
||||
public static CustomDialog addDismissButton(final CustomDialog dialog, int textId) {
|
||||
return CustomDialogFactory.addButton(dialog, textId, new OnClickListener() {
|
||||
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
dialog.dismiss();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static Dialog setDismissListener(Dialog dialog, OnDismissListener listener) {
|
||||
public static CustomDialog addCancelButton(final CustomDialog dialog, int textId) {
|
||||
return CustomDialogFactory.addButton(dialog, textId, new OnClickListener() {
|
||||
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
dialog.cancel();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public static CustomDialog setDismissListener(CustomDialog dialog, OnDismissListener listener) {
|
||||
dialog.setOnDismissListener(listener);
|
||||
|
||||
|
||||
return dialog;
|
||||
}
|
||||
|
||||
public static void show(Dialog dialog) {
|
||||
|
||||
|
||||
public static CustomDialog setCancelListener(CustomDialog dialog, OnCancelListener listener) {
|
||||
dialog.setOnCancelListener(listener);
|
||||
return dialog;
|
||||
}
|
||||
|
||||
public static void show(CustomDialog dialog) {
|
||||
|
||||
dialog.findViewById(R.id.dialog_template_button).setVisibility(View.GONE);
|
||||
dialog.findViewById(R.id.dialog_template_button_vertical).setVisibility(View.GONE);
|
||||
dialog.show();
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
private static ViewGroup getUnusedButtonContainer(CustomDialog dialog) {
|
||||
if (dialog.verticalButtons)
|
||||
return (ViewGroup) dialog.findViewById(R.id.dialog_button_container);
|
||||
else
|
||||
return (ViewGroup) dialog.findViewById(R.id.dialog_button_container_vertical);
|
||||
}
|
||||
|
||||
private static ViewGroup getButtonContainer(CustomDialog dialog) {
|
||||
if (dialog.verticalButtons)
|
||||
return (ViewGroup) dialog.findViewById(R.id.dialog_button_container_vertical);
|
||||
else
|
||||
return (ViewGroup) dialog.findViewById(R.id.dialog_button_container);
|
||||
}
|
||||
|
||||
private static Button getButtonTemplate(CustomDialog dialog) {
|
||||
if (dialog.verticalButtons)
|
||||
return (Button) dialog.findViewById(R.id.dialog_template_button_vertical);
|
||||
else
|
||||
return (Button) dialog.findViewById(R.id.dialog_template_button);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -9,13 +9,15 @@ import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.ListView;
|
||||
|
||||
import com.gpl.rpg.AndorsTrail.view.CustomDialogFactory.CustomDialog;
|
||||
|
||||
/**
|
||||
* Simply instantiate this class, implement abstract methods in an anonymous type, and tada, your Button is a Spinner!
|
||||
*/
|
||||
public abstract class SpinnerEmulator {
|
||||
|
||||
private Button spinnerButton;
|
||||
private Dialog spinnerDialog = null;
|
||||
private CustomDialog spinnerDialog = null;
|
||||
private ListView choicesList;
|
||||
private Context context;
|
||||
|
||||
|
||||
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
68714
AndorsTrail/assets/translation/da.po
Normal file
68714
AndorsTrail/assets/translation/da.po
Normal file
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
68714
AndorsTrail/assets/translation/lzh.po
Normal file
68714
AndorsTrail/assets/translation/lzh.po
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
Binary file not shown.
File diff suppressed because it is too large
Load Diff
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user