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