Skip to content
Permalink
Browse files
Merge pull request #5927 from spycrab/qt_gamelist_cache
Qt: Implement gamelist caching
  • Loading branch information
JosJuice committed Sep 5, 2017
2 parents 3e47baa + b9c5a2a commit b96e4a2
Show file tree
Hide file tree
Showing 8 changed files with 257 additions and 55 deletions.
@@ -59,6 +59,7 @@ set(SRCS
Config/Mapping/WiimoteEmuMotionControl.cpp
Config/PropertiesDialog.cpp
Config/SettingsWindow.cpp
GameList/GameFileCache.cpp
GameList/GameFile.cpp
GameList/GameList.cpp
GameList/GameListModel.cpp
@@ -188,6 +188,7 @@
<ClCompile Include="Config\PropertiesDialog.cpp" />
<ClCompile Include="Config\SettingsWindow.cpp" />
<ClCompile Include="GameList\GameFile.cpp" />
<ClCompile Include="GameList\GameFileCache.cpp" />
<ClCompile Include="GameList\GameList.cpp" />
<ClCompile Include="GameList\GameListModel.cpp" />
<ClCompile Include="GameList\GameTracker.cpp" />
@@ -236,6 +237,7 @@
<ClInclude Include="Config\Mapping\WiimoteEmuExtension.h" />
<ClInclude Include="Config\Mapping\WiimoteEmuGeneral.h" />
<ClInclude Include="Config\Mapping\WiimoteEmuMotionControl.h" />
<ClInclude Include="GameList\GameFileCache.h" />
<ClInclude Include="QtUtils\BlockUserInputFilter.h" />
<ClInclude Include="QtUtils\ElidedButton.h" />
<ClInclude Include="QtUtils\ListTabWidget.h" />
@@ -2,8 +2,6 @@
// Licensed under GPLv2+
// Refer to the license.txt file included.

#include <QCryptographicHash>
#include <QDataStream>
#include <QDir>
#include <QFileInfo>
#include <QImage>
@@ -26,9 +24,6 @@
#include "DolphinQt2/Resources.h"
#include "DolphinQt2/Settings.h"

static const int CACHE_VERSION = 13; // Last changed in PR #3261
static const int DATASTREAM_VERSION = QDataStream::Qt_5_5;

QList<DiscIO::Language> GameFile::GetAvailableLanguages() const
{
return m_long_names.keys();
@@ -43,23 +38,25 @@ ConvertLanguageMap(const std::map<DiscIO::Language, std::string>& map)
return result;
}

GameFile::GameFile()
{
m_valid = false;
}

GameFile::GameFile(const QString& path) : m_path(path)
{
m_valid = false;

if (!LoadFileInfo(path))
return;

if (!TryLoadCache())
if (TryLoadVolume())
{
if (TryLoadVolume())
{
LoadState();
}
else if (!TryLoadElfDol())
{
return;
}
LoadState();
}
else if (!TryLoadElfDol())
{
return;
}

m_valid = true;
@@ -76,16 +73,6 @@ bool GameFile::IsValid() const
return true;
}

QString GameFile::GetCacheFileName() const
{
QString folder = QString::fromStdString(File::GetUserPath(D_CACHE_IDX));
// Append a hash of the full path to prevent name clashes between
// files with the same names in different folders.
QString hash =
QString::fromUtf8(QCryptographicHash::hash(m_path.toUtf8(), QCryptographicHash::Md5).toHex());
return folder + GetFileName() + hash;
}

void GameFile::ReadBanner(const DiscIO::Volume& volume)
{
int width, height;
@@ -129,27 +116,6 @@ bool GameFile::IsElfOrDol()
return extension == QStringLiteral("elf") || extension == QStringLiteral("dol");
}

bool GameFile::TryLoadCache()
{
QFile cache(GetCacheFileName());
if (!cache.exists())
return false;
if (!cache.open(QIODevice::ReadOnly))
return false;
if (QFileInfo(cache).lastModified() < m_last_modified)
return false;

QDataStream in(&cache);
in.setVersion(DATASTREAM_VERSION);

int cache_version;
in >> cache_version;
if (cache_version != CACHE_VERSION)
return false;

return false;
}

bool GameFile::TryLoadVolume()
{
QSharedPointer<DiscIO::Volume> volume(
@@ -179,7 +145,6 @@ bool GameFile::TryLoadVolume()

ReadBanner(*volume);

SaveCache();
return true;
}

@@ -199,11 +164,6 @@ bool GameFile::TryLoadElfDol()
return true;
}

void GameFile::SaveCache()
{
// TODO
}

QString GameFile::GetFileName() const
{
return QFileInfo(m_path).fileName();
@@ -427,3 +387,96 @@ QString FormatSize(qint64 size)
}
return QStringLiteral("%1 %2").arg(QString::number(num, 'f', 1)).arg(unit);
}

template <typename T, typename U = std::enable_if_t<std::is_enum<T>::value>>
QDataStream& operator<<(QDataStream& out, const T& enum_value)
{
out << static_cast<std::underlying_type_t<T>>(enum_value);
return out;
}

template <typename T, typename U = std::enable_if_t<std::is_enum<T>::value>>
QDataStream& operator>>(QDataStream& in, T& enum_value)
{
std::underlying_type_t<T> tmp;
in >> tmp;
enum_value = static_cast<T>(tmp);
return in;
}

// Some C++ implementations define uint64_t as an 'unsigned long', but QDataStream only has built-in
// overloads for quint64, which is an 'unsigned long long' on Unix
QDataStream& operator<<(QDataStream& out, const unsigned long& integer)
{
out << static_cast<quint64>(integer);
return out;
}
QDataStream& operator>>(QDataStream& in, unsigned long& integer)
{
quint64 tmp;
in >> tmp;
integer = static_cast<unsigned long>(tmp);
return in;
}

QDataStream& operator<<(QDataStream& out, const GameFile& file)
{
out << file.m_last_modified;
out << file.m_path;
out << file.m_title_id;
out << file.m_game_id;
out << file.m_maker_id;
out << file.m_maker;
out << file.m_long_makers;
out << file.m_short_makers;
out << file.m_internal_name;
out << file.m_long_names;
out << file.m_short_names;
out << file.m_platform;
out << file.m_region;
out << file.m_country;
out << file.m_blob_type;
out << file.m_size;
out << file.m_raw_size;
out << file.m_descriptions;
out << file.m_revision;
out << file.m_disc_number;
out << file.m_issues;
out << file.m_rating;
out << file.m_apploader_date;
out << file.m_banner;

return out;
}

QDataStream& operator>>(QDataStream& in, GameFile& file)
{
in >> file.m_last_modified;
in >> file.m_path;
in >> file.m_title_id;
in >> file.m_game_id;
in >> file.m_maker_id;
in >> file.m_maker;
in >> file.m_long_makers;
in >> file.m_short_makers;
in >> file.m_internal_name;
in >> file.m_long_names;
in >> file.m_short_names;
in >> file.m_platform;
in >> file.m_region;
in >> file.m_country;
in >> file.m_blob_type;
in >> file.m_size;
in >> file.m_raw_size;
in >> file.m_descriptions;
in >> file.m_revision;
in >> file.m_disc_number;
in >> file.m_issues;
in >> file.m_rating;
in >> file.m_apploader_date;
in >> file.m_banner;

file.m_valid = true;

return in;
}
@@ -5,6 +5,7 @@
#pragma once

#include <QDateTime>
#include <QFile>
#include <QMap>
#include <QPixmap>
#include <QString>
@@ -21,10 +22,10 @@ enum class Platform;
class Volume;
}

// TODO cache
class GameFile final
{
public:
GameFile();
explicit GameFile(const QString& path);

bool IsValid() const;
@@ -34,6 +35,7 @@ class GameFile final
QString GetFileExtension() const;
QString GetFileFolder() const;
qint64 GetFileSize() const { return m_size; }
QDateTime GetLastModified() const { return m_last_modified; }
// The rest will not.
QString GetGameID() const { return m_game_id; }
QString GetMakerID() const { return m_maker_id; }
@@ -73,18 +75,18 @@ class GameFile final
bool Uninstall();
bool ExportWiiSave();

friend QDataStream& operator<<(QDataStream& out, const GameFile& file);
friend QDataStream& operator>>(QDataStream& in, GameFile& file);

private:
QString GetBannerString(const QMap<DiscIO::Language, QString>& m) const;

QString GetCacheFileName() const;
void ReadBanner(const DiscIO::Volume& volume);
bool LoadFileInfo(const QString& path);
void LoadState();
bool IsElfOrDol();
bool TryLoadElfDol();
bool TryLoadCache();
bool TryLoadVolume();
void SaveCache();

bool m_valid;
QString m_path;
@@ -115,3 +117,9 @@ class GameFile final
};

QString FormatSize(qint64 size);

QDataStream& operator<<(QDataStream& out, const GameFile& file);
QDataStream& operator>>(QDataStream& in, GameFile& file);

QDataStream& operator<<(QDataStream& out, const unsigned long& file);
QDataStream& operator>>(QDataStream& in, unsigned long& file);
@@ -0,0 +1,87 @@
// Copyright 2017 Dolphin Emulator Project
// Licensed under GPLv2+
// Refer to the license.txt file included.

#include "GameFileCache.h"

#include <QDataStream>
#include <QDir>
#include <QFileInfo>

#include "Common/FileUtil.h"
#include "Core/ConfigManager.h"
#include "DolphinQt2/Settings.h"

static const int CACHE_VERSION = 1; // Last changed in PR #5927
static const int DATASTREAM_VERSION = QDataStream::Qt_5_0;

GameFileCache::GameFileCache()
: m_path(QString::fromStdString(File::GetUserPath(D_CACHE_IDX) + "qt_gamefile.cache"))
{
}

bool GameFileCache::IsCached(const QString& path)
{
std::lock_guard<std::mutex> guard(m_mutex);

return m_gamefiles.contains(path);
}

GameFile GameFileCache::GetFile(const QString& path)
{
std::lock_guard<std::mutex> guard(m_mutex);

return m_gamefiles[path];
}

void GameFileCache::Load()
{
std::lock_guard<std::mutex> guard(m_mutex);

QFile file(m_path);

if (!file.open(QIODevice::ReadOnly))
return;

QDataStream stream(&file);
stream.setVersion(DATASTREAM_VERSION);

qint32 cache_version;
stream >> cache_version;

// If the cache file is using an older version, ignore it and create it from scratch
if (cache_version != CACHE_VERSION)
return;

stream >> m_gamefiles;
}

void GameFileCache::Save()
{
std::lock_guard<std::mutex> guard(m_mutex);

QFile file(m_path);

if (!file.open(QIODevice::WriteOnly))
return;

QDataStream stream(&file);
stream.setVersion(DATASTREAM_VERSION);

stream << static_cast<qint32>(CACHE_VERSION);
stream << m_gamefiles;
}

void GameFileCache::Update(const GameFile& gamefile)
{
std::lock_guard<std::mutex> guard(m_mutex);

m_gamefiles[gamefile.GetFilePath()] = gamefile;
}

QList<QString> GameFileCache::GetCached()
{
std::lock_guard<std::mutex> guard(m_mutex);

return m_gamefiles.keys();
}

0 comments on commit b96e4a2

Please sign in to comment.