From d71773af4be25f85238c44d7dd71c7c9bb309779 Mon Sep 17 00:00:00 2001 From: Ghabry Date: Thu, 23 May 2024 21:17:03 +0200 Subject: [PATCH] Android: Try to load the title image in three ways 1. If only one title image: Use this one 2. By parsing the database 3. By taking the first image in the title folder This approach is surprisingly fast and the caching skips the scan after the first time. --- ...asyrpg_player_game_browser_GameScanner.cpp | 99 +++++++++++++++---- src/filefinder.cpp | 8 -- src/filefinder.h | 8 ++ 3 files changed, 88 insertions(+), 27 deletions(-) diff --git a/builds/android/app/src/gamebrowser/org_easyrpg_player_game_browser_GameScanner.cpp b/builds/android/app/src/gamebrowser/org_easyrpg_player_game_browser_GameScanner.cpp index 1cf15c8f6b0..92f0f27bb5b 100644 --- a/builds/android/app/src/gamebrowser/org_easyrpg_player_game_browser_GameScanner.cpp +++ b/builds/android/app/src/gamebrowser/org_easyrpg_player_game_browser_GameScanner.cpp @@ -31,12 +31,15 @@ #include #include - #include "filefinder.h" #include "utils.h" #include "string_view.h" #include "platform/android/android.h" +#include +#include +#include + // via https://stackoverflow.com/q/1821806 static void custom_png_write_func(png_structp png_ptr, png_bytep data, png_size_t length) { std::vector *p = reinterpret_cast*>(png_get_io_ptr(png_ptr)); @@ -216,28 +219,86 @@ Java_org_easyrpg_player_game_1browser_GameScanner_findGames(JNIEnv *env, jclass } } - // Very simple title graphic search: The first image in "Title" is used - auto title_fs = fs.Subtree("Title"); + /// Obtaining of the title image: + // 1. When the title directory contains only one image: Load it + // 2. Attempt to fetch it from the database + // 3. If this fails grab the first from the title folder jbyteArray title_image = nullptr; + + auto load_image = [&](Filesystem_Stream::InputStream& stream) { + if (!stream) { + return; + } + + if (stream.GetName().ends_with(".xyz")) { + title_image = readXyz(env, stream); + } else if (stream.GetName().ends_with(".png") || stream.GetName().ends_with(".bmp")) { + auto vec = Utils::ReadStream(stream); + title_image = env->NewByteArray(vec.size()); + env->SetByteArrayRegion(title_image, 0, vec.size(), reinterpret_cast(vec.data())); + } + }; + + // 1. When the title directory contains only one image: Load it + auto title_fs = fs.Subtree("Title"); if (title_fs) { - for (auto &[name, entry]: *title_fs.ListDirectory()) { - if (entry.type == DirectoryTree::FileType::Regular) { - if (StringView(name).ends_with(".xyz")) { - auto is = title_fs.OpenInputStream(entry.name); - title_image = readXyz(env, is); - } else if (StringView(name).ends_with(".png") || - StringView(name).ends_with(".bmp")) { - auto is = title_fs.OpenInputStream(entry.name); - if (!is) { - // When opening of the image fails it is an unsupported archive format - // Skip this game - continue; + auto& content = *title_fs.ListDirectory(); + if (content.size() == 1 && content[0].second.type == DirectoryTree::FileType::Regular) { + auto is = title_fs.OpenInputStream(content[0].second.name); + if (!is) { + // When opening of the image fails it is in an unsupported archive format + // Skip this game + continue; + } + load_image(is); + } + } + + // 2. Attempt to fetch it from the database + if (!title_image) { + std::string db_file = fs.FindFile("RPG_RT.ldb"); + if (!db_file.empty()) { + // This can fail when the database file is renamed, is not an error condition + auto is = fs.OpenInputStream(db_file); + if (!is) { + // When opening of the db fails it is in an unsupported archive format + // Skip this game + continue; + } else { + auto db = lcf::LDB_Reader::Load(is); + if (!db) { + // Database corrupted? Skip + continue; + } + + if (!db->system.title_name.empty()) { + auto encodings = lcf::ReaderUtil::DetectEncodings(*db); + for (auto &enc: encodings) { + lcf::Encoder encoder(enc); + if (encoder.IsOk()) { + std::string title_name = lcf::ToString(db->system.title_name); + encoder.Encode(title_name); + auto title_is = fs.OpenFile("Title", title_name, FileFinder::IMG_TYPES); + // Title image was found -> Load it + load_image(title_is); + } } + } + } + } + } - auto vec = Utils::ReadStream(is); - title_image = env->NewByteArray(vec.size()); - env->SetByteArrayRegion(title_image, 0, vec.size(), - reinterpret_cast(vec.data())); + // 3. Simply grab the first from the title folder + if (!title_image) { + // No image loaded yet: Grab the first from the title folder + if (title_fs) { + for (auto &[name, entry]: *title_fs.ListDirectory()) { + if (entry.type == DirectoryTree::FileType::Regular) { + auto is = title_fs.OpenInputStream(entry.name); + load_image(is); + if (title_image) { + break; + } } } } diff --git a/src/filefinder.cpp b/src/filefinder.cpp index b0341a45573..ea2ac1500fb 100644 --- a/src/filefinder.cpp +++ b/src/filefinder.cpp @@ -62,14 +62,6 @@ namespace { std::shared_ptr root_fs; FilesystemView game_fs; FilesystemView save_fs; - - constexpr const auto IMG_TYPES = Utils::MakeSvArray(".bmp", ".png", ".xyz"); - constexpr const auto MUSIC_TYPES = Utils::MakeSvArray( - ".opus", ".oga", ".ogg", ".wav", ".mid", ".midi", ".mp3", ".wma"); - constexpr const auto SOUND_TYPES = Utils::MakeSvArray( - ".opus", ".oga", ".ogg", ".wav", ".mp3", ".wma"); - constexpr const auto FONTS_TYPES = Utils::MakeSvArray(".fon", ".fnt", ".bdf", ".ttf", ".ttc", ".otf", ".woff2", ".woff"); - constexpr const auto TEXT_TYPES = Utils::MakeSvArray(".txt", ".csv", ""); // "" = Complete Filename (incl. extension) provided by the user } FilesystemView FileFinder::Game() { diff --git a/src/filefinder.h b/src/filefinder.h index ab0c688767a..9188212df88 100644 --- a/src/filefinder.h +++ b/src/filefinder.h @@ -37,6 +37,14 @@ * insensitive files paths. */ namespace FileFinder { + constexpr const auto IMG_TYPES = Utils::MakeSvArray(".bmp", ".png", ".xyz"); + constexpr const auto MUSIC_TYPES = Utils::MakeSvArray( + ".opus", ".oga", ".ogg", ".wav", ".mid", ".midi", ".mp3", ".wma"); + constexpr const auto SOUND_TYPES = Utils::MakeSvArray( + ".opus", ".oga", ".ogg", ".wav", ".mp3", ".wma"); + constexpr const auto FONTS_TYPES = Utils::MakeSvArray(".fon", ".fnt", ".bdf", ".ttf", ".ttc", ".otf", ".woff2", ".woff"); + constexpr const auto TEXT_TYPES = Utils::MakeSvArray(".txt", ".csv", ""); // "" = Complete Filename (incl. extension) provided by the user + /** * Quits FileFinder. */