Changes Filesystem::setSource mount order on Android

Simplifies the way setSource is handled on Android. It tries to mount
first and if that fails it will copy to memory and mount.

The /sdcard/lovegame fallback is moved to GameActivity.java.

Also a flag is added (mustCacheArchive) that will copy the game.love
file to the cache dir, so it can be mounted directly and not loaded to
memory, which does not work for large .love files.

The Filesystem.cpp change was also submitted to rude/love repo in this
push request: https://bitbucket.org/rude/love/pull-requests/99
This commit is contained in:
cigumo
2017-11-16 19:53:41 -03:00
parent 646de828b9
commit 957330d722
2 changed files with 98 additions and 52 deletions
@@ -233,57 +233,29 @@ bool Filesystem::setSource(const char *source)
if (!love::android::createStorageDirectories()) if (!love::android::createStorageDirectories())
SDL_Log("Error creating storage directories!"); SDL_Log("Error creating storage directories!");
char* game_archive_ptr = NULL; new_search_path = love::android::getSelectedGameFile();
size_t game_archive_size = 0;
bool archive_loaded = false;
// try to load the game that was sent to LÖVE via a Intent // try mounting first, if that fails, load to memory and mount
archive_loaded = love::android::loadGameArchiveToMemory(love::android::getSelectedGameFile(), &game_archive_ptr, &game_archive_size); if (!PHYSFS_mount(new_search_path.c_str(), nullptr, 1))
if (!archive_loaded)
{ {
// try to load the game in the assets/ folder // PHYSFS cannot yet mount a zip file inside an .apk
archive_loaded = love::android::loadGameArchiveToMemory("game.love", &game_archive_ptr, &game_archive_size); SDL_Log("Mounting %s did not work. Loading to memory.",
} new_search_path.c_str());
char* game_archive_ptr = NULL;
if (archive_loaded) size_t game_archive_size = 0;
{ if (!love::android::loadGameArchiveToMemory(
if (!PHYSFS_mountMemory(game_archive_ptr, game_archive_size, love::android::freeGameArchiveMemory, "archive.zip", "/", 0)) new_search_path.c_str(), &game_archive_ptr,
&game_archive_size))
{ {
SDL_Log("Mounting of in-memory game archive failed!"); SDL_Log("Failure memory loading archive %s", new_search_path.c_str());
love::android::freeGameArchiveMemory(game_archive_ptr);
return false; return false;
} }
} if (!PHYSFS_mountMemory(
else game_archive_ptr, game_archive_size,
{ love::android::freeGameArchiveMemory, "archive.zip", "/", 0))
// try to load the game in the directory that was sent to LÖVE via an
// Intent ...
std::string game_path = std::string(love::android::getSelectedGameFile());
if (game_path == "")
{ {
// ... or fall back to the game at /sdcard/lovegame SDL_Log("Failure mounting in-memory archive.");
game_path = "/sdcard/lovegame/"; love::android::freeGameArchiveMemory(game_archive_ptr);
}
SDL_RWops *sdcard_main = SDL_RWFromFile(std::string(game_path + "main.lua").c_str(), "rb");
if (sdcard_main)
{
new_search_path = game_path;
sdcard_main->close(sdcard_main);
if (!PHYSFS_mount(new_search_path.c_str(), nullptr, 1))
{
SDL_Log("mounting of %s failed", new_search_path.c_str());
return false;
}
}
else
{
// Neither assets/game.love or /sdcard/lovegame was mounted
// sucessfully, therefore simply fail.
return false; return false;
} }
} }
@@ -2,9 +2,11 @@ package org.love2d.android;
import org.libsdl.app.SDLActivity; import org.libsdl.app.SDLActivity;
import java.util.Arrays;
import java.util.List; import java.util.List;
import java.io.BufferedInputStream; import java.io.BufferedInputStream;
import java.io.BufferedOutputStream; import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
@@ -39,7 +41,7 @@ public class GameActivity extends SDLActivity {
private static Context context; private static Context context;
private static Vibrator vibrator = null; private static Vibrator vibrator = null;
private static boolean immersiveActive = false; private static boolean immersiveActive = false;
private static boolean mustCacheArchive = false;
@Override @Override
protected String[] getLibraries() { protected String[] getLibraries() {
return new String[] { return new String[] {
@@ -76,14 +78,13 @@ public class GameActivity extends SDLActivity {
handleIntent (intent); handleIntent (intent);
resetNative(); resetNative();
startNative(); startNative();
}; }
protected void handleIntent (Intent intent) { protected void handleIntent (Intent intent) {
Uri game = intent.getData(); Uri game = intent.getData();
if (game != null) { if (game != null) {
if (game.getScheme().equals ("file")) { if (game.getScheme().equals ("file")) {
Log.d("GameActivity", "Received intent with path: " + game.getPath()); Log.d("GameActivity", "Received intent with path: " + game.getPath());
// If we were given the path of a main.lua then use its // If we were given the path of a main.lua then use its
// directory. Otherwise use full path. // directory. Otherwise use full path.
List<String> path_segments = game.getPathSegments(); List<String> path_segments = game.getPathSegments();
@@ -93,12 +94,36 @@ public class GameActivity extends SDLActivity {
gamePath = game.getPath(); gamePath = game.getPath();
} }
} else { } else {
copyGameToCache (game); // if archive exists, copy it to the cache
copyGameToCache (game);
return;
} }
Log.d("GameActivity", "new gamePath: " + gamePath); Log.d("GameActivity", "new gamePath: " + gamePath);
} else {
boolean archiveExists = false;
try {
List<String> assets = Arrays.asList(getAssets().list(""));
archiveExists = assets.contains("game.love");
} catch (Exception e) {
Log.d("GameActivity", "could not list application assets:" + e.getMessage());
}
if (archiveExists) {
String df = this.getCacheDir().getPath()+"/game.love";
if (mustCacheArchive && copyAssetFile("game.love",df))
gamePath = df;
else
gamePath = "game.love";
} else {
File ext = Environment.getExternalStorageDirectory();
if ((new File(ext,"/lovegame/main.lua")).exists()) {
gamePath = ext.getPath() + "/lovegame/";
}
}
Log.d("GameActivity", "new gamePath: " + gamePath);
} }
}; }
@Override @Override
protected void onDestroy() { protected void onDestroy() {
@@ -198,7 +223,56 @@ public class GameActivity extends SDLActivity {
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i); context.startActivity(i);
} }
boolean copyAssetFile(String fileName, String destF)
{
boolean success = false;
// open streams
BufferedOutputStream bos = null;
try {
bos = new BufferedOutputStream(new FileOutputStream(destF, false));
} catch (IOException e) {
Log.d ("GameActivity", "Could not open destination file:" + e.getMessage());
}
InputStream ins = null;
try {
ins = getAssets().open(fileName);
} catch (IOException e) {
Log.d("GameActivity", "Could not open game file:" + e.getMessage());
}
// copy
int bytes_written = 0;
if (ins != null && bos != null) {
int chunk_read = 0;
try {
byte[] buf = new byte[8192];
chunk_read = ins.read(buf);
do {
bos.write(buf, 0, chunk_read);
bytes_written += chunk_read;
chunk_read = ins.read(buf);
} while(chunk_read != -1);
} catch (IOException e) {
Log.d ("GameActivity", "Copying failed:" + e.getMessage());
}
}
// close streams
try {
if (ins != null) ins.close();
if (bos != null) bos.close();
success = true;
} catch (IOException e) {
Log.d ("GameActivity", "Copying failed: " + e.getMessage());
}
Log.d("GameActivity", "Copied " + fileName + " to " + destF
+ ". Wrote:" + bytes_written + " bytes");
return success;
}
void copyGameToCache (Uri sourceuri) void copyGameToCache (Uri sourceuri)
{ {
String destinationFilename = this.getCacheDir().getPath()+"/downloaded.love"; String destinationFilename = this.getCacheDir().getPath()+"/downloaded.love";