summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdmiral H. Curtiss <pikachu025@gmail.com>2021-10-26 02:01:16 +0200
committerAdmiral H. Curtiss <pikachu025@gmail.com>2021-12-12 21:26:09 +0100
commitda161faff46d9de45b4e80ebf498fc11f85bb493 (patch)
tree8f94fe54b347dd279c3a7d0f939ed1d064f5c80f
parentaa0595589aa10d5c6958b61814628d8c12f3f087 (diff)
GameList: Show game mod descriptor .json files in game list.
-rw-r--r--Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/FileBrowserHelper.java2
-rw-r--r--Source/Core/DiscIO/Blob.cpp2
-rw-r--r--Source/Core/DiscIO/Blob.h1
-rw-r--r--Source/Core/DolphinQt/GameList/GameList.cpp14
-rw-r--r--Source/Core/DolphinQt/GameList/GameTracker.cpp2
-rw-r--r--Source/Core/DolphinQt/MainWindow.cpp6
-rw-r--r--Source/Core/DolphinQt/Settings/PathPane.cpp6
-rw-r--r--Source/Core/UICommon/GameFile.cpp55
-rw-r--r--Source/Core/UICommon/GameFile.h2
-rw-r--r--Source/Core/UICommon/GameFileCache.cpp7
10 files changed, 80 insertions, 17 deletions
diff --git a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/FileBrowserHelper.java b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/FileBrowserHelper.java
index 7132e5d405..848b5c4970 100644
--- a/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/FileBrowserHelper.java
+++ b/Source/Android/app/src/main/java/org/dolphinemu/dolphinemu/utils/FileBrowserHelper.java
@@ -30,7 +30,7 @@ import java.util.Set;
public final class FileBrowserHelper
{
public static final HashSet<String> GAME_EXTENSIONS = new HashSet<>(Arrays.asList(
- "gcm", "tgc", "iso", "ciso", "gcz", "wbfs", "wia", "rvz", "wad", "dol", "elf"));
+ "gcm", "tgc", "iso", "ciso", "gcz", "wbfs", "wia", "rvz", "wad", "dol", "elf", "json"));
public static final HashSet<String> GAME_LIKE_EXTENSIONS = new HashSet<>(GAME_EXTENSIONS);
diff --git a/Source/Core/DiscIO/Blob.cpp b/Source/Core/DiscIO/Blob.cpp
index 4eac308a27..7062c363cd 100644
--- a/Source/Core/DiscIO/Blob.cpp
+++ b/Source/Core/DiscIO/Blob.cpp
@@ -50,6 +50,8 @@ std::string GetName(BlobType blob_type, bool translate)
return "WIA";
case BlobType::RVZ:
return "RVZ";
+ case BlobType::MOD_DESCRIPTOR:
+ return translate_str("Mod");
default:
return "";
}
diff --git a/Source/Core/DiscIO/Blob.h b/Source/Core/DiscIO/Blob.h
index 3d593049f9..0a7cf09664 100644
--- a/Source/Core/DiscIO/Blob.h
+++ b/Source/Core/DiscIO/Blob.h
@@ -39,6 +39,7 @@ enum class BlobType
TGC,
WIA,
RVZ,
+ MOD_DESCRIPTOR,
};
std::string GetName(BlobType blob_type, bool translate);
diff --git a/Source/Core/DolphinQt/GameList/GameList.cpp b/Source/Core/DolphinQt/GameList/GameList.cpp
index 85b09600bb..a8c62fbd2e 100644
--- a/Source/Core/DolphinQt/GameList/GameList.cpp
+++ b/Source/Core/DolphinQt/GameList/GameList.cpp
@@ -352,16 +352,17 @@ void GameList::ShowContextMenu(const QPoint&)
else
{
const auto game = GetSelectedGame();
+ const bool is_mod_descriptor = game->IsModDescriptor();
DiscIO::Platform platform = game->GetPlatform();
menu->addAction(tr("&Properties"), this, &GameList::OpenProperties);
- if (platform != DiscIO::Platform::ELFOrDOL)
+ if (!is_mod_descriptor && platform != DiscIO::Platform::ELFOrDOL)
{
menu->addAction(tr("&Wiki"), this, &GameList::OpenWiki);
}
menu->addSeparator();
- if (DiscIO::IsDisc(platform))
+ if (!is_mod_descriptor && DiscIO::IsDisc(platform))
{
menu->addAction(tr("Start with Riivolution Patches..."), this,
&GameList::StartWithRiivolution);
@@ -382,7 +383,7 @@ void GameList::ShowContextMenu(const QPoint&)
menu->addSeparator();
}
- if (platform == DiscIO::Platform::WiiDisc)
+ if (!is_mod_descriptor && platform == DiscIO::Platform::WiiDisc)
{
auto* perform_disc_update = menu->addAction(tr("Perform System Update"), this,
[this, file_path = game->GetFilePath()] {
@@ -394,7 +395,7 @@ void GameList::ShowContextMenu(const QPoint&)
perform_disc_update->setEnabled(!Core::IsRunning() || !SConfig::GetInstance().bWii);
}
- if (platform == DiscIO::Platform::WiiWAD)
+ if (!is_mod_descriptor && platform == DiscIO::Platform::WiiWAD)
{
QAction* wad_install_action = new QAction(tr("Install to the NAND"), menu);
QAction* wad_uninstall_action = new QAction(tr("Uninstall from the NAND"), menu);
@@ -420,14 +421,15 @@ void GameList::ShowContextMenu(const QPoint&)
menu->addSeparator();
}
- if (platform == DiscIO::Platform::WiiWAD || platform == DiscIO::Platform::WiiDisc)
+ if (!is_mod_descriptor &&
+ (platform == DiscIO::Platform::WiiWAD || platform == DiscIO::Platform::WiiDisc))
{
menu->addAction(tr("Open Wii &Save Folder"), this, &GameList::OpenWiiSaveFolder);
menu->addAction(tr("Export Wii Save"), this, &GameList::ExportWiiSave);
menu->addSeparator();
}
- if (platform == DiscIO::Platform::GameCubeDisc)
+ if (!is_mod_descriptor && platform == DiscIO::Platform::GameCubeDisc)
{
menu->addAction(tr("Open GameCube &Save Folder"), this, &GameList::OpenGCSaveFolder);
menu->addSeparator();
diff --git a/Source/Core/DolphinQt/GameList/GameTracker.cpp b/Source/Core/DolphinQt/GameList/GameTracker.cpp
index 161d6df419..b783cc0ab3 100644
--- a/Source/Core/DolphinQt/GameList/GameTracker.cpp
+++ b/Source/Core/DolphinQt/GameList/GameTracker.cpp
@@ -27,7 +27,7 @@ static const QStringList game_filters{
QStringLiteral("*.[gG][cC][zZ]"), QStringLiteral("*.[wW][bB][fF][sS]"),
QStringLiteral("*.[wW][iI][aA]"), QStringLiteral("*.[rR][vV][zZ]"),
QStringLiteral("*.[wW][aA][dD]"), QStringLiteral("*.[eE][lL][fF]"),
- QStringLiteral("*.[dD][oO][lL]")};
+ QStringLiteral("*.[dD][oO][lL]"), QStringLiteral("*.[jJ][sS][oO][nN]")};
GameTracker::GameTracker(QObject* parent) : QFileSystemWatcher(parent)
{
diff --git a/Source/Core/DolphinQt/MainWindow.cpp b/Source/Core/DolphinQt/MainWindow.cpp
index b0bb587e7e..778fcce6ce 100644
--- a/Source/Core/DolphinQt/MainWindow.cpp
+++ b/Source/Core/DolphinQt/MainWindow.cpp
@@ -733,8 +733,10 @@ QStringList MainWindow::PromptFileNames()
QStringList paths = DolphinFileDialog::getOpenFileNames(
this, tr("Select a File"),
settings.value(QStringLiteral("mainwindow/lastdir"), QString{}).toString(),
- tr("All GC/Wii files (*.elf *.dol *.gcm *.iso *.tgc *.wbfs *.ciso *.gcz *.wia *.rvz *.wad "
- "*.dff *.m3u);;All Files (*)"));
+ QStringLiteral("%1 (*.elf *.dol *.gcm *.iso *.tgc *.wbfs *.ciso *.gcz *.wia *.rvz *.wad "
+ "*.dff *.m3u *.json);;%2 (*)")
+ .arg(tr("All GC/Wii files"))
+ .arg(tr("All Files")));
if (!paths.isEmpty())
{
diff --git a/Source/Core/DolphinQt/Settings/PathPane.cpp b/Source/Core/DolphinQt/Settings/PathPane.cpp
index 41fe993f36..3f1bf93e28 100644
--- a/Source/Core/DolphinQt/Settings/PathPane.cpp
+++ b/Source/Core/DolphinQt/Settings/PathPane.cpp
@@ -44,8 +44,10 @@ void PathPane::BrowseDefaultGame()
{
QString file = QDir::toNativeSeparators(DolphinFileDialog::getOpenFileName(
this, tr("Select a Game"), Settings::Instance().GetDefaultGame(),
- tr("All GC/Wii files (*.elf *.dol *.gcm *.iso *.tgc *.wbfs "
- "*.ciso *.gcz *.wia *.rvz *.wad *.m3u);;All Files (*)")));
+ QStringLiteral("%1 (*.elf *.dol *.gcm *.iso *.tgc *.wbfs *.ciso *.gcz *.wia *.rvz *.wad "
+ "*.m3u *.json);;%2 (*)")
+ .arg(tr("All GC/Wii files"))
+ .arg(tr("All Files"))));
if (!file.isEmpty())
Settings::Instance().SetDefaultGame(file);
diff --git a/Source/Core/UICommon/GameFile.cpp b/Source/Core/UICommon/GameFile.cpp
index 367ea65642..3417051a54 100644
--- a/Source/Core/UICommon/GameFile.cpp
+++ b/Source/Core/UICommon/GameFile.cpp
@@ -43,6 +43,7 @@
#include "DiscIO/Blob.h"
#include "DiscIO/DiscExtractor.h"
#include "DiscIO/Enums.h"
+#include "DiscIO/GameModDescriptor.h"
#include "DiscIO/Volume.h"
#include "DiscIO/WiiSaveBanner.h"
@@ -163,6 +164,32 @@ GameFile::GameFile(std::string path) : m_file_path(std::move(path))
m_platform = DiscIO::Platform::ELFOrDOL;
m_blob_type = DiscIO::BlobType::DIRECTORY;
}
+
+ if (!IsValid() && GetExtension() == ".json")
+ {
+ auto descriptor = DiscIO::ParseGameModDescriptorFile(m_file_path);
+ if (descriptor)
+ {
+ GameFile proxy(descriptor->base_file);
+ if (proxy.IsValid())
+ {
+ m_valid = true;
+ m_file_size = File::GetSize(m_file_path);
+ m_long_names.emplace(DiscIO::Language::English, std::move(descriptor->display_name));
+ m_internal_name = proxy.GetInternalName();
+ m_game_id = proxy.GetGameID();
+ m_gametdb_id = proxy.GetGameTDBID();
+ m_title_id = proxy.GetTitleID();
+ m_maker_id = proxy.GetMakerID();
+ m_region = proxy.GetRegion();
+ m_country = proxy.GetCountry();
+ m_platform = proxy.GetPlatform();
+ m_revision = proxy.GetRevision();
+ m_disc_number = proxy.GetDiscNumber();
+ m_blob_type = DiscIO::BlobType::MOD_DESCRIPTOR;
+ }
+ }
+ }
}
GameFile::~GameFile() = default;
@@ -470,6 +497,18 @@ bool GameFile::ReadPNGBanner(const std::string& path)
return true;
}
+bool GameFile::TryLoadGameModDescriptorBanner()
+{
+ if (m_blob_type != DiscIO::BlobType::MOD_DESCRIPTOR)
+ return false;
+
+ auto descriptor = DiscIO::ParseGameModDescriptorFile(m_file_path);
+ if (!descriptor)
+ return false;
+
+ return ReadPNGBanner(descriptor->banner);
+}
+
bool GameFile::CustomBannerChanged()
{
std::string path, name;
@@ -482,8 +521,12 @@ bool GameFile::CustomBannerChanged()
// Homebrew Channel icon naming. Typical for DOLs and ELFs, but we also support it for volumes.
if (!ReadPNGBanner(path + "icon.png"))
{
- // If no custom icon is found, go back to the non-custom one.
- m_pending.custom_banner = {};
+ // If it's a game mod descriptor file, it may specify its own custom banner.
+ if (!TryLoadGameModDescriptorBanner())
+ {
+ // If no custom icon is found, go back to the non-custom one.
+ m_pending.custom_banner = {};
+ }
}
}
@@ -499,6 +542,8 @@ const std::string& GameFile::GetName(const Core::TitleDatabase& title_database)
{
if (!m_custom_name.empty())
return m_custom_name;
+ if (IsModDescriptor())
+ return GetName(Variant::LongAndPossiblyCustom);
const std::string& database_name = title_database.GetTitleName(m_gametdb_id, GetConfigLanguage());
return database_name.empty() ? GetName(Variant::LongAndPossiblyCustom) : database_name;
@@ -652,6 +697,7 @@ bool GameFile::ShouldShowFileFormatDetails() const
case DiscIO::BlobType::PLAIN:
break;
case DiscIO::BlobType::DRIVE:
+ case DiscIO::BlobType::MOD_DESCRIPTOR:
return false;
default:
return true;
@@ -699,6 +745,11 @@ bool GameFile::ShouldAllowConversion() const
return DiscIO::IsDisc(m_platform) && m_volume_size_is_accurate;
}
+bool GameFile::IsModDescriptor() const
+{
+ return m_blob_type == DiscIO::BlobType::MOD_DESCRIPTOR;
+}
+
const GameBanner& GameFile::GetBannerImage() const
{
return m_custom_banner.empty() ? m_volume_banner : m_custom_banner;
diff --git a/Source/Core/UICommon/GameFile.h b/Source/Core/UICommon/GameFile.h
index fc981cd226..eb1151a28a 100644
--- a/Source/Core/UICommon/GameFile.h
+++ b/Source/Core/UICommon/GameFile.h
@@ -107,6 +107,7 @@ public:
bool IsVolumeSizeAccurate() const { return m_volume_size_is_accurate; }
bool IsDatelDisc() const { return m_is_datel_disc; }
bool IsNKit() const { return m_is_nkit; }
+ bool IsModDescriptor() const;
const GameBanner& GetBannerImage() const;
const GameCover& GetCoverImage() const;
void DoState(PointerWrap& p);
@@ -132,6 +133,7 @@ private:
bool IsElfOrDol() const;
bool ReadXMLMetadata(const std::string& path);
bool ReadPNGBanner(const std::string& path);
+ bool TryLoadGameModDescriptorBanner();
// IMPORTANT: Nearly all data members must be save/restored in DoState.
// If anything is changed, make sure DoState handles it properly and
diff --git a/Source/Core/UICommon/GameFileCache.cpp b/Source/Core/UICommon/GameFileCache.cpp
index a1b55b3614..1040c24b2f 100644
--- a/Source/Core/UICommon/GameFileCache.cpp
+++ b/Source/Core/UICommon/GameFileCache.cpp
@@ -27,13 +27,14 @@
namespace UICommon
{
-static constexpr u32 CACHE_REVISION = 20; // Last changed in PR 9461
+static constexpr u32 CACHE_REVISION = 21; // Last changed in PR 10187
std::vector<std::string> FindAllGamePaths(const std::vector<std::string>& directories_to_scan,
bool recursive_scan)
{
- static const std::vector<std::string> search_extensions = {
- ".gcm", ".tgc", ".iso", ".ciso", ".gcz", ".wbfs", ".wia", ".rvz", ".wad", ".dol", ".elf"};
+ static const std::vector<std::string> search_extensions = {".gcm", ".tgc", ".iso", ".ciso",
+ ".gcz", ".wbfs", ".wia", ".rvz",
+ ".wad", ".dol", ".elf", ".json"};
// TODO: We could process paths iteratively as they are found
return Common::DoFileSearch(directories_to_scan, search_extensions, recursive_scan);