mirror of
https://github.com/OMGeeky/andors-trail.git
synced 2026-02-23 15:38:29 +01:00
Compare commits
5 Commits
add-tick-d
...
import-exp
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
62aa912517 | ||
|
|
8e60423735 | ||
|
|
f9a752ab8a | ||
|
|
79a1416616 | ||
|
|
8275f0110a |
3
AndorsTrail/.gitignore
vendored
3
AndorsTrail/.gitignore
vendored
@@ -40,6 +40,9 @@ gradle-app.setting
|
|||||||
# Cache of project
|
# Cache of project
|
||||||
.gradletasknamecache
|
.gradletasknamecache
|
||||||
|
|
||||||
|
|
||||||
|
local.properties
|
||||||
|
|
||||||
# Eclipse Gradle plugin generated files
|
# Eclipse Gradle plugin generated files
|
||||||
# Eclipse Core
|
# Eclipse Core
|
||||||
.project
|
.project
|
||||||
|
|||||||
6
AndorsTrail/.idea/compiler.xml
generated
6
AndorsTrail/.idea/compiler.xml
generated
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="CompilerConfiguration">
|
|
||||||
<bytecodeTargetLevel target="11" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
20
AndorsTrail/.idea/gradle.xml
generated
20
AndorsTrail/.idea/gradle.xml
generated
@@ -1,20 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="GradleMigrationSettings" migrationVersion="1" />
|
|
||||||
<component name="GradleSettings">
|
|
||||||
<option name="linkedExternalProjectsSettings">
|
|
||||||
<GradleProjectSettings>
|
|
||||||
<option name="testRunner" value="GRADLE" />
|
|
||||||
<option name="distributionType" value="DEFAULT_WRAPPED" />
|
|
||||||
<option name="externalProjectPath" value="$PROJECT_DIR$" />
|
|
||||||
<option name="gradleJvm" value="1.8" />
|
|
||||||
<option name="modules">
|
|
||||||
<set>
|
|
||||||
<option value="$PROJECT_DIR$" />
|
|
||||||
<option value="$PROJECT_DIR$/app" />
|
|
||||||
</set>
|
|
||||||
</option>
|
|
||||||
</GradleProjectSettings>
|
|
||||||
</option>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
25
AndorsTrail/.idea/jarRepositories.xml
generated
25
AndorsTrail/.idea/jarRepositories.xml
generated
@@ -1,25 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="RemoteRepositoriesConfiguration">
|
|
||||||
<remote-repository>
|
|
||||||
<option name="id" value="central" />
|
|
||||||
<option name="name" value="Maven Central repository" />
|
|
||||||
<option name="url" value="https://repo1.maven.org/maven2" />
|
|
||||||
</remote-repository>
|
|
||||||
<remote-repository>
|
|
||||||
<option name="id" value="jboss.community" />
|
|
||||||
<option name="name" value="JBoss Community repository" />
|
|
||||||
<option name="url" value="https://repository.jboss.org/nexus/content/repositories/public/" />
|
|
||||||
</remote-repository>
|
|
||||||
<remote-repository>
|
|
||||||
<option name="id" value="BintrayJCenter" />
|
|
||||||
<option name="name" value="BintrayJCenter" />
|
|
||||||
<option name="url" value="https://jcenter.bintray.com/" />
|
|
||||||
</remote-repository>
|
|
||||||
<remote-repository>
|
|
||||||
<option name="id" value="Google" />
|
|
||||||
<option name="name" value="Google" />
|
|
||||||
<option name="url" value="https://dl.google.com/dl/android/maven2/" />
|
|
||||||
</remote-repository>
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
10
AndorsTrail/.idea/misc.xml
generated
10
AndorsTrail/.idea/misc.xml
generated
@@ -1,10 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="ExternalStorageConfigurationManager" enabled="true" />
|
|
||||||
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" project-jdk-name="11" project-jdk-type="JavaSDK">
|
|
||||||
<output url="file://$PROJECT_DIR$/build/classes" />
|
|
||||||
</component>
|
|
||||||
<component name="ProjectType">
|
|
||||||
<option name="id" value="Android" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
6
AndorsTrail/.idea/vcs.xml
generated
6
AndorsTrail/.idea/vcs.xml
generated
@@ -1,6 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<project version="4">
|
|
||||||
<component name="VcsDirectoryMappings">
|
|
||||||
<mapping directory="$PROJECT_DIR$/.." vcs="Git" />
|
|
||||||
</component>
|
|
||||||
</project>
|
|
||||||
@@ -7,10 +7,7 @@
|
|||||||
android:versionName="0.8.2"
|
android:versionName="0.8.2"
|
||||||
android:installLocation="auto"
|
android:installLocation="auto"
|
||||||
>
|
>
|
||||||
<uses-sdk
|
|
||||||
android:minSdkVersion="4"
|
|
||||||
android:targetSdkVersion="30"
|
|
||||||
/>
|
|
||||||
|
|
||||||
<supports-screens
|
<supports-screens
|
||||||
android:smallScreens="true"
|
android:smallScreens="true"
|
||||||
@@ -38,7 +35,7 @@
|
|||||||
<activity
|
<activity
|
||||||
android:name="com.gpl.rpg.AndorsTrail.activity.StartScreenActivity"
|
android:name="com.gpl.rpg.AndorsTrail.activity.StartScreenActivity"
|
||||||
android:clearTaskOnLaunch="true"
|
android:clearTaskOnLaunch="true"
|
||||||
>
|
android:exported="true">
|
||||||
<intent-filter>
|
<intent-filter>
|
||||||
<action android:name="android.intent.action.MAIN" />
|
<action android:name="android.intent.action.MAIN" />
|
||||||
<category android:name="android.intent.category.LAUNCHER" />
|
<category android:name="android.intent.category.LAUNCHER" />
|
||||||
@@ -46,7 +43,6 @@
|
|||||||
</activity>
|
</activity>
|
||||||
<activity
|
<activity
|
||||||
android:name="com.gpl.rpg.AndorsTrail.activity.MainActivity"
|
android:name="com.gpl.rpg.AndorsTrail.activity.MainActivity"
|
||||||
android:label="@string/app_name"
|
|
||||||
android:theme="@style/AndorsTrailTheme_Blue.NoBackground"
|
android:theme="@style/AndorsTrailTheme_Blue.NoBackground"
|
||||||
/>
|
/>
|
||||||
<activity android:name="com.gpl.rpg.AndorsTrail.activity.HeroinfoActivity" />
|
<activity android:name="com.gpl.rpg.AndorsTrail.activity.HeroinfoActivity" />
|
||||||
|
|||||||
@@ -1,16 +1,26 @@
|
|||||||
package com.gpl.rpg.AndorsTrail.activity;
|
package com.gpl.rpg.AndorsTrail.activity;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.ArrayList;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
import android.Manifest;
|
import android.Manifest;
|
||||||
import android.annotation.TargetApi;
|
import android.annotation.TargetApi;
|
||||||
import android.app.Activity;
|
import android.app.Activity;
|
||||||
import android.app.Dialog;
|
import android.app.Dialog;
|
||||||
|
import android.content.ClipData;
|
||||||
|
import android.content.ContentResolver;
|
||||||
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
import android.content.pm.PackageManager;
|
import android.content.pm.PackageManager;
|
||||||
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
|
import android.support.annotation.RequiresApi;
|
||||||
|
import android.support.v4.provider.DocumentFile;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.View.OnClickListener;
|
import android.view.View.OnClickListener;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@@ -22,241 +32,644 @@ import android.widget.Toast;
|
|||||||
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
|
import com.gpl.rpg.AndorsTrail.AndorsTrailApplication;
|
||||||
import com.gpl.rpg.AndorsTrail.AndorsTrailPreferences;
|
import com.gpl.rpg.AndorsTrail.AndorsTrailPreferences;
|
||||||
import com.gpl.rpg.AndorsTrail.R;
|
import com.gpl.rpg.AndorsTrail.R;
|
||||||
|
import com.gpl.rpg.AndorsTrail.controller.Constants;
|
||||||
import com.gpl.rpg.AndorsTrail.model.ModelContainer;
|
import com.gpl.rpg.AndorsTrail.model.ModelContainer;
|
||||||
import com.gpl.rpg.AndorsTrail.resource.tiles.TileManager;
|
import com.gpl.rpg.AndorsTrail.resource.tiles.TileManager;
|
||||||
import com.gpl.rpg.AndorsTrail.savegames.Savegames;
|
import com.gpl.rpg.AndorsTrail.savegames.Savegames;
|
||||||
import com.gpl.rpg.AndorsTrail.savegames.Savegames.FileHeader;
|
import com.gpl.rpg.AndorsTrail.savegames.Savegames.FileHeader;
|
||||||
|
import com.gpl.rpg.AndorsTrail.util.AndroidStorage;
|
||||||
import com.gpl.rpg.AndorsTrail.util.ThemeHelper;
|
import com.gpl.rpg.AndorsTrail.util.ThemeHelper;
|
||||||
import com.gpl.rpg.AndorsTrail.view.CustomDialogFactory;
|
import com.gpl.rpg.AndorsTrail.view.CustomDialogFactory;
|
||||||
|
|
||||||
public final class LoadSaveActivity extends AndorsTrailBaseActivity implements OnClickListener {
|
public final class LoadSaveActivity extends AndorsTrailBaseActivity implements OnClickListener {
|
||||||
private boolean isLoading = true;
|
private boolean isLoading = true;
|
||||||
private static final int SLOT_NUMBER_CREATE_NEW_SLOT = -1;
|
//region special slot numbers
|
||||||
private static final int SLOT_NUMBER_FIRST_SLOT = 1;
|
private static final int SLOT_NUMBER_CREATE_NEW_SLOT = -1;
|
||||||
private ModelContainer model;
|
public static final int SLOT_NUMBER_EXPORT_SAVEGAMES = -2;
|
||||||
private TileManager tileManager;
|
public static final int SLOT_NUMBER_IMPORT_SAVEGAMES = -3;
|
||||||
private AndorsTrailPreferences preferences;
|
public static final int SLOT_NUMBER_IMPORT_WORLDMAP = -4;
|
||||||
|
private static final int SLOT_NUMBER_FIRST_SLOT = 1;
|
||||||
|
//endregion
|
||||||
|
private ModelContainer model;
|
||||||
|
private TileManager tileManager;
|
||||||
|
private AndorsTrailPreferences preferences;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onCreate(Bundle savedInstanceState) {
|
public void onCreate(Bundle savedInstanceState) {
|
||||||
setTheme(ThemeHelper.getDialogTheme());
|
setTheme(ThemeHelper.getDialogTheme());
|
||||||
super.onCreate(savedInstanceState);
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
final AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(this);
|
final AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(this);
|
||||||
app.setWindowParameters(this);
|
app.setWindowParameters(this);
|
||||||
this.model = app.getWorld().model;
|
this.model = app.getWorld().model;
|
||||||
this.preferences = app.getPreferences();
|
this.preferences = app.getPreferences();
|
||||||
this.tileManager = app.getWorld().tileManager;
|
this.tileManager = app.getWorld().tileManager;
|
||||||
|
|
||||||
String loadsave = getIntent().getData().getLastPathSegment();
|
String loadsave = getIntent().getData().getLastPathSegment();
|
||||||
isLoading = (loadsave.equalsIgnoreCase("load"));
|
isLoading = (loadsave.equalsIgnoreCase("load"));
|
||||||
|
|
||||||
setContentView(R.layout.loadsave);
|
setContentView(R.layout.loadsave);
|
||||||
|
|
||||||
TextView tv = (TextView) findViewById(R.id.loadsave_title);
|
TextView tv = (TextView) findViewById(R.id.loadsave_title);
|
||||||
if (isLoading) {
|
if (isLoading) {
|
||||||
tv.setCompoundDrawablesWithIntrinsicBounds(android.R.drawable.ic_menu_search, 0, 0, 0);
|
tv.setCompoundDrawablesWithIntrinsicBounds(android.R.drawable.ic_menu_search, 0, 0, 0);
|
||||||
tv.setText(R.string.loadsave_title_load);
|
tv.setText(R.string.loadsave_title_load);
|
||||||
} else {
|
} else {
|
||||||
tv.setCompoundDrawablesWithIntrinsicBounds(android.R.drawable.ic_menu_save, 0, 0, 0);
|
tv.setCompoundDrawablesWithIntrinsicBounds(android.R.drawable.ic_menu_save, 0, 0, 0);
|
||||||
tv.setText(R.string.loadsave_title_save);
|
tv.setText(R.string.loadsave_title_save);
|
||||||
}
|
}
|
||||||
|
|
||||||
ViewGroup slotList = (ViewGroup) findViewById(R.id.loadsave_slot_list);
|
ViewGroup slotList = (ViewGroup) findViewById(R.id.loadsave_slot_list);
|
||||||
Button slotTemplateButton = (Button) findViewById(R.id.loadsave_slot_n);
|
Button slotTemplateButton = (Button) findViewById(R.id.loadsave_slot_n);
|
||||||
LayoutParams params = slotTemplateButton.getLayoutParams();
|
LayoutParams params = slotTemplateButton.getLayoutParams();
|
||||||
slotList.removeView(slotTemplateButton);
|
slotList.removeView(slotTemplateButton);
|
||||||
|
|
||||||
ViewGroup newSlotContainer = (ViewGroup) findViewById(R.id.loadsave_save_to_new_slot_container);
|
ViewGroup newSlotContainer = (ViewGroup) findViewById(R.id.loadsave_save_to_new_slot_container);
|
||||||
Button createNewSlot = (Button) findViewById(R.id.loadsave_save_to_new_slot);
|
Button createNewSlot = (Button) findViewById(R.id.loadsave_save_to_new_slot);
|
||||||
|
|
||||||
addSavegameSlotButtons(slotList, params, Savegames.getUsedSavegameSlots(this));
|
Button exportSaves = (Button) findViewById(R.id.loadsave_export_save);
|
||||||
|
Button importSaves = (Button) findViewById(R.id.loadsave_import_save);
|
||||||
|
Button importWorldmap = (Button) findViewById(R.id.loadsave_import_worldmap);
|
||||||
|
|
||||||
checkAndRequestPermissions();
|
exportSaves.setTag(SLOT_NUMBER_EXPORT_SAVEGAMES);
|
||||||
|
importSaves.setTag(SLOT_NUMBER_IMPORT_SAVEGAMES);
|
||||||
if (!isLoading) {
|
importWorldmap.setTag(SLOT_NUMBER_IMPORT_WORLDMAP);
|
||||||
createNewSlot.setTag(SLOT_NUMBER_CREATE_NEW_SLOT);
|
|
||||||
createNewSlot.setOnClickListener(this);
|
|
||||||
newSlotContainer.setVisibility(View.VISIBLE);
|
|
||||||
} else {
|
|
||||||
newSlotContainer.setVisibility(View.GONE);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static final int READ_EXTERNAL_STORAGE_REQUEST=1;
|
ViewGroup exportImportContainer = (ViewGroup) findViewById(R.id.loadsave_export_import_save_container);
|
||||||
private static final int WRITE_EXTERNAL_STORAGE_REQUEST=2;
|
|
||||||
|
|
||||||
@TargetApi(23)
|
|
||||||
private void checkAndRequestPermissions() {
|
|
||||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) {
|
|
||||||
if (getApplicationContext().checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
|
|
||||||
this.requestPermissions(new String[] {Manifest.permission.READ_EXTERNAL_STORAGE}, READ_EXTERNAL_STORAGE_REQUEST);
|
|
||||||
}
|
|
||||||
if (getApplicationContext().checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
|
|
||||||
this.requestPermissions(new String[] {Manifest.permission.WRITE_EXTERNAL_STORAGE}, WRITE_EXTERNAL_STORAGE_REQUEST);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
|
||||||
if (grantResults.length > 0 && grantResults[0] != PackageManager.PERMISSION_GRANTED) {
|
|
||||||
Toast.makeText(this, R.string.storage_permissions_mandatory, Toast.LENGTH_LONG).show();
|
|
||||||
((AndorsTrailApplication)getApplication()).discardWorld();
|
|
||||||
finish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addSavegameSlotButtons(ViewGroup parent, LayoutParams params, List<Integer> usedSavegameSlots) {
|
|
||||||
int unused = 1;
|
|
||||||
for (int slot : usedSavegameSlots) {
|
|
||||||
final FileHeader header = Savegames.quickload(this, slot);
|
|
||||||
if (header == null) continue;
|
|
||||||
|
|
||||||
while (unused < slot){
|
|
||||||
Button b = new Button(this);
|
|
||||||
b.setLayoutParams(params);
|
|
||||||
b.setTag(unused);
|
|
||||||
b.setOnClickListener(this);
|
|
||||||
b.setText(getString(R.string.loadsave_empty_slot, unused));
|
|
||||||
tileManager.setImageViewTileForPlayer(getResources(), b, header.iconID);
|
|
||||||
parent.addView(b, params);
|
|
||||||
unused++;
|
|
||||||
}
|
|
||||||
unused++;
|
|
||||||
|
|
||||||
Button b = new Button(this);
|
|
||||||
b.setLayoutParams(params);
|
|
||||||
b.setTag(slot);
|
|
||||||
b.setOnClickListener(this);
|
|
||||||
b.setText(slot + ". " + header.describe());
|
|
||||||
tileManager.setImageViewTileForPlayer(getResources(), b, header.iconID);
|
|
||||||
parent.addView(b, params);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void loadsave(int slot) {
|
|
||||||
if (slot == SLOT_NUMBER_CREATE_NEW_SLOT) {
|
|
||||||
List<Integer> usedSlots = Savegames.getUsedSavegameSlots(this);
|
|
||||||
if (usedSlots.isEmpty()) slot = SLOT_NUMBER_FIRST_SLOT;
|
|
||||||
else slot = Collections.max(usedSlots) + 1;
|
|
||||||
}
|
|
||||||
if (slot < SLOT_NUMBER_FIRST_SLOT) slot = SLOT_NUMBER_FIRST_SLOT;
|
|
||||||
|
|
||||||
Intent i = new Intent();
|
|
||||||
i.putExtra("slot", slot);
|
|
||||||
setResult(Activity.RESULT_OK, i);
|
|
||||||
LoadSaveActivity.this.finish();
|
|
||||||
}
|
|
||||||
|
|
||||||
private String getConfirmOverwriteQuestion(int slot) {
|
|
||||||
if (isLoading) return null;
|
|
||||||
if (slot == SLOT_NUMBER_CREATE_NEW_SLOT) return null; // if we're creating a new slot
|
|
||||||
if (!Savegames.getSlotFile(slot, this).exists()) return null;
|
|
||||||
|
|
||||||
if (preferences.displayOverwriteSavegame == AndorsTrailPreferences.CONFIRM_OVERWRITE_SAVEGAME_ALWAYS) {
|
|
||||||
return getString(R.string.loadsave_save_overwrite_confirmation_all);
|
|
||||||
}
|
|
||||||
if (preferences.displayOverwriteSavegame == AndorsTrailPreferences.CONFIRM_OVERWRITE_SAVEGAME_NEVER) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
final String currentPlayerName = model.player.getName();
|
|
||||||
final FileHeader header = Savegames.quickload(this, slot);
|
|
||||||
if (header == null) return null;
|
|
||||||
|
|
||||||
final String savedPlayerName = header.playerName;
|
|
||||||
if (currentPlayerName.equals(savedPlayerName)) return null; // if the names match
|
|
||||||
|
|
||||||
return getString(R.string.loadsave_save_overwrite_confirmation, savedPlayerName, currentPlayerName);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onClick(View view) {
|
|
||||||
final int slot = (Integer) view.getTag();
|
|
||||||
|
|
||||||
if (!isLoading && slot != SLOT_NUMBER_CREATE_NEW_SLOT && AndorsTrailApplication.CURRENT_VERSION == AndorsTrailApplication.DEVELOPMENT_INCOMPATIBLE_SAVEGAME_VERSION) {
|
|
||||||
final FileHeader header = Savegames.quickload(this, slot);
|
|
||||||
if (header != null && header.fileversion != AndorsTrailApplication.DEVELOPMENT_INCOMPATIBLE_SAVEGAME_VERSION) {
|
|
||||||
final Dialog d = CustomDialogFactory.createDialog(this,
|
|
||||||
"Overwriting not allowed",
|
|
||||||
getResources().getDrawable(android.R.drawable.ic_dialog_alert),
|
|
||||||
"You are currently using a development version of Andor's trail. Overwriting a regular savegame is not allowed in development mode.",
|
|
||||||
null,
|
|
||||||
true);
|
|
||||||
CustomDialogFactory.addDismissButton(d, android.R.string.ok);
|
|
||||||
CustomDialogFactory.show(d);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
if (isLoading) {
|
addSavegameSlotButtons(slotList, params, Savegames.getUsedSavegameSlots(this));
|
||||||
if(!Savegames.getSlotFile(slot, this).exists()) {
|
|
||||||
showErrorLoadingEmptySlot();
|
|
||||||
} else {
|
|
||||||
final FileHeader header = Savegames.quickload(this, slot);
|
|
||||||
if (header != null && !header.hasUnlimitedSaves) {
|
|
||||||
showSlotGetsDeletedOnLoadWarning(slot);
|
|
||||||
} else {
|
|
||||||
loadsave(slot);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
final String message = getConfirmOverwriteQuestion(slot);
|
|
||||||
if (message != null) {
|
|
||||||
showConfirmoverwriteQuestion(slot, message);
|
|
||||||
} else {
|
|
||||||
loadsave(slot);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showErrorLoadingEmptySlot() {
|
checkAndRequestPermissions();
|
||||||
final Dialog d = CustomDialogFactory.createDialog(this,
|
|
||||||
getString(R.string.startscreen_error_loading_game),
|
|
||||||
getResources().getDrawable(android.R.drawable.ic_dialog_alert),
|
|
||||||
getString(R.string.startscreen_error_loading_empty_slot),
|
|
||||||
null,
|
|
||||||
true);
|
|
||||||
CustomDialogFactory.addDismissButton(d, android.R.string.ok);
|
|
||||||
CustomDialogFactory.show(d);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showSlotGetsDeletedOnLoadWarning(final int slot) {
|
if (!isLoading) {
|
||||||
final Dialog d = CustomDialogFactory.createDialog(this,
|
createNewSlot.setTag(SLOT_NUMBER_CREATE_NEW_SLOT);
|
||||||
getString(R.string.startscreen_attention_slot_gets_delete_on_load),
|
createNewSlot.setOnClickListener(this);
|
||||||
getResources().getDrawable(android.R.drawable.ic_dialog_alert),
|
newSlotContainer.setVisibility(View.VISIBLE);
|
||||||
getString(R.string.startscreen_attention_message_slot_gets_delete_on_load),
|
exportImportContainer.setVisibility(View.GONE);
|
||||||
null,
|
} else {
|
||||||
true);
|
newSlotContainer.setVisibility(View.GONE);
|
||||||
CustomDialogFactory.addButton(d, android.R.string.ok, new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
loadsave(slot);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
CustomDialogFactory.show(d);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void showConfirmoverwriteQuestion(final int slot, String message) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||||
final String title =
|
exportSaves.setOnClickListener(this);
|
||||||
getString(R.string.loadsave_save_overwrite_confirmation_title) + ' '
|
importSaves.setOnClickListener(this);
|
||||||
+ getString(R.string.loadsave_save_overwrite_confirmation_slot, slot);
|
importWorldmap.setOnClickListener(this);
|
||||||
final Dialog d = CustomDialogFactory.createDialog(this,
|
exportImportContainer.setVisibility(View.VISIBLE);
|
||||||
title,
|
}
|
||||||
getResources().getDrawable(android.R.drawable.ic_dialog_alert),
|
}
|
||||||
message,
|
}
|
||||||
null,
|
|
||||||
true);
|
private static final int READ_EXTERNAL_STORAGE_REQUEST = 1;
|
||||||
|
private static final int WRITE_EXTERNAL_STORAGE_REQUEST = 2;
|
||||||
|
|
||||||
|
private void checkAndRequestPermissions() {
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && Build.VERSION.SDK_INT <= Build.VERSION_CODES.Q) {
|
||||||
|
if (getApplicationContext().checkSelfPermission(Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
|
||||||
|
this.requestPermissions(new String[]{Manifest.permission.READ_EXTERNAL_STORAGE}, READ_EXTERNAL_STORAGE_REQUEST);
|
||||||
|
}
|
||||||
|
if (getApplicationContext().checkSelfPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) {
|
||||||
|
this.requestPermissions(new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE}, WRITE_EXTERNAL_STORAGE_REQUEST);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
|
||||||
|
if (grantResults.length > 0 && grantResults[0] != PackageManager.PERMISSION_GRANTED) {
|
||||||
|
Toast.makeText(this, R.string.storage_permissions_mandatory, Toast.LENGTH_LONG).show();
|
||||||
|
((AndorsTrailApplication) getApplication()).discardWorld();
|
||||||
|
finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addSavegameSlotButtons(ViewGroup parent, LayoutParams params, List<Integer> usedSavegameSlots) {
|
||||||
|
int unused = 1;
|
||||||
|
for (int slot : usedSavegameSlots) {
|
||||||
|
final FileHeader header = Savegames.quickload(this, slot);
|
||||||
|
if (header == null) continue;
|
||||||
|
|
||||||
|
while (unused < slot) {
|
||||||
|
Button b = new Button(this);
|
||||||
|
b.setLayoutParams(params);
|
||||||
|
b.setTag(unused);
|
||||||
|
b.setOnClickListener(this);
|
||||||
|
b.setText(getString(R.string.loadsave_empty_slot, unused));
|
||||||
|
tileManager.setImageViewTileForPlayer(getResources(), b, header.iconID);
|
||||||
|
parent.addView(b, params);
|
||||||
|
unused++;
|
||||||
|
}
|
||||||
|
unused++;
|
||||||
|
|
||||||
|
Button b = new Button(this);
|
||||||
|
b.setLayoutParams(params);
|
||||||
|
b.setTag(slot);
|
||||||
|
b.setOnClickListener(this);
|
||||||
|
b.setText(slot + ". " + header.describe());
|
||||||
|
tileManager.setImageViewTileForPlayer(getResources(), b, header.iconID);
|
||||||
|
parent.addView(b, params);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void completeLoadSaveActivity(int slot) {
|
||||||
|
Intent i = new Intent();
|
||||||
|
if (slot == SLOT_NUMBER_CREATE_NEW_SLOT) {
|
||||||
|
List<Integer> usedSlots = Savegames.getUsedSavegameSlots(this);
|
||||||
|
if (usedSlots.isEmpty())
|
||||||
|
slot = SLOT_NUMBER_FIRST_SLOT;
|
||||||
|
else slot = Collections.max(usedSlots) + 1;
|
||||||
|
} else if (slot == SLOT_NUMBER_EXPORT_SAVEGAMES
|
||||||
|
|| slot == SLOT_NUMBER_IMPORT_SAVEGAMES
|
||||||
|
|| slot == SLOT_NUMBER_IMPORT_WORLDMAP) {
|
||||||
|
i.putExtra("import_export", true);
|
||||||
|
} else if (slot < SLOT_NUMBER_FIRST_SLOT)
|
||||||
|
slot = SLOT_NUMBER_FIRST_SLOT;
|
||||||
|
|
||||||
|
i.putExtra("slot", slot);
|
||||||
|
setResult(Activity.RESULT_OK, i);
|
||||||
|
LoadSaveActivity.this.finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getConfirmOverwriteQuestion(int slot) {
|
||||||
|
if (isLoading)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
return getConfirmOverwriteQuestionIgnoringLoading(slot);
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getConfirmOverwriteQuestionIgnoringLoading(int slot) {
|
||||||
|
if (slot == SLOT_NUMBER_CREATE_NEW_SLOT)
|
||||||
|
return null;//creating a new savegame
|
||||||
|
|
||||||
|
if (!Savegames.getSlotFile(slot, this).exists())
|
||||||
|
return null;//nothing in slot to overwrite
|
||||||
|
|
||||||
|
if (preferences.displayOverwriteSavegame == AndorsTrailPreferences.CONFIRM_OVERWRITE_SAVEGAME_ALWAYS) {
|
||||||
|
return getString(R.string.loadsave_save_overwrite_confirmation_all);
|
||||||
|
}
|
||||||
|
if (preferences.displayOverwriteSavegame == AndorsTrailPreferences.CONFIRM_OVERWRITE_SAVEGAME_NEVER) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String currentPlayerName = model.player.getName();
|
||||||
|
final FileHeader header = Savegames.quickload(this, slot);
|
||||||
|
if (header == null) return null;
|
||||||
|
|
||||||
|
final String savedPlayerName = header.playerName;
|
||||||
|
if (currentPlayerName.equals(savedPlayerName)) return null; //if the names match
|
||||||
|
|
||||||
|
return getString(R.string.loadsave_save_overwrite_confirmation, savedPlayerName, currentPlayerName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(View view) {
|
||||||
|
final int slot = (Integer) view.getTag();
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
switch (slot) {
|
||||||
|
case SLOT_NUMBER_IMPORT_WORLDMAP:
|
||||||
|
clickImportWorldmap();
|
||||||
|
return;
|
||||||
|
case SLOT_NUMBER_IMPORT_SAVEGAMES:
|
||||||
|
clickImportSaveGames();
|
||||||
|
return;
|
||||||
|
case SLOT_NUMBER_EXPORT_SAVEGAMES:
|
||||||
|
clickExportSaveGames();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!isLoading
|
||||||
|
&& slot != SLOT_NUMBER_CREATE_NEW_SLOT
|
||||||
|
&& AndorsTrailApplication.CURRENT_VERSION == AndorsTrailApplication.DEVELOPMENT_INCOMPATIBLE_SAVEGAME_VERSION) {
|
||||||
|
if (!isOverwriteTargetInIncompatibleVersion(slot)) {
|
||||||
|
saveOrOverwriteSavegame(slot);
|
||||||
|
}
|
||||||
|
} else if (isLoading) {
|
||||||
|
loadSaveGame(slot);
|
||||||
|
} else {
|
||||||
|
saveOrOverwriteSavegame(slot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveOrOverwriteSavegame(int slot) {
|
||||||
|
final String message = getConfirmOverwriteQuestion(slot);
|
||||||
|
if (message != null) {
|
||||||
|
showConfirmoverwriteQuestion(slot, message);
|
||||||
|
} else {
|
||||||
|
completeLoadSaveActivity(slot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean isOverwriteTargetInIncompatibleVersion(int slot) {
|
||||||
|
final FileHeader header = Savegames.quickload(this, slot);
|
||||||
|
if (header != null && header.fileversion != AndorsTrailApplication.DEVELOPMENT_INCOMPATIBLE_SAVEGAME_VERSION) {
|
||||||
|
final Dialog d = CustomDialogFactory.createErrorDialog(this, "Overwriting not allowed", "You are currently using a development version of Andor's trail. Overwriting a regular savegame is not allowed in development mode.");
|
||||||
|
CustomDialogFactory.show(d);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
//region Imports/Exports
|
||||||
|
|
||||||
|
private void exportSaveGames(Intent data) {
|
||||||
|
Uri uri = data.getData();
|
||||||
|
|
||||||
|
Context context = getApplicationContext();
|
||||||
|
ContentResolver resolver = AndorsTrailApplication.getApplicationFromActivity(this).getContentResolver();
|
||||||
|
|
||||||
|
File storageDir = AndroidStorage.getStorageDirectory(context, Constants.FILENAME_SAVEGAME_DIRECTORY);
|
||||||
|
DocumentFile source = DocumentFile.fromFile(storageDir);
|
||||||
|
DocumentFile target = DocumentFile.fromTreeUri(context, uri);
|
||||||
|
if (target == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DocumentFile[] files = source.listFiles();
|
||||||
|
|
||||||
|
boolean hasExistingFiles = false;
|
||||||
|
for (DocumentFile file :
|
||||||
|
files) {
|
||||||
|
String fileName = file.getName();
|
||||||
|
if (fileName == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
DocumentFile existingFile = target.findFile(fileName);
|
||||||
|
if (existingFile != null) {
|
||||||
|
hasExistingFiles = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasExistingFiles) {
|
||||||
|
showConfirmOverwriteByExportQuestion(resolver, target, files);
|
||||||
|
} else {
|
||||||
|
exportSaveGamesFolderContentToFolder(resolver, target, files);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void exportSaveGamesFolderContentToFolder(ContentResolver resolver, DocumentFile target, DocumentFile[] files) {
|
||||||
|
for (DocumentFile file : files) {
|
||||||
|
String fileName = file.getName();
|
||||||
|
DocumentFile existingFile = target.findFile(fileName);
|
||||||
|
boolean hasExistingFile = existingFile != null && existingFile.exists();
|
||||||
|
|
||||||
|
if (file.isFile()) {
|
||||||
|
try {
|
||||||
|
if (hasExistingFile)
|
||||||
|
existingFile.delete();
|
||||||
|
|
||||||
|
|
||||||
|
AndroidStorage.copyDocumentFileToNewOrExistingFile(file, resolver, target);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
} else if (file.isDirectory()) {
|
||||||
|
DocumentFile targetWorlmap = existingFile;
|
||||||
|
//if the folder exists already, put the files in the existing folder. (should not happen because of check earlier)
|
||||||
|
if (!hasExistingFile)
|
||||||
|
//create a new folder for the worldmap-files
|
||||||
|
targetWorlmap = target.createDirectory(Constants.FILENAME_WORLDMAP_DIRECTORY);
|
||||||
|
|
||||||
|
if (targetWorlmap == null)//Unable to create worldmap folder for some reason
|
||||||
|
continue;
|
||||||
|
|
||||||
|
DocumentFile[] worldmapFiles = file.listFiles();
|
||||||
|
for (DocumentFile f : worldmapFiles) {
|
||||||
|
try {
|
||||||
|
AndroidStorage.copyDocumentFileToNewOrExistingFile(f, resolver, targetWorlmap);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
completeLoadSaveActivity(SLOT_NUMBER_EXPORT_SAVEGAMES);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN)
|
||||||
|
private void importSaveGames(Intent data) {
|
||||||
|
Uri uri = data.getData();
|
||||||
|
ClipData uris = data.getClipData();
|
||||||
|
|
||||||
|
if (uri == null && uris == null) {
|
||||||
|
//no file was selected
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Context context = getApplicationContext();
|
||||||
|
ContentResolver resolver = context.getContentResolver();
|
||||||
|
|
||||||
|
File storageDir = AndroidStorage.getStorageDirectory(context, Constants.FILENAME_SAVEGAME_DIRECTORY);
|
||||||
|
DocumentFile appSavegameFolder = DocumentFile.fromFile(storageDir);
|
||||||
|
|
||||||
|
List<Uri> uriList = new ArrayList<>();
|
||||||
|
if (uri != null) {
|
||||||
|
uriList.add(uri);
|
||||||
|
} else {
|
||||||
|
for (int i = 0; i < uris.getItemCount(); i++)
|
||||||
|
uriList.add(uris.getItemAt(i).getUri());
|
||||||
|
}
|
||||||
|
importSaveGamesFromUris(context, resolver, appSavegameFolder, uriList);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void importSaveGamesFromUris(Context context, ContentResolver resolver, DocumentFile appSavegameFolder, List<Uri> uriList) {
|
||||||
|
int count = uriList.size();
|
||||||
|
|
||||||
|
ArrayList<DocumentFile> alreadyExistingFiles = new ArrayList<>();
|
||||||
|
ArrayList<DocumentFile> newFiles = new ArrayList<>();
|
||||||
|
|
||||||
|
for (int i = 0; i < count; i++) {
|
||||||
|
Uri item = uriList.get(i);
|
||||||
|
DocumentFile itemFile = DocumentFile.fromSingleUri(context, item);
|
||||||
|
boolean fileAlreadyExists = getExistsSavegameInOwnFiles(itemFile, appSavegameFolder);
|
||||||
|
if (fileAlreadyExists)
|
||||||
|
alreadyExistingFiles.add(itemFile);
|
||||||
|
else
|
||||||
|
newFiles.add(itemFile);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (alreadyExistingFiles.size() > 0) {
|
||||||
|
showConfirmOverwriteByImportQuestion(resolver, appSavegameFolder, alreadyExistingFiles, newFiles);
|
||||||
|
} else {
|
||||||
|
importSaveGames(resolver, appSavegameFolder, newFiles);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void importSaveGames(ContentResolver resolver, DocumentFile appSavegameFolder, List<DocumentFile> saveFiles) {
|
||||||
|
for (DocumentFile file : saveFiles) {
|
||||||
|
int slot = getSlotFromSavegameFileName(file.getName());
|
||||||
|
importSaveGameFile(resolver, appSavegameFolder, file, slot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private void completeSavegameImportAndCheckIfDone(List<Integer> importsNeedingConfirmation, int slot) {
|
||||||
|
importsNeedingConfirmation.remove((Object) slot);
|
||||||
|
if (importsNeedingConfirmation.isEmpty()) {
|
||||||
|
completeLoadSaveActivity(SLOT_NUMBER_IMPORT_SAVEGAMES);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private boolean getExistsSavegameInOwnFiles(DocumentFile savegameFile, DocumentFile appSavegameFolder) {
|
||||||
|
if (savegameFile == null)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
DocumentFile foundFile = appSavegameFolder.findFile(Objects.requireNonNull(savegameFile.getName()));
|
||||||
|
return foundFile != null && foundFile.exists();
|
||||||
|
}
|
||||||
|
|
||||||
|
private int getSlotFromSavegameFileName(String fileName) {
|
||||||
|
if (fileName == null || !fileName.startsWith(Constants.FILENAME_SAVEGAME_FILENAME_PREFIX)) {
|
||||||
|
//TODO: Maybe output a message that the file didn't have the right name?
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
String slotStr = fileName.substring(Constants.FILENAME_SAVEGAME_FILENAME_PREFIX.length());
|
||||||
|
|
||||||
|
int slot;
|
||||||
|
try {
|
||||||
|
slot = Integer.parseInt(slotStr);
|
||||||
|
return slot;
|
||||||
|
} catch (NumberFormatException e) {
|
||||||
|
//TODO: Maybe output a message that the file didn't have the right name?
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void importSaveGameFile(ContentResolver resolver, DocumentFile appSavegameFolder, DocumentFile itemFile, int slot) {
|
||||||
|
String targetName = Savegames.getSlotFileName(slot);
|
||||||
|
DocumentFile targetFile = getOrCreateDocumentFile(appSavegameFolder, targetName);
|
||||||
|
|
||||||
|
if (targetFile == null || !targetName.equals(targetFile.getName())) {
|
||||||
|
showErrorImportingSaveGameUnknown();//TODO: maybe replace with a more specific error message
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
AndroidStorage.copyDocumentFile(itemFile, resolver, targetFile);
|
||||||
|
} catch (IOException e) {
|
||||||
|
showErrorImportingSaveGameUnknown();
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private DocumentFile getOrCreateDocumentFile(DocumentFile folder, String targetName) {
|
||||||
|
DocumentFile targetFile = folder.findFile(targetName);//try finding the file
|
||||||
|
if (targetFile == null)//no file found, creating new one
|
||||||
|
targetFile = folder.createFile(Constants.NO_FILE_EXTENSION_MIME_TYPE, targetName);
|
||||||
|
return targetFile;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void importWorldmap(Intent data) {
|
||||||
|
Uri uri = data.getData();
|
||||||
|
|
||||||
|
Context context = getApplicationContext();
|
||||||
|
ContentResolver resolver = AndorsTrailApplication.getApplicationFromActivity(this).getContentResolver();
|
||||||
|
|
||||||
|
File storageDir = AndroidStorage.getStorageDirectory(context, Constants.FILENAME_SAVEGAME_DIRECTORY);
|
||||||
|
DocumentFile storageFolder = DocumentFile.fromFile(storageDir);
|
||||||
|
DocumentFile ownWorldmapFolder = storageFolder.findFile(Constants.FILENAME_WORLDMAP_DIRECTORY);
|
||||||
|
if (ownWorldmapFolder == null) {
|
||||||
|
ownWorldmapFolder = storageFolder.createDirectory(Constants.FILENAME_WORLDMAP_DIRECTORY);
|
||||||
|
}
|
||||||
|
|
||||||
|
DocumentFile chosenFolder = DocumentFile.fromTreeUri(context, uri);
|
||||||
|
if (chosenFolder == null || !chosenFolder.isDirectory()) {
|
||||||
|
showErrorImportingWorldmapWrongDirectory();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (!Constants.FILENAME_WORLDMAP_DIRECTORY.equals(chosenFolder.getName())) {
|
||||||
|
//user did not select the worldmap folder directly
|
||||||
|
DocumentFile file = chosenFolder.findFile(Constants.FILENAME_WORLDMAP_DIRECTORY);
|
||||||
|
if (file == null || !file.isDirectory() || !Constants.FILENAME_WORLDMAP_DIRECTORY.equals(file.getName())) {
|
||||||
|
//could not find a worldmap folder in the users selection
|
||||||
|
showErrorImportingWorldmapWrongDirectory();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
chosenFolder = file;
|
||||||
|
}
|
||||||
|
|
||||||
|
DocumentFile[] files = chosenFolder.listFiles();
|
||||||
|
for (DocumentFile file : files) {
|
||||||
|
if (file.isFile()) {
|
||||||
|
try {
|
||||||
|
AndroidStorage.copyDocumentFileToNewOrExistingFile(file, resolver, ownWorldmapFolder);
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
completeLoadSaveActivity(SLOT_NUMBER_IMPORT_WORLDMAP);
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||||
|
private void clickExportSaveGames() {
|
||||||
|
startActivityForResult(AndroidStorage.getNewOpenDirectoryIntent(), -SLOT_NUMBER_EXPORT_SAVEGAMES);
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||||
|
private void clickImportSaveGames() {
|
||||||
|
startActivityForResult(AndroidStorage.getNewSelectMultipleSavegameFilesIntent(), -SLOT_NUMBER_IMPORT_SAVEGAMES);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||||
|
private void clickImportWorldmap() {
|
||||||
|
startActivityForResult(AndroidStorage.getNewOpenDirectoryIntent(), -SLOT_NUMBER_IMPORT_WORLDMAP);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showConfirmOverwriteByExportQuestion(ContentResolver resolver, DocumentFile targetFolder, DocumentFile[] files) {
|
||||||
|
final Dialog d = CustomDialogFactory.createDialog(this,
|
||||||
|
getString(R.string.loadsave_export_overwrite_confirmation_title),
|
||||||
|
getResources().getDrawable(android.R.drawable.ic_dialog_alert),
|
||||||
|
getString(R.string.loadsave_export_overwrite_confirmation),
|
||||||
|
null,
|
||||||
|
true);
|
||||||
|
|
||||||
|
CustomDialogFactory.addButton(d, android.R.string.yes, v -> exportSaveGamesFolderContentToFolder(resolver, targetFolder, files));
|
||||||
|
CustomDialogFactory.addDismissButton(d, android.R.string.no);
|
||||||
|
|
||||||
|
CustomDialogFactory.show(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showConfirmOverwriteByImportQuestion(ContentResolver resolver,
|
||||||
|
DocumentFile appSavegameFolder,
|
||||||
|
List<DocumentFile> alreadyExistingFiles,
|
||||||
|
List<DocumentFile> newFiles) {
|
||||||
|
final String title = getString(R.string.loadsave_import_overwrite_confirmation_title);
|
||||||
|
String message = getString(R.string.loadsave_import_overwrite_confirmation);
|
||||||
|
|
||||||
|
StringBuilder sb = new StringBuilder();
|
||||||
|
sb.append('\n');
|
||||||
|
int amount = alreadyExistingFiles.size();
|
||||||
|
|
||||||
|
Context context = AndorsTrailApplication.getApplicationFromActivity(this).getApplicationContext();
|
||||||
|
|
||||||
|
for (int i = 0; i < amount && i < 3; i++) {
|
||||||
|
DocumentFile alreadyExistingFile = alreadyExistingFiles.get(i);
|
||||||
|
String alreadyExistingFileName = alreadyExistingFile.getName();
|
||||||
|
FileHeader fileHeader = Savegames.quickload(context, getSlotFromSavegameFileName(alreadyExistingFileName));
|
||||||
|
sb.append('\n');
|
||||||
|
String fileHeaderDesription = "";
|
||||||
|
if (fileHeader != null)
|
||||||
|
fileHeaderDesription = fileHeader.describe();
|
||||||
|
|
||||||
|
sb.append(getString(R.string.loadsave_import_overwrite_confirmation_file_pattern, alreadyExistingFileName, fileHeaderDesription));
|
||||||
|
// sb.append(alreadyExistingFile.getName());
|
||||||
|
}
|
||||||
|
if (amount > 3) {
|
||||||
|
sb.append("\n...");
|
||||||
|
}
|
||||||
|
message = message + sb;
|
||||||
|
final Dialog d = CustomDialogFactory.createDialog(this,
|
||||||
|
title,
|
||||||
|
getResources().getDrawable(android.R.drawable.ic_dialog_alert),
|
||||||
|
message,
|
||||||
|
null,
|
||||||
|
true);
|
||||||
|
|
||||||
|
CustomDialogFactory.addButton(d, android.R.string.yes, v -> newFiles.addAll(alreadyExistingFiles));
|
||||||
|
CustomDialogFactory.addDismissButton(d, android.R.string.no);
|
||||||
|
CustomDialogFactory.setDismissListener(d, dialog -> {
|
||||||
|
importSaveGames(resolver, appSavegameFolder, newFiles);
|
||||||
|
completeLoadSaveActivity(SLOT_NUMBER_IMPORT_SAVEGAMES);
|
||||||
|
});
|
||||||
|
CustomDialogFactory.show(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
|
|
||||||
|
if (resultCode != Activity.RESULT_OK)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
|
||||||
|
switch (-requestCode) {
|
||||||
|
case SLOT_NUMBER_EXPORT_SAVEGAMES:
|
||||||
|
exportSaveGames(data);
|
||||||
|
return;
|
||||||
|
case SLOT_NUMBER_IMPORT_SAVEGAMES:
|
||||||
|
importSaveGames(data);
|
||||||
|
return;
|
||||||
|
case SLOT_NUMBER_IMPORT_WORLDMAP:
|
||||||
|
importWorldmap(data);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
private void loadSaveGame(int slot) {
|
||||||
|
if (!Savegames.getSlotFile(slot, this).exists()) {
|
||||||
|
showErrorLoadingEmptySlot();
|
||||||
|
} else {
|
||||||
|
final FileHeader header = Savegames.quickload(this, slot);
|
||||||
|
if (header != null && !header.hasUnlimitedSaves) {
|
||||||
|
showSlotGetsDeletedOnLoadWarning(slot);
|
||||||
|
} else {
|
||||||
|
completeLoadSaveActivity(slot);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//region show Dialogs
|
||||||
|
|
||||||
|
private void showErrorImportingWorldmapWrongDirectory() {
|
||||||
|
final Dialog d = CustomDialogFactory.createErrorDialog(this,
|
||||||
|
getString(R.string.loadsave_import_worldmap_unsuccessfull),
|
||||||
|
getString(R.string.loadsave_import_worldmap_unsuccessfull_wrong_directory));
|
||||||
|
CustomDialogFactory.show(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showErrorImportingSaveGameUnknown() {
|
||||||
|
final Dialog d = CustomDialogFactory.createErrorDialog(this,
|
||||||
|
getString(R.string.loadsave_import_save_unsuccessfull),
|
||||||
|
getString(R.string.loadsave_import_save_unsuccessfull_unknown));
|
||||||
|
CustomDialogFactory.show(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showErrorLoadingEmptySlot() {
|
||||||
|
final Dialog d = CustomDialogFactory.createErrorDialog(this,
|
||||||
|
getString(R.string.startscreen_error_loading_game),
|
||||||
|
getString(R.string.startscreen_error_loading_empty_slot));
|
||||||
|
CustomDialogFactory.show(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showSlotGetsDeletedOnLoadWarning(final int slot) {
|
||||||
|
final Dialog d = CustomDialogFactory.createDialog(this,
|
||||||
|
getString(R.string.startscreen_attention_slot_gets_delete_on_load),
|
||||||
|
getResources().getDrawable(android.R.drawable.ic_dialog_alert),
|
||||||
|
getString(R.string.startscreen_attention_message_slot_gets_delete_on_load),
|
||||||
|
null,
|
||||||
|
true);
|
||||||
|
CustomDialogFactory.addButton(d, android.R.string.ok, v -> completeLoadSaveActivity(slot));
|
||||||
|
CustomDialogFactory.show(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void showConfirmoverwriteQuestion(final int slot, String message) {
|
||||||
|
final String title =
|
||||||
|
getString(R.string.loadsave_save_overwrite_confirmation_title) + ' '
|
||||||
|
+ getString(R.string.loadsave_save_overwrite_confirmation_slot, slot);
|
||||||
|
final Dialog d = CustomDialogFactory.createDialog(this,
|
||||||
|
title,
|
||||||
|
getResources().getDrawable(android.R.drawable.ic_dialog_alert),
|
||||||
|
message,
|
||||||
|
null,
|
||||||
|
true);
|
||||||
|
|
||||||
|
CustomDialogFactory.addButton(d, android.R.string.yes, v -> completeLoadSaveActivity(slot));
|
||||||
|
CustomDialogFactory.addDismissButton(d, android.R.string.no);
|
||||||
|
CustomDialogFactory.show(d);
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
CustomDialogFactory.addButton(d, android.R.string.yes, new View.OnClickListener() {
|
|
||||||
@Override
|
|
||||||
public void onClick(View v) {
|
|
||||||
loadsave(slot);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
CustomDialogFactory.addDismissButton(d, android.R.string.no);
|
|
||||||
CustomDialogFactory.show(d);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,22 +41,22 @@ import com.gpl.rpg.AndorsTrail.view.CustomDialogFactory;
|
|||||||
|
|
||||||
public class StartScreenActivity_MainMenu extends Fragment {
|
public class StartScreenActivity_MainMenu extends Fragment {
|
||||||
|
|
||||||
private static final int INTENTREQUEST_PREFERENCES = 7;
|
private static final int INTENTREQUEST_PREFERENCES = 7;
|
||||||
public static final int INTENTREQUEST_LOADGAME = 9;
|
public static final int INTENTREQUEST_LOADGAME = 9;
|
||||||
|
|
||||||
private boolean hasExistingGame = false;
|
private boolean hasExistingGame = false;
|
||||||
private Button startscreen_continue;
|
private Button startscreen_continue;
|
||||||
private Button startscreen_newgame;
|
private Button startscreen_newgame;
|
||||||
private Button startscreen_load;
|
private Button startscreen_load;
|
||||||
private ViewGroup save_preview_holder;
|
private ViewGroup save_preview_holder;
|
||||||
private ImageView save_preview_hero_icon;
|
private ImageView save_preview_hero_icon;
|
||||||
private TextView save_preview_hero_desc;
|
private TextView save_preview_hero_desc;
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
updatePreferences(false);
|
updatePreferences(false);
|
||||||
super.onCreateView(inflater, container, savedInstanceState);
|
super.onCreateView(inflater, container, savedInstanceState);
|
||||||
|
|
||||||
|
|
||||||
if (container != null) {
|
if (container != null) {
|
||||||
@@ -339,49 +339,51 @@ public class StartScreenActivity_MainMenu extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
public void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||||
super.onActivityResult(requestCode, resultCode, data);
|
super.onActivityResult(requestCode, resultCode, data);
|
||||||
switch (requestCode) {
|
switch (requestCode) {
|
||||||
case INTENTREQUEST_LOADGAME:
|
case INTENTREQUEST_LOADGAME:
|
||||||
if (resultCode != Activity.RESULT_OK) break;
|
if (resultCode != Activity.RESULT_OK) break;
|
||||||
final int slot = data.getIntExtra("slot", 1);
|
final boolean wasImportOrExport = data.getBooleanExtra("import_export", false);
|
||||||
continueGame(false, slot, null);
|
if (wasImportOrExport) break;
|
||||||
break;
|
final int slot = data.getIntExtra("slot", 1);
|
||||||
case INTENTREQUEST_PREFERENCES:
|
continueGame(false, slot, null);
|
||||||
updatePreferences(true);
|
break;
|
||||||
break;
|
case INTENTREQUEST_PREFERENCES:
|
||||||
}
|
updatePreferences(true);
|
||||||
}
|
break;
|
||||||
|
}
|
||||||
private void updatePreferences(boolean alreadyStartedLoadingResources) {
|
}
|
||||||
AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(getActivity());
|
|
||||||
AndorsTrailPreferences preferences = app.getPreferences();
|
private void updatePreferences(boolean alreadyStartedLoadingResources) {
|
||||||
preferences.read(getActivity());
|
AndorsTrailApplication app = AndorsTrailApplication.getApplicationFromActivity(getActivity());
|
||||||
if (app.setLocale(getActivity())) {
|
AndorsTrailPreferences preferences = app.getPreferences();
|
||||||
if (alreadyStartedLoadingResources) {
|
preferences.read(getActivity());
|
||||||
// Changing the locale after having loaded the game requires resources to
|
if (app.setLocale(getActivity())) {
|
||||||
// be re-loaded. Therefore, we just exit here.
|
if (alreadyStartedLoadingResources) {
|
||||||
Toast.makeText(getActivity(), R.string.change_locale_requires_restart, Toast.LENGTH_LONG).show();
|
// Changing the locale after having loaded the game requires resources to
|
||||||
doFinish();
|
// be re-loaded. Therefore, we just exit here.
|
||||||
return;
|
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();
|
if (ThemeHelper.changeTheme(preferences.selectedTheme)) {
|
||||||
doFinish();
|
// Changing the theme requires a restart to re-create all activities.
|
||||||
return;
|
Toast.makeText(getActivity(), R.string.change_theme_requires_restart, Toast.LENGTH_LONG).show();
|
||||||
}
|
doFinish();
|
||||||
app.getWorld().tileManager.updatePreferences(preferences);
|
return;
|
||||||
}
|
}
|
||||||
|
app.getWorld().tileManager.updatePreferences(preferences);
|
||||||
@SuppressLint("NewApi")
|
}
|
||||||
private void doFinish() {
|
|
||||||
//For Lollipop and above
|
@SuppressLint("NewApi")
|
||||||
((AndorsTrailApplication)getActivity().getApplication()).discardWorld();
|
private void doFinish() {
|
||||||
getActivity().finish();
|
//For Lollipop and above
|
||||||
}
|
((AndorsTrailApplication) getActivity().getApplication()).discardWorld();
|
||||||
|
getActivity().finish();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public interface OnNewGameRequestedListener {
|
public interface OnNewGameRequestedListener {
|
||||||
|
|||||||
@@ -51,6 +51,10 @@ public final class Constants {
|
|||||||
public static final String CHEAT_DETECTION_FOLDER = "dEAGyGE3YojqXjI3x4x7";
|
public static final String CHEAT_DETECTION_FOLDER = "dEAGyGE3YojqXjI3x4x7";
|
||||||
public static final String PASSIVE_ACHIEVEMENT_CHECK_PHRASE = "passive_achievement_check";
|
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 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) { 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; }
|
public static int rollValue(final ConstRange r, int bias) { return rollValue((r.max + 1) * 100 -1, r.current * 100 + bias)/100; }
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ package com.gpl.rpg.AndorsTrail.controller;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.Intent;
|
import android.content.Intent;
|
||||||
|
import android.os.Build;
|
||||||
import android.util.SparseIntArray;
|
import android.util.SparseIntArray;
|
||||||
import android.view.KeyEvent;
|
import android.view.KeyEvent;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
@@ -98,28 +99,36 @@ public final class InputController implements OnClickListener, OnLongClickListen
|
|||||||
|
|
||||||
// Keys mapping to UP_LEFT
|
// Keys mapping to UP_LEFT
|
||||||
key = KEY_MOVE_UP_LEFT;
|
key = KEY_MOVE_UP_LEFT;
|
||||||
keyMap.put(KeyEvent.KEYCODE_DPAD_UP_LEFT, key);
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||||
|
keyMap.put(KeyEvent.KEYCODE_DPAD_UP_LEFT, key);
|
||||||
|
}
|
||||||
keyMap.put(KeyEvent.KEYCODE_NUMPAD_7, key);
|
keyMap.put(KeyEvent.KEYCODE_NUMPAD_7, key);
|
||||||
keyMap.put(KeyEvent.KEYCODE_7, key);
|
keyMap.put(KeyEvent.KEYCODE_7, key);
|
||||||
keyMap.put(KeyEvent.KEYCODE_MOVE_HOME, key);
|
keyMap.put(KeyEvent.KEYCODE_MOVE_HOME, key);
|
||||||
|
|
||||||
// Keys mapping to UP_RIGHT
|
// Keys mapping to UP_RIGHT
|
||||||
key = KEY_MOVE_UP_RIGHT;
|
key = KEY_MOVE_UP_RIGHT;
|
||||||
keyMap.put(KeyEvent.KEYCODE_DPAD_UP_RIGHT, key);
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||||
|
keyMap.put(KeyEvent.KEYCODE_DPAD_UP_RIGHT, key);
|
||||||
|
}
|
||||||
keyMap.put(KeyEvent.KEYCODE_NUMPAD_9, key);
|
keyMap.put(KeyEvent.KEYCODE_NUMPAD_9, key);
|
||||||
keyMap.put(KeyEvent.KEYCODE_9, key);
|
keyMap.put(KeyEvent.KEYCODE_9, key);
|
||||||
keyMap.put(KeyEvent.KEYCODE_PAGE_UP, key);
|
keyMap.put(KeyEvent.KEYCODE_PAGE_UP, key);
|
||||||
|
|
||||||
// Keys mapping to DOWN_LEFT
|
// Keys mapping to DOWN_LEFT
|
||||||
key = KEY_MOVE_DOWN_LEFT;
|
key = KEY_MOVE_DOWN_LEFT;
|
||||||
keyMap.put(KeyEvent.KEYCODE_DPAD_DOWN_LEFT, key);
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||||
|
keyMap.put(KeyEvent.KEYCODE_DPAD_DOWN_LEFT, key);
|
||||||
|
}
|
||||||
keyMap.put(KeyEvent.KEYCODE_NUMPAD_1, key);
|
keyMap.put(KeyEvent.KEYCODE_NUMPAD_1, key);
|
||||||
keyMap.put(KeyEvent.KEYCODE_1, key);
|
keyMap.put(KeyEvent.KEYCODE_1, key);
|
||||||
keyMap.put(KeyEvent.KEYCODE_MOVE_END, key);
|
keyMap.put(KeyEvent.KEYCODE_MOVE_END, key);
|
||||||
|
|
||||||
// Keys mapping to DOWN_RIGHT
|
// Keys mapping to DOWN_RIGHT
|
||||||
key = KEY_MOVE_DOWN_RIGHT;
|
key = KEY_MOVE_DOWN_RIGHT;
|
||||||
keyMap.put(KeyEvent.KEYCODE_DPAD_DOWN_RIGHT, key);
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
||||||
|
keyMap.put(KeyEvent.KEYCODE_DPAD_DOWN_RIGHT, key);
|
||||||
|
}
|
||||||
keyMap.put(KeyEvent.KEYCODE_NUMPAD_3, key);
|
keyMap.put(KeyEvent.KEYCODE_NUMPAD_3, key);
|
||||||
keyMap.put(KeyEvent.KEYCODE_3, key);
|
keyMap.put(KeyEvent.KEYCODE_3, key);
|
||||||
keyMap.put(KeyEvent.KEYCODE_PAGE_DOWN, key);
|
keyMap.put(KeyEvent.KEYCODE_PAGE_DOWN, key);
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ import com.gpl.rpg.AndorsTrail.model.actor.MonsterType;
|
|||||||
import com.gpl.rpg.AndorsTrail.model.item.ItemType;
|
import com.gpl.rpg.AndorsTrail.model.item.ItemType;
|
||||||
import com.gpl.rpg.AndorsTrail.model.map.PredefinedMap;
|
import com.gpl.rpg.AndorsTrail.model.map.PredefinedMap;
|
||||||
import com.gpl.rpg.AndorsTrail.model.quest.Quest;
|
import com.gpl.rpg.AndorsTrail.model.quest.Quest;
|
||||||
|
import com.gpl.rpg.AndorsTrail.util.HashMapHelper;
|
||||||
|
|
||||||
public final class GameStatistics {
|
public final class GameStatistics {
|
||||||
private int deaths = 0;
|
private int deaths = 0;
|
||||||
@@ -36,10 +37,10 @@ public final class GameStatistics {
|
|||||||
|
|
||||||
public void addMonsterKill(MonsterType monsterType) {
|
public void addMonsterKill(MonsterType monsterType) {
|
||||||
// Track monster kills by type ID, for savegame file
|
// Track monster kills by type ID, for savegame file
|
||||||
killedMonstersByTypeID.put(monsterType.id, killedMonstersByTypeID.getOrDefault((monsterType.id), 0) + 1);
|
killedMonstersByTypeID.put(monsterType.id, getNumberOfKillsForMonsterType(monsterType.id) + 1);
|
||||||
|
|
||||||
// Also track by name, for statistics display (multiple IDs w/same name don't matter to player)
|
// Also track by name, for statistics display (multiple IDs w/same name don't matter to player)
|
||||||
killedMonstersByName.put(monsterType.name, killedMonstersByName.getOrDefault(monsterType.name, 0) + 1);
|
killedMonstersByName.put(monsterType.name, getNumberOfKillsForMonsterName(monsterType.name) + 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addPlayerDeath(int lostExp) {
|
public void addPlayerDeath(int lostExp) {
|
||||||
@@ -50,8 +51,7 @@ public final class GameStatistics {
|
|||||||
}
|
}
|
||||||
public void addItemUsage(ItemType type) {
|
public void addItemUsage(ItemType type) {
|
||||||
final String n = type.id;
|
final String n = type.id;
|
||||||
if (!usedItems.containsKey(n)) usedItems.put(n, 1);
|
usedItems.put(n, HashMapHelper.getOrDefault(usedItems, n,0) + 1);
|
||||||
else usedItems.put(n, usedItems.get(n) + 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getDeaths() {
|
public int getDeaths() {
|
||||||
@@ -73,15 +73,11 @@ public final class GameStatistics {
|
|||||||
public boolean isDead() { return !hasUnlimitedLives() && getLivesLeft() < 1; }
|
public boolean isDead() { return !hasUnlimitedLives() && getLivesLeft() < 1; }
|
||||||
|
|
||||||
public int getNumberOfKillsForMonsterType(String monsterTypeID) {
|
public int getNumberOfKillsForMonsterType(String monsterTypeID) {
|
||||||
Integer v = killedMonstersByTypeID.get(monsterTypeID);
|
return HashMapHelper.getOrDefault(killedMonstersByTypeID, monsterTypeID, 0);
|
||||||
if (v == null) return 0;
|
|
||||||
return v;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getNumberOfKillsForMonsterName(String monsterName) {
|
public int getNumberOfKillsForMonsterName(String monsterName) {
|
||||||
Integer v = killedMonstersByName.get(monsterName);
|
return HashMapHelper.getOrDefault(killedMonstersByName, monsterName, 0);
|
||||||
if (v == null) return 0;
|
|
||||||
return v;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getTop5MostCommonlyKilledMonsters(WorldContext world, Resources res) {
|
public String getTop5MostCommonlyKilledMonsters(WorldContext world, Resources res) {
|
||||||
@@ -144,20 +140,15 @@ public final class GameStatistics {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public int getNumberOfUsedItems() {
|
public int getNumberOfUsedItems() {
|
||||||
int result = 0;
|
return HashMapHelper.sumIntegerValues(usedItems);
|
||||||
for (int v : usedItems.values()) result += v;
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getNumberOfTimesItemHasBeenUsed(String itemId) {
|
public int getNumberOfTimesItemHasBeenUsed(String itemId) {
|
||||||
if (!usedItems.containsKey(itemId)) return 0;
|
return HashMapHelper.getOrDefault(usedItems, itemId, 0);
|
||||||
return usedItems.get(itemId);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getNumberOfKilledMonsters() {
|
public int getNumberOfKilledMonsters() {
|
||||||
int result = 0;
|
return HashMapHelper.sumIntegerValues(killedMonstersByTypeID);
|
||||||
for (int v : killedMonstersByTypeID.values()) result += v;
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final Comparator<Entry<String, Integer>> descendingValueComparator = new Comparator<Entry<String, Integer>>() {
|
private static final Comparator<Entry<String, Integer>> descendingValueComparator = new Comparator<Entry<String, Integer>>() {
|
||||||
@@ -186,7 +177,7 @@ public final class GameStatistics {
|
|||||||
// Also track by name, for statistics display (multiple IDs w/same name don't matter to player)
|
// Also track by name, for statistics display (multiple IDs w/same name don't matter to player)
|
||||||
MonsterType t = world.monsterTypes.getMonsterType(id);
|
MonsterType t = world.monsterTypes.getMonsterType(id);
|
||||||
|
|
||||||
if (t != null) killedMonstersByName.put(t.name, killedMonstersByName.getOrDefault(t.name, 0) + value);
|
if (t != null) killedMonstersByName.put(t.name, getNumberOfKillsForMonsterName(t.name) + value);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fileversion <= 17) return;
|
if (fileversion <= 17) return;
|
||||||
|
|||||||
@@ -86,7 +86,7 @@ public final class Savegames {
|
|||||||
|
|
||||||
private static void writeBackup(Context androidContext, byte[] savegame, String playerId) throws IOException {
|
private static void writeBackup(Context androidContext, byte[] savegame, String playerId) throws IOException {
|
||||||
File cheatDetectionFolder = AndroidStorage.getStorageDirectory(androidContext, Constants.CHEAT_DETECTION_FOLDER);
|
File cheatDetectionFolder = AndroidStorage.getStorageDirectory(androidContext, Constants.CHEAT_DETECTION_FOLDER);
|
||||||
if (!cheatDetectionFolder.exists()) cheatDetectionFolder.mkdir();
|
ensureDirExists(cheatDetectionFolder);
|
||||||
File backupFile = new File(cheatDetectionFolder, playerId + "X");
|
File backupFile = new File(cheatDetectionFolder, playerId + "X");
|
||||||
FileOutputStream fileOutputStream = new FileOutputStream(backupFile);
|
FileOutputStream fileOutputStream = new FileOutputStream(backupFile);
|
||||||
fileOutputStream.write(savegame);
|
fileOutputStream.write(savegame);
|
||||||
@@ -127,34 +127,33 @@ public final class Savegames {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static boolean triedToCheat(Context androidContext, FileHeader fh) throws IOException {
|
private static boolean triedToCheat(Context androidContext, FileHeader fh) throws IOException {
|
||||||
long savedVersionToCheck = 0;
|
long savedVersionToCheck = 0;
|
||||||
File cheatDetectionFolder = AndroidStorage.getStorageDirectory(androidContext, Constants.CHEAT_DETECTION_FOLDER);
|
File cheatDetectionFolder = AndroidStorage.getStorageDirectory(androidContext, Constants.CHEAT_DETECTION_FOLDER);
|
||||||
if (!cheatDetectionFolder.exists()) cheatDetectionFolder.mkdir();
|
ensureDirExists(cheatDetectionFolder);
|
||||||
File cheatDetectionFile = new File(cheatDetectionFolder, fh.playerId);
|
File cheatDetectionFile = new File(cheatDetectionFolder, fh.playerId);
|
||||||
if (cheatDetectionFile.exists()) {
|
if (cheatDetectionFile.exists()) {
|
||||||
FileInputStream fileInputStream = new FileInputStream(cheatDetectionFile);
|
FileInputStream fileInputStream = new FileInputStream(cheatDetectionFile);
|
||||||
DataInputStream dataInputStream = new DataInputStream(fileInputStream);
|
DataInputStream dataInputStream = new DataInputStream(fileInputStream);
|
||||||
final CheatDetection cheatDetection = new CheatDetection(dataInputStream);
|
final CheatDetection cheatDetection = new CheatDetection(dataInputStream);
|
||||||
savedVersionToCheck = cheatDetection.savedVersion;
|
savedVersionToCheck = cheatDetection.savedVersion;
|
||||||
dataInputStream.close();
|
dataInputStream.close();
|
||||||
fileInputStream.close();
|
fileInputStream.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (savedVersionToCheck == DENY_LOADING_BECAUSE_GAME_IS_CURRENTLY_PLAYED) {
|
if (savedVersionToCheck == DENY_LOADING_BECAUSE_GAME_IS_CURRENTLY_PLAYED) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (androidContext.getFileStreamPath(fh.playerId).exists()) {
|
if (androidContext.getFileStreamPath(fh.playerId).exists()) {
|
||||||
FileInputStream fileInputStream = androidContext.openFileInput(fh.playerId);
|
FileInputStream fileInputStream = androidContext.openFileInput(fh.playerId);
|
||||||
DataInputStream dataInputStream = new DataInputStream(fileInputStream);
|
DataInputStream dataInputStream = new DataInputStream(fileInputStream);
|
||||||
final CheatDetection cheatDetection = new CheatDetection(dataInputStream);
|
final CheatDetection cheatDetection = new CheatDetection(dataInputStream);
|
||||||
if (cheatDetection.savedVersion == DENY_LOADING_BECAUSE_GAME_IS_CURRENTLY_PLAYED) {
|
if (cheatDetection.savedVersion == DENY_LOADING_BECAUSE_GAME_IS_CURRENTLY_PLAYED) {
|
||||||
savedVersionToCheck = DENY_LOADING_BECAUSE_GAME_IS_CURRENTLY_PLAYED;
|
savedVersionToCheck = DENY_LOADING_BECAUSE_GAME_IS_CURRENTLY_PLAYED;
|
||||||
}
|
} else if (cheatDetection.savedVersion > savedVersionToCheck) {
|
||||||
else if (cheatDetection.savedVersion > savedVersionToCheck) {
|
savedVersionToCheck = cheatDetection.savedVersion;
|
||||||
savedVersionToCheck = cheatDetection.savedVersion;
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) {
|
if (AndorsTrailApplication.DEVELOPMENT_DEBUGMESSAGES) {
|
||||||
L.log("Internal cheatcheck file savedVersion: " + cheatDetection.savedVersion);
|
L.log("Internal cheatcheck file savedVersion: " + cheatDetection.savedVersion);
|
||||||
@@ -167,31 +166,48 @@ public final class Savegames {
|
|||||||
return (savedVersionToCheck == DENY_LOADING_BECAUSE_GAME_IS_CURRENTLY_PLAYED || fh.savedVersion < savedVersionToCheck);
|
return (savedVersionToCheck == DENY_LOADING_BECAUSE_GAME_IS_CURRENTLY_PLAYED || fh.savedVersion < savedVersionToCheck);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static FileOutputStream getOutputFile(Context androidContext, int slot) throws IOException {
|
private static FileOutputStream getOutputFile(Context androidContext, int slot) throws IOException {
|
||||||
if (slot == SLOT_QUICKSAVE) {
|
if (slot == SLOT_QUICKSAVE) {
|
||||||
return androidContext.openFileOutput(Constants.FILENAME_SAVEGAME_QUICKSAVE, Context.MODE_PRIVATE);
|
return androidContext.openFileOutput(Constants.FILENAME_SAVEGAME_QUICKSAVE, Context.MODE_PRIVATE);
|
||||||
} else {
|
} else {
|
||||||
ensureSavegameDirectoryExists(androidContext);
|
ensureSavegameDirectoryExists(androidContext);
|
||||||
return new FileOutputStream(getSlotFile(slot, 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));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static File getSlotFile(int slot, Context context) {
|
private static void ensureSavegameDirectoryExists(Context context) {
|
||||||
File root = AndroidStorage.getStorageDirectory(context, Constants.FILENAME_SAVEGAME_DIRECTORY);
|
File dir = AndroidStorage.getStorageDirectory(context, Constants.FILENAME_SAVEGAME_DIRECTORY);
|
||||||
return new File(root, Constants.FILENAME_SAVEGAME_FILENAME_PREFIX + slot);
|
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 {
|
||||||
@@ -207,10 +223,11 @@ public final class Savegames {
|
|||||||
dest.close();
|
dest.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static LoadSavegameResult loadWorld(Resources res, WorldContext world, ControllerContext controllers, InputStream inState, FileHeader fh) throws IOException {
|
public static LoadSavegameResult loadWorld(Resources res, WorldContext world, ControllerContext controllers, InputStream inState, FileHeader fh) throws IOException {
|
||||||
DataInputStream src = new DataInputStream(inState);
|
DataInputStream src = new DataInputStream(inState);
|
||||||
final FileHeader header = new FileHeader(src, fh.skipIcon);
|
final FileHeader header = new FileHeader(src, fh.skipIcon);
|
||||||
if (header.fileversion > AndorsTrailApplication.CURRENT_VERSION) return LoadSavegameResult.savegameIsFromAFutureVersion;
|
if (header.fileversion > AndorsTrailApplication.CURRENT_VERSION)
|
||||||
|
return LoadSavegameResult.savegameIsFromAFutureVersion;
|
||||||
|
|
||||||
world.maps.readFromParcel(src, world, controllers, header.fileversion);
|
world.maps.readFromParcel(src, world, controllers, header.fileversion);
|
||||||
world.model = new ModelContainer(src, world, controllers, header.fileversion);
|
world.model = new ModelContainer(src, world, controllers, header.fileversion);
|
||||||
@@ -249,15 +266,15 @@ public final class Savegames {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void writeCheatCheck(Context androidContext, long savedVersion, String playerId) throws IOException {
|
private static void writeCheatCheck(Context androidContext, long savedVersion, String playerId) throws IOException {
|
||||||
File cheatDetectionFolder = AndroidStorage.getStorageDirectory(androidContext, Constants.CHEAT_DETECTION_FOLDER);
|
File cheatDetectionFolder = AndroidStorage.getStorageDirectory(androidContext, Constants.CHEAT_DETECTION_FOLDER);
|
||||||
if (!cheatDetectionFolder.exists()) cheatDetectionFolder.mkdir();
|
ensureDirExists(cheatDetectionFolder);
|
||||||
File cheatDetectionFile = new File(cheatDetectionFolder, playerId);
|
File cheatDetectionFile = new File(cheatDetectionFolder, playerId);
|
||||||
FileOutputStream fileOutputStream = new FileOutputStream(cheatDetectionFile);
|
FileOutputStream fileOutputStream = new FileOutputStream(cheatDetectionFile);
|
||||||
DataOutputStream dataOutputStream = new DataOutputStream(fileOutputStream);
|
DataOutputStream dataOutputStream = new DataOutputStream(fileOutputStream);
|
||||||
CheatDetection.writeToParcel(dataOutputStream, savedVersion);
|
CheatDetection.writeToParcel(dataOutputStream, savedVersion);
|
||||||
dataOutputStream.close();
|
dataOutputStream.close();
|
||||||
fileOutputStream.close();
|
fileOutputStream.close();
|
||||||
|
|
||||||
fileOutputStream = androidContext.openFileOutput(playerId, Context.MODE_PRIVATE);
|
fileOutputStream = androidContext.openFileOutput(playerId, Context.MODE_PRIVATE);
|
||||||
dataOutputStream = new DataOutputStream(fileOutputStream);
|
dataOutputStream = new DataOutputStream(fileOutputStream);
|
||||||
@@ -268,26 +285,26 @@ public final class Savegames {
|
|||||||
|
|
||||||
private static final Pattern savegameFilenamePattern = Pattern.compile(Constants.FILENAME_SAVEGAME_FILENAME_PREFIX + "(\\d+)");
|
private static final Pattern savegameFilenamePattern = Pattern.compile(Constants.FILENAME_SAVEGAME_FILENAME_PREFIX + "(\\d+)");
|
||||||
|
|
||||||
public static List<Integer> getUsedSavegameSlots(Context context) {
|
public static List<Integer> getUsedSavegameSlots(Context context) {
|
||||||
try {
|
try {
|
||||||
final List<Integer> result = new ArrayList<Integer>();
|
final List<Integer> result = new ArrayList<Integer>();
|
||||||
AndroidStorage.getStorageDirectory(context, Constants.FILENAME_SAVEGAME_DIRECTORY).listFiles(new FilenameFilter() {
|
AndroidStorage.getStorageDirectory(context, Constants.FILENAME_SAVEGAME_DIRECTORY).listFiles(new FilenameFilter() {
|
||||||
@Override
|
@Override
|
||||||
public boolean accept(File f, String filename) {
|
public boolean accept(File f, String filename) {
|
||||||
Matcher m = savegameFilenamePattern.matcher(filename);
|
Matcher m = savegameFilenamePattern.matcher(filename);
|
||||||
if (m != null && m.matches()) {
|
if (m != null && m.matches()) {
|
||||||
result.add(Integer.parseInt(m.group(1)));
|
result.add(Integer.parseInt(m.group(1)));
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
Collections.sort(result);
|
Collections.sort(result);
|
||||||
return result;
|
return result;
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return null;
|
return new ArrayList<Integer>();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final class CheatDetection {
|
private static final class CheatDetection {
|
||||||
public final int fileversion;
|
public final int fileversion;
|
||||||
@@ -307,17 +324,16 @@ public final class Savegames {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static final class FileHeader {
|
||||||
public static final class FileHeader {
|
public final int fileversion;
|
||||||
public final int fileversion;
|
public final String playerName;
|
||||||
public final String playerName;
|
public final String displayInfo;
|
||||||
public final String displayInfo;
|
public final int iconID;
|
||||||
public final int iconID;
|
public boolean skipIcon = false;
|
||||||
public boolean skipIcon = false;
|
public final boolean isDead;
|
||||||
public final boolean isDead;
|
public final boolean hasUnlimitedSaves;
|
||||||
public final boolean hasUnlimitedSaves;
|
public final String playerId;
|
||||||
public final String playerId;
|
public final long savedVersion;
|
||||||
public final long savedVersion;
|
|
||||||
|
|
||||||
public String describe() {
|
public String describe() {
|
||||||
return (fileversion == AndorsTrailApplication.DEVELOPMENT_INCOMPATIBLE_SAVEGAME_VERSION ? "(D) " : "") + playerName + ", " + displayInfo;
|
return (fileversion == AndorsTrailApplication.DEVELOPMENT_INCOMPATIBLE_SAVEGAME_VERSION ? "(D) " : "") + playerName + ", " + displayInfo;
|
||||||
@@ -326,17 +342,18 @@ public final class Savegames {
|
|||||||
|
|
||||||
// ====== PARCELABLE ===================================================================
|
// ====== PARCELABLE ===================================================================
|
||||||
|
|
||||||
public FileHeader(DataInputStream src, boolean skipIcon) throws IOException {
|
public FileHeader(DataInputStream src, boolean skipIcon) throws IOException {
|
||||||
int fileversion = src.readInt();
|
int fileversion = src.readInt();
|
||||||
if (fileversion == 11) fileversion = 5; // Fileversion 5 had no version identifier, but the first byte was 11.
|
if (fileversion == 11)
|
||||||
this.fileversion = fileversion;
|
fileversion = 5; // Fileversion 5 had no version identifier, but the first byte was 11.
|
||||||
if (fileversion >= 14) { // Before fileversion 14 (0.6.7), we had no file header.
|
this.fileversion = fileversion;
|
||||||
this.playerName = src.readUTF();
|
if (fileversion >= 14) { // Before fileversion 14 (0.6.7), we had no file header.
|
||||||
this.displayInfo = src.readUTF();
|
this.playerName = src.readUTF();
|
||||||
} else {
|
this.displayInfo = src.readUTF();
|
||||||
this.playerName = null;
|
} else {
|
||||||
this.displayInfo = null;
|
this.playerName = null;
|
||||||
}
|
this.displayInfo = null;
|
||||||
|
}
|
||||||
|
|
||||||
if (fileversion >= 43) {
|
if (fileversion >= 43) {
|
||||||
int id = src.readInt();
|
int id = src.readInt();
|
||||||
|
|||||||
@@ -1,10 +1,16 @@
|
|||||||
package com.gpl.rpg.AndorsTrail.util;
|
package com.gpl.rpg.AndorsTrail.util;
|
||||||
|
|
||||||
|
import android.content.ContentResolver;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.Intent;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.os.Build;
|
import android.os.Build;
|
||||||
import android.os.Environment;
|
import android.os.Environment;
|
||||||
|
import android.support.annotation.NonNull;
|
||||||
|
import android.support.annotation.RequiresApi;
|
||||||
import android.support.v4.content.FileProvider;
|
import android.support.v4.content.FileProvider;
|
||||||
|
import android.support.v4.provider.DocumentFile;
|
||||||
|
import android.webkit.MimeTypeMap;
|
||||||
|
|
||||||
import com.gpl.rpg.AndorsTrail.controller.Constants;
|
import com.gpl.rpg.AndorsTrail.controller.Constants;
|
||||||
|
|
||||||
@@ -17,7 +23,7 @@ import java.io.OutputStream;
|
|||||||
|
|
||||||
public final class AndroidStorage {
|
public final class AndroidStorage {
|
||||||
public static File getStorageDirectory(Context context, String name) {
|
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);
|
return context.getExternalFilesDir(name);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -25,6 +31,7 @@ public final class AndroidStorage {
|
|||||||
return new File(root, name);
|
return new File(root, name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean shouldMigrateToInternalStorage(Context context) {
|
public static boolean shouldMigrateToInternalStorage(Context context) {
|
||||||
boolean ret = false;
|
boolean ret = false;
|
||||||
File externalSaveGameDirectory = new File(Environment.getExternalStorageDirectory(), Constants.FILENAME_SAVEGAME_DIRECTORY);
|
File externalSaveGameDirectory = new File(Environment.getExternalStorageDirectory(), Constants.FILENAME_SAVEGAME_DIRECTORY);
|
||||||
@@ -76,33 +83,90 @@ public final class AndroidStorage {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void copyFile(File source, File target) throws IOException {
|
public static void copyFile(File source, File target) throws IOException {
|
||||||
InputStream in = null;
|
try (InputStream in = new FileInputStream(source); OutputStream out = new FileOutputStream(target)) {
|
||||||
OutputStream out = null;
|
copyStream(in, out);
|
||||||
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);
|
|
||||||
}
|
|
||||||
} finally {
|
|
||||||
if (in != null) {
|
|
||||||
in.close();
|
|
||||||
}
|
|
||||||
if (out != null) {
|
|
||||||
out.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the MIME-Type for a file.<p/>
|
||||||
|
* Fallback value is '* / *' (without spaces) <p/>
|
||||||
|
* Mostly copied together from: <a href="https://stackoverflow.com/q/8589645/17292289">StackOverflow</a>
|
||||||
|
*/
|
||||||
|
@NonNull
|
||||||
|
public static String getMimeType(ContentResolver resolver, Uri uri) {
|
||||||
|
String type = null;
|
||||||
|
if (ContentResolver.SCHEME_CONTENT.equals(uri.getScheme())) {
|
||||||
|
type = resolver.getType(uri);
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
|
final String extension = MimeTypeMap.getFileExtensionFromUrl(uri.getPath());
|
||||||
|
if (extension != null) {
|
||||||
|
type = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension.toLowerCase());
|
||||||
|
}
|
||||||
|
if (type == null) {
|
||||||
|
type = "*/*"; // fallback type.
|
||||||
|
}
|
||||||
|
return type;
|
||||||
|
}
|
||||||
|
|
||||||
public static String getUrlForFile(Context context, File worldmap) {
|
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) {
|
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||||
Uri uri = FileProvider.getUriForFile(context, "com.gpl.rpg.AndorsTrail.fileprovider", worldmap);
|
Uri uri = FileProvider.getUriForFile(context, "com.gpl.rpg.AndorsTrail.fileprovider", worldmap);//TODO: remove fixed fileprovider
|
||||||
return uri.toString();
|
return uri.toString();
|
||||||
} else {
|
} else {
|
||||||
return "file://" + worldmap.getAbsolutePath();
|
return "file://" + worldmap.getAbsolutePath();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
|
||||||
|
public static Intent getNewOpenDirectoryIntent() {
|
||||||
|
Intent intent = new Intent(Intent.ACTION_OPEN_DOCUMENT_TREE);
|
||||||
|
return intent;
|
||||||
|
}
|
||||||
|
|
||||||
|
@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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package com.gpl.rpg.AndorsTrail.util;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
|
||||||
|
public final class HashMapHelper {
|
||||||
|
public static <K,V> V getOrDefault(HashMap<K,V> map, K key, V defaultValue) {
|
||||||
|
V v = map.get(key);
|
||||||
|
return v == null ? defaultValue : v;
|
||||||
|
}
|
||||||
|
public static <K> Integer sumIntegerValues(HashMap<K,Integer> map) {
|
||||||
|
int sum = 0;
|
||||||
|
for (Integer v : map.values()) sum += v;
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -88,6 +88,17 @@ public class CustomDialogFactory {
|
|||||||
|
|
||||||
return dialog;
|
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) {
|
public static CustomDialog setTitle(final CustomDialog dialog, String title, Drawable icon) {
|
||||||
TextView titleView = (TextView) dialog.findViewById(R.id.dialog_title);
|
TextView titleView = (TextView) dialog.findViewById(R.id.dialog_title);
|
||||||
|
|||||||
@@ -1,7 +0,0 @@
|
|||||||
## This file must *NOT* be checked into Version Control Systems,
|
|
||||||
# as it contains information specific to your local configuration.
|
|
||||||
#
|
|
||||||
# Location of the SDK. This is only used by Gradle.
|
|
||||||
#
|
|
||||||
#Sun Sep 25 12:50:59 CEST 2022
|
|
||||||
sdk.dir=C\:\\Users\\chris\\AppData\\Local\\Android\\Sdk
|
|
||||||
@@ -51,19 +51,45 @@
|
|||||||
</ScrollView>
|
</ScrollView>
|
||||||
|
|
||||||
<LinearLayout
|
<LinearLayout
|
||||||
android:id="@+id/loadsave_save_to_new_slot_container"
|
android:id="@+id/loadsave_save_to_new_slot_container"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:orientation="vertical"
|
||||||
|
style="@style/AndorsTrail_Style_StdFrame"
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
android:id="@+id/loadsave_save_to_new_slot"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
android:orientation="vertical"
|
android:text="@string/loadsave_save_to_new_slot"
|
||||||
style="@style/AndorsTrail_Style_StdFrame"
|
/>
|
||||||
>
|
</LinearLayout>
|
||||||
<Button
|
|
||||||
android:id="@+id/loadsave_save_to_new_slot"
|
|
||||||
android:layout_width="match_parent"
|
<LinearLayout
|
||||||
android:layout_height="wrap_content"
|
android:id="@+id/loadsave_export_import_save_container"
|
||||||
android:text="@string/loadsave_save_to_new_slot"
|
android:layout_width="match_parent"
|
||||||
/>
|
android:layout_height="wrap_content"
|
||||||
</LinearLayout>
|
android:orientation="vertical"
|
||||||
|
style="@style/AndorsTrail_Style_StdFrame"
|
||||||
|
>
|
||||||
|
<Button
|
||||||
|
android:id="@+id/loadsave_export_save"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/loadsave_export_save"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
android:id="@+id/loadsave_import_save"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/loadsave_import_save"
|
||||||
|
/>
|
||||||
|
<Button
|
||||||
|
android:id="@+id/loadsave_import_worldmap"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:text="@string/loadsave_import_worldmap"
|
||||||
|
/>
|
||||||
|
</LinearLayout>
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user