Merge pull request #10691 from t895/nro-check
android: Add proper homebrew check
This commit is contained in:
commit
f759ff3a5c
|
@ -223,6 +223,8 @@ object NativeLibrary {
|
|||
|
||||
external fun getCompany(filename: String): String
|
||||
|
||||
external fun isHomebrew(filename: String): Boolean
|
||||
|
||||
external fun setAppDirectory(directory: String)
|
||||
|
||||
external fun initializeGpuDriver(
|
||||
|
|
|
@ -127,13 +127,7 @@ class SearchFragment : Fragment() {
|
|||
}
|
||||
}
|
||||
|
||||
R.id.chip_homebrew -> {
|
||||
baseList.filter {
|
||||
Log.error("Guh - ${it.path}")
|
||||
FileUtil.hasExtension(it.path, "nro")
|
||||
|| FileUtil.hasExtension(it.path, "nso")
|
||||
}
|
||||
}
|
||||
R.id.chip_homebrew -> baseList.filter { it.isHomebrew }
|
||||
|
||||
R.id.chip_retail -> baseList.filter {
|
||||
FileUtil.hasExtension(it.path, "xci")
|
||||
|
|
|
@ -16,7 +16,8 @@ class Game(
|
|||
val regions: String,
|
||||
val path: String,
|
||||
val gameId: String,
|
||||
val company: String
|
||||
val company: String,
|
||||
val isHomebrew: Boolean
|
||||
) : Parcelable {
|
||||
val keyAddedToLibraryTime get() = "${gameId}_AddedToLibraryTime"
|
||||
val keyLastPlayedTime get() = "${gameId}_LastPlayed"
|
||||
|
@ -31,6 +32,7 @@ class Game(
|
|||
&& path == other.path
|
||||
&& gameId == other.gameId
|
||||
&& company == other.company
|
||||
&& isHomebrew == other.isHomebrew
|
||||
}
|
||||
|
||||
companion object {
|
||||
|
|
|
@ -13,6 +13,8 @@ import androidx.preference.PreferenceManager
|
|||
import kotlinx.coroutines.Dispatchers
|
||||
import kotlinx.coroutines.launch
|
||||
import kotlinx.coroutines.withContext
|
||||
import kotlinx.serialization.ExperimentalSerializationApi
|
||||
import kotlinx.serialization.MissingFieldException
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.yuzu.yuzu_emu.NativeLibrary
|
||||
|
@ -20,6 +22,7 @@ import org.yuzu.yuzu_emu.YuzuApplication
|
|||
import org.yuzu.yuzu_emu.utils.GameHelper
|
||||
import java.util.Locale
|
||||
|
||||
@OptIn(ExperimentalSerializationApi::class)
|
||||
class GamesViewModel : ViewModel() {
|
||||
private val _games = MutableLiveData<List<Game>>(emptyList())
|
||||
val games: LiveData<List<Game>> get() = _games
|
||||
|
@ -49,7 +52,13 @@ class GamesViewModel : ViewModel() {
|
|||
if (storedGames!!.isNotEmpty()) {
|
||||
val deserializedGames = mutableSetOf<Game>()
|
||||
storedGames.forEach {
|
||||
val game: Game = Json.decodeFromString(it)
|
||||
val game: Game
|
||||
try {
|
||||
game = Json.decodeFromString(it)
|
||||
} catch (e: MissingFieldException) {
|
||||
return@forEach
|
||||
}
|
||||
|
||||
val gameExists =
|
||||
DocumentFile.fromSingleUri(YuzuApplication.appContext, Uri.parse(game.path))
|
||||
?.exists()
|
||||
|
|
|
@ -6,7 +6,6 @@ package org.yuzu.yuzu_emu.utils
|
|||
import android.content.SharedPreferences
|
||||
import android.net.Uri
|
||||
import androidx.preference.PreferenceManager
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.encodeToString
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.yuzu.yuzu_emu.NativeLibrary
|
||||
|
@ -83,7 +82,8 @@ object GameHelper {
|
|||
NativeLibrary.getRegions(filePath),
|
||||
filePath,
|
||||
gameId,
|
||||
NativeLibrary.getCompany(filePath)
|
||||
NativeLibrary.getCompany(filePath),
|
||||
NativeLibrary.isHomebrew(filePath)
|
||||
)
|
||||
|
||||
val addedTime = preferences.getLong(newGame.keyAddedToLibraryTime, 0L)
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
|
||||
#include <android/api-level.h>
|
||||
#include <android/native_window_jni.h>
|
||||
#include <core/loader/nro.h>
|
||||
|
||||
#include "common/detached_tasks.h"
|
||||
#include "common/dynamic_library.h"
|
||||
|
@ -281,6 +282,10 @@ public:
|
|||
return GetRomMetadata(path).icon;
|
||||
}
|
||||
|
||||
bool GetIsHomebrew(const std::string& path) {
|
||||
return GetRomMetadata(path).isHomebrew;
|
||||
}
|
||||
|
||||
void ResetRomMetadata() {
|
||||
m_rom_metadata_cache.clear();
|
||||
}
|
||||
|
@ -348,6 +353,7 @@ private:
|
|||
struct RomMetadata {
|
||||
std::string title;
|
||||
std::vector<u8> icon;
|
||||
bool isHomebrew;
|
||||
};
|
||||
|
||||
RomMetadata GetRomMetadata(const std::string& path) {
|
||||
|
@ -360,11 +366,17 @@ private:
|
|||
|
||||
RomMetadata CacheRomMetadata(const std::string& path) {
|
||||
const auto file = Core::GetGameFileFromPath(m_vfs, path);
|
||||
const auto loader = Loader::GetLoader(EmulationSession::GetInstance().System(), file, 0, 0);
|
||||
auto loader = Loader::GetLoader(EmulationSession::GetInstance().System(), file, 0, 0);
|
||||
|
||||
RomMetadata entry;
|
||||
loader->ReadTitle(entry.title);
|
||||
loader->ReadIcon(entry.icon);
|
||||
if (loader->GetFileType() == Loader::FileType::NRO) {
|
||||
auto loader_nro = dynamic_cast<Loader::AppLoader_NRO*>(loader.get());
|
||||
entry.isHomebrew = loader_nro->IsHomebrew();
|
||||
} else {
|
||||
entry.isHomebrew = false;
|
||||
}
|
||||
|
||||
m_rom_metadata_cache[path] = entry;
|
||||
|
||||
|
@ -662,6 +674,12 @@ jstring Java_org_yuzu_yuzu_1emu_NativeLibrary_getCompany([[maybe_unused]] JNIEnv
|
|||
return env->NewStringUTF("");
|
||||
}
|
||||
|
||||
jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_isHomebrew([[maybe_unused]] JNIEnv* env,
|
||||
[[maybe_unused]] jclass clazz,
|
||||
[[maybe_unused]] jstring j_filename) {
|
||||
return EmulationSession::GetInstance().GetIsHomebrew(GetJString(env, j_filename));
|
||||
}
|
||||
|
||||
void Java_org_yuzu_yuzu_1emu_NativeLibrary_initializeEmulation
|
||||
[[maybe_unused]] (JNIEnv* env, [[maybe_unused]] jclass clazz) {
|
||||
// Create the default config.ini.
|
||||
|
|
|
@ -33,7 +33,8 @@ static_assert(sizeof(NroSegmentHeader) == 0x8, "NroSegmentHeader has incorrect s
|
|||
struct NroHeader {
|
||||
INSERT_PADDING_BYTES(0x4);
|
||||
u32_le module_header_offset;
|
||||
INSERT_PADDING_BYTES(0x8);
|
||||
u32 magic_ext1;
|
||||
u32 magic_ext2;
|
||||
u32_le magic;
|
||||
INSERT_PADDING_BYTES(0x4);
|
||||
u32_le file_size;
|
||||
|
@ -124,6 +125,16 @@ FileType AppLoader_NRO::IdentifyType(const FileSys::VirtualFile& nro_file) {
|
|||
return FileType::Error;
|
||||
}
|
||||
|
||||
bool AppLoader_NRO::IsHomebrew() {
|
||||
// Read NSO header
|
||||
NroHeader nro_header{};
|
||||
if (sizeof(NroHeader) != file->ReadObject(&nro_header)) {
|
||||
return false;
|
||||
}
|
||||
return nro_header.magic_ext1 == Common::MakeMagic('H', 'O', 'M', 'E') &&
|
||||
nro_header.magic_ext2 == Common::MakeMagic('B', 'R', 'E', 'W');
|
||||
}
|
||||
|
||||
static constexpr u32 PageAlignSize(u32 size) {
|
||||
return static_cast<u32>((size + Core::Memory::YUZU_PAGEMASK) & ~Core::Memory::YUZU_PAGEMASK);
|
||||
}
|
||||
|
|
|
@ -38,6 +38,8 @@ public:
|
|||
*/
|
||||
static FileType IdentifyType(const FileSys::VirtualFile& nro_file);
|
||||
|
||||
bool IsHomebrew();
|
||||
|
||||
FileType GetFileType() const override {
|
||||
return IdentifyType(file);
|
||||
}
|
||||
|
|
Reference in New Issue