diff --git a/.travis/linux-frozen/docker.sh b/.travis/linux-frozen/docker.sh
index d5031c651..eef05d0b2 100755
--- a/.travis/linux-frozen/docker.sh
+++ b/.travis/linux-frozen/docker.sh
@@ -20,7 +20,7 @@ echo y | sh cmake-3.10.1-Linux-x86_64.sh --prefix=cmake
export PATH=/citra/cmake/cmake-3.10.1-Linux-x86_64/bin:$PATH
mkdir build && cd build
-cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DCITRA_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"}
+cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DCITRA_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON
make -j4
ctest -VV -C Release
diff --git a/.travis/linux/docker.sh b/.travis/linux/docker.sh
index 8d03946cf..703817d9f 100755
--- a/.travis/linux/docker.sh
+++ b/.travis/linux/docker.sh
@@ -11,7 +11,7 @@ echo y | sh cmake-3.10.1-Linux-x86_64.sh --prefix=cmake
export PATH=/citra/cmake/cmake-3.10.1-Linux-x86_64/bin:$PATH
mkdir build && cd build
-cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DENABLE_QT_TRANSLATION=ON -DCITRA_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"}
+cmake .. -DCMAKE_BUILD_TYPE=Release -DCMAKE_C_COMPILER=/usr/lib/ccache/gcc -DCMAKE_CXX_COMPILER=/usr/lib/ccache/g++ -DENABLE_QT_TRANSLATION=ON -DCITRA_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON
make -j4
ctest -VV -C Release
diff --git a/.travis/macos/build.sh b/.travis/macos/build.sh
index ce6445fab..281f6b5be 100755
--- a/.travis/macos/build.sh
+++ b/.travis/macos/build.sh
@@ -7,7 +7,7 @@ export Qt5_DIR=$(brew --prefix)/opt/qt5
export PATH="/usr/local/opt/ccache/libexec:$PATH"
mkdir build && cd build
-cmake .. -DCMAKE_OSX_ARCHITECTURES="x86_64;x86_64h" -DCMAKE_BUILD_TYPE=Release -DENABLE_QT_TRANSLATION=ON -DCITRA_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"}
+cmake .. -DCMAKE_OSX_ARCHITECTURES="x86_64;x86_64h" -DCMAKE_BUILD_TYPE=Release -DENABLE_QT_TRANSLATION=ON -DCITRA_ENABLE_COMPATIBILITY_REPORTING=${ENABLE_COMPATIBILITY_REPORTING:-"OFF"} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON
make -j4
ctest -VV -C Release
diff --git a/CMakeLists.txt b/CMakeLists.txt
index d587e9c1b..9c78b70aa 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -40,6 +40,22 @@ function(check_submodules_present)
endfunction()
check_submodules_present()
+
+configure_file(${CMAKE_SOURCE_DIR}/dist/compatibility_list/compatibility_list.qrc
+ ${CMAKE_BINARY_DIR}/dist/compatibility_list/compatibility_list.qrc
+ COPYONLY)
+
+if (ENABLE_COMPATIBILITY_LIST_DOWNLOAD AND NOT EXISTS ${CMAKE_BINARY_DIR}/dist/compatibility_list/compatibility_list.json)
+ message(STATUS "Downloading compatibility list for citra...")
+ file(DOWNLOAD
+ https://api.citra-emu.org/gamedb/titleid/
+ "${CMAKE_BINARY_DIR}/dist/compatibility_list/compatibility_list.json" SHOW_PROGRESS)
+endif()
+
+if (NOT EXISTS ${CMAKE_BINARY_DIR}/dist/compatibility_list/compatibility_list.json)
+ file(WRITE ${CMAKE_BINARY_DIR}/dist/compatibility_list/compatibility_list.json "")
+endif()
+
# Detect current compilation architecture and create standard definitions
# =======================================================================
diff --git a/appveyor.yml b/appveyor.yml
index aaaaaa769..6a216a380 100644
--- a/appveyor.yml
+++ b/appveyor.yml
@@ -43,9 +43,9 @@ before_build:
$COMPAT = if ($env:ENABLE_COMPATIBILITY_REPORTING -eq $null) {0} else {$env:ENABLE_COMPATIBILITY_REPORTING}
if ($env:BUILD_TYPE -eq 'msvc') {
# redirect stderr and change the exit code to prevent powershell from cancelling the build if cmake prints a warning
- cmd /C 'cmake -G "Visual Studio 15 2017 Win64" -DCITRA_USE_BUNDLED_QT=1 -DCITRA_USE_BUNDLED_SDL2=1 -DCITRA_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} .. 2>&1 && exit 0'
+ cmd /C 'cmake -G "Visual Studio 15 2017 Win64" -DCITRA_USE_BUNDLED_QT=1 -DCITRA_USE_BUNDLED_SDL2=1 -DCITRA_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON .. 2>&1 && exit 0'
} else {
- C:\msys64\usr\bin\bash.exe -lc "cmake -G 'MSYS Makefiles' -DCMAKE_BUILD_TYPE=Release -DENABLE_QT_TRANSLATION=ON -DCITRA_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} .. 2>&1"
+ C:\msys64\usr\bin\bash.exe -lc "cmake -G 'MSYS Makefiles' -DCMAKE_BUILD_TYPE=Release -DENABLE_QT_TRANSLATION=ON -DCITRA_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON .. 2>&1"
}
- cd ..
diff --git a/dist/compatibility_list/compatibility_list.qrc b/dist/compatibility_list/compatibility_list.qrc
new file mode 100644
index 000000000..a29b73598
--- /dev/null
+++ b/dist/compatibility_list/compatibility_list.qrc
@@ -0,0 +1,5 @@
+
+
+ compatibility_list.json
+
+
diff --git a/src/citra_qt/CMakeLists.txt b/src/citra_qt/CMakeLists.txt
index b0fc1acca..4d08a622e 100644
--- a/src/citra_qt/CMakeLists.txt
+++ b/src/citra_qt/CMakeLists.txt
@@ -85,6 +85,9 @@ set(UIS
compatdb.ui
)
+file(GLOB COMPAT_LIST
+ ${CMAKE_BINARY_DIR}/dist/compatibility_list/compatibility_list.qrc
+ ${CMAKE_BINARY_DIR}/dist/compatibility_list/compatibility_list.json)
file(GLOB_RECURSE ICONS ${CMAKE_SOURCE_DIR}/dist/icons/*)
file(GLOB_RECURSE THEMES ${CMAKE_SOURCE_DIR}/dist/qt_themes/*)
@@ -125,6 +128,7 @@ endif()
target_sources(citra-qt
PRIVATE
+ ${COMPAT_LIST}
${ICONS}
${THEMES}
${UI_HDRS}
diff --git a/src/citra_qt/game_list.cpp b/src/citra_qt/game_list.cpp
index cc87f2415..401cd9d98 100644
--- a/src/citra_qt/game_list.cpp
+++ b/src/citra_qt/game_list.cpp
@@ -2,11 +2,14 @@
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
+#include
#include
#include
#include
#include
#include
+#include
+#include
#include
#include
#include
@@ -227,6 +230,7 @@ GameList::GameList(GMainWindow* parent) : QWidget{parent} {
item_model->insertColumns(0, COLUMN_COUNT);
item_model->setHeaderData(COLUMN_NAME, Qt::Horizontal, "Name");
+ item_model->setHeaderData(COLUMN_COMPATIBILITY, Qt::Horizontal, "Compatibility");
item_model->setHeaderData(COLUMN_FILE_TYPE, Qt::Horizontal, "File type");
item_model->setHeaderData(COLUMN_SIZE, Qt::Horizontal, "Size");
@@ -337,6 +341,39 @@ void GameList::PopupContextMenu(const QPoint& menu_location) {
context_menu.exec(tree_view->viewport()->mapToGlobal(menu_location));
}
+void GameList::LoadCompatibilityList() {
+ QFile compat_list{":compatibility_list/compatibility_list.json"};
+
+ if (!compat_list.open(QFile::ReadOnly | QFile::Text)) {
+ NGLOG_ERROR(Frontend, "Unable to open game compatibility list");
+ return;
+ }
+
+ if (compat_list.size() == 0) {
+ NGLOG_ERROR(Frontend, "Game compatibility list is empty");
+ return;
+ }
+
+ const QByteArray content = compat_list.readAll();
+ if (content.isEmpty()) {
+ NGLOG_ERROR(Frontend, "Unable to completely read game compatibility list");
+ return;
+ }
+
+ const QString string_content = content;
+ QJsonDocument json = QJsonDocument::fromJson(string_content.toUtf8());
+ QJsonObject list = json.object();
+ QStringList game_ids = list.keys();
+ for (QString id : game_ids) {
+ QJsonObject game = list[id].toObject();
+
+ if (game.contains("compatibility") && game["compatibility"].isString()) {
+ QString compatibility = game["compatibility"].toString();
+ compatibility_list.insert(std::make_pair(id.toUpper().toStdString(), compatibility));
+ }
+ }
+}
+
void GameList::PopulateAsync(const QString& dir_path, bool deep_scan) {
if (!FileUtil::Exists(dir_path.toStdString()) ||
!FileUtil::IsDirectory(dir_path.toStdString())) {
@@ -351,7 +388,7 @@ void GameList::PopulateAsync(const QString& dir_path, bool deep_scan) {
emit ShouldCancelWorker();
- GameListWorker* worker = new GameListWorker(dir_path, deep_scan);
+ GameListWorker* worker = new GameListWorker(dir_path, deep_scan, compatibility_list);
connect(worker, &GameListWorker::EntryReady, this, &GameList::AddEntry, Qt::QueuedConnection);
connect(worker, &GameListWorker::Finished, this, &GameList::DonePopulating,
@@ -436,8 +473,21 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign
return update_smdh;
}();
+ auto it = std::find_if(compatibility_list.begin(), compatibility_list.end(),
+ [program_id](const std::pair& element) {
+ std::string pid =
+ Common::StringFromFormat("%016" PRIX64, program_id);
+ return element.first == pid;
+ });
+
+ // The game list uses this as compatibility number for untested games
+ QString compatibility("99");
+ if (it != compatibility_list.end())
+ compatibility = it->second;
+
emit EntryReady({
new GameListItemPath(QString::fromStdString(physical_name), smdh, program_id),
+ new GameListItemCompat(compatibility),
new GameListItem(
QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))),
new GameListItemSize(FileUtil::GetSize(physical_name)),
diff --git a/src/citra_qt/game_list.h b/src/citra_qt/game_list.h
index 74773d3d9..c01dc1d21 100644
--- a/src/citra_qt/game_list.h
+++ b/src/citra_qt/game_list.h
@@ -4,6 +4,7 @@
#pragma once
+#include
#include
#include
#include "common/common_types.h"
@@ -29,6 +30,7 @@ class GameList : public QWidget {
public:
enum {
COLUMN_NAME,
+ COLUMN_COMPATIBILITY,
COLUMN_FILE_TYPE,
COLUMN_SIZE,
COLUMN_COUNT, // Number of columns
@@ -68,6 +70,7 @@ public:
void setFilterFocus();
void setFilterVisible(bool visibility);
+ void LoadCompatibilityList();
void PopulateAsync(const QString& dir_path, bool deep_scan);
void SaveInterfaceLayout();
@@ -100,6 +103,7 @@ private:
QStandardItemModel* item_model = nullptr;
GameListWorker* current_worker = nullptr;
QFileSystemWatcher* watcher = nullptr;
+ std::unordered_map compatibility_list;
};
Q_DECLARE_METATYPE(GameListOpenTarget);
diff --git a/src/citra_qt/game_list_p.h b/src/citra_qt/game_list_p.h
index 6cf29be9e..170c77b73 100644
--- a/src/citra_qt/game_list_p.h
+++ b/src/citra_qt/game_list_p.h
@@ -5,11 +5,16 @@
#pragma once
#include
+#include