mirror of
https://github.com/PrismLauncher/PrismLauncher.git
synced 2025-04-29 22:24:26 +02:00
fix: load world size async (#3651)
This commit is contained in:
commit
e9245716f7
@ -198,22 +198,6 @@ bool putLevelDatDataToFS(const QFileInfo& file, QByteArray& data)
|
||||
return f.commit();
|
||||
}
|
||||
|
||||
int64_t calculateWorldSize(const QFileInfo& file)
|
||||
{
|
||||
if (file.isFile() && file.suffix() == "zip") {
|
||||
return file.size();
|
||||
} else if (file.isDir()) {
|
||||
QDirIterator it(file.absoluteFilePath(), QDir::Files, QDirIterator::Subdirectories);
|
||||
int64_t total = 0;
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
total += it.fileInfo().size();
|
||||
}
|
||||
return total;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
World::World(const QFileInfo& file)
|
||||
{
|
||||
repath(file);
|
||||
@ -223,7 +207,6 @@ void World::repath(const QFileInfo& file)
|
||||
{
|
||||
m_containerFile = file;
|
||||
m_folderName = file.fileName();
|
||||
m_size = calculateWorldSize(file);
|
||||
if (file.isFile() && file.suffix() == "zip") {
|
||||
m_iconFile = QString();
|
||||
readFromZip(file);
|
||||
@ -252,41 +235,41 @@ void World::readFromFS(const QFileInfo& file)
|
||||
{
|
||||
auto bytes = getLevelDatDataFromFS(file);
|
||||
if (bytes.isEmpty()) {
|
||||
is_valid = false;
|
||||
m_isValid = false;
|
||||
return;
|
||||
}
|
||||
loadFromLevelDat(bytes);
|
||||
levelDatTime = file.lastModified();
|
||||
m_levelDatTime = file.lastModified();
|
||||
}
|
||||
|
||||
void World::readFromZip(const QFileInfo& file)
|
||||
{
|
||||
QuaZip zip(file.absoluteFilePath());
|
||||
is_valid = zip.open(QuaZip::mdUnzip);
|
||||
if (!is_valid) {
|
||||
m_isValid = zip.open(QuaZip::mdUnzip);
|
||||
if (!m_isValid) {
|
||||
return;
|
||||
}
|
||||
auto location = MMCZip::findFolderOfFileInZip(&zip, "level.dat");
|
||||
is_valid = !location.isEmpty();
|
||||
if (!is_valid) {
|
||||
m_isValid = !location.isEmpty();
|
||||
if (!m_isValid) {
|
||||
return;
|
||||
}
|
||||
m_containerOffsetPath = location;
|
||||
QuaZipFile zippedFile(&zip);
|
||||
// read the install profile
|
||||
is_valid = zip.setCurrentFile(location + "level.dat");
|
||||
if (!is_valid) {
|
||||
m_isValid = zip.setCurrentFile(location + "level.dat");
|
||||
if (!m_isValid) {
|
||||
return;
|
||||
}
|
||||
is_valid = zippedFile.open(QIODevice::ReadOnly);
|
||||
m_isValid = zippedFile.open(QIODevice::ReadOnly);
|
||||
QuaZipFileInfo64 levelDatInfo;
|
||||
zippedFile.getFileInfo(&levelDatInfo);
|
||||
auto modTime = levelDatInfo.getNTFSmTime();
|
||||
if (!modTime.isValid()) {
|
||||
modTime = levelDatInfo.dateTime;
|
||||
}
|
||||
levelDatTime = modTime;
|
||||
if (!is_valid) {
|
||||
m_levelDatTime = modTime;
|
||||
if (!m_isValid) {
|
||||
return;
|
||||
}
|
||||
loadFromLevelDat(zippedFile.readAll());
|
||||
@ -430,7 +413,7 @@ void World::loadFromLevelDat(QByteArray data)
|
||||
{
|
||||
auto levelData = parseLevelDat(data);
|
||||
if (!levelData) {
|
||||
is_valid = false;
|
||||
m_isValid = false;
|
||||
return;
|
||||
}
|
||||
|
||||
@ -439,20 +422,20 @@ void World::loadFromLevelDat(QByteArray data)
|
||||
valPtr = &levelData->at("Data");
|
||||
} catch (const std::out_of_range& e) {
|
||||
qWarning() << "Unable to read NBT tags from " << m_folderName << ":" << e.what();
|
||||
is_valid = false;
|
||||
m_isValid = false;
|
||||
return;
|
||||
}
|
||||
nbt::value& val = *valPtr;
|
||||
|
||||
is_valid = val.get_type() == nbt::tag_type::Compound;
|
||||
if (!is_valid)
|
||||
m_isValid = val.get_type() == nbt::tag_type::Compound;
|
||||
if (!m_isValid)
|
||||
return;
|
||||
|
||||
auto name = read_string(val, "LevelName");
|
||||
m_actualName = name ? *name : m_folderName;
|
||||
|
||||
auto timestamp = read_long(val, "LastPlayed");
|
||||
m_lastPlayed = timestamp ? QDateTime::fromMSecsSinceEpoch(*timestamp) : levelDatTime;
|
||||
m_lastPlayed = timestamp ? QDateTime::fromMSecsSinceEpoch(*timestamp) : m_levelDatTime;
|
||||
|
||||
m_gameType = read_gametype(val, "GameType");
|
||||
|
||||
@ -490,7 +473,7 @@ bool World::replace(World& with)
|
||||
|
||||
bool World::destroy()
|
||||
{
|
||||
if (!is_valid)
|
||||
if (!m_isValid)
|
||||
return false;
|
||||
|
||||
if (FS::trash(m_containerFile.filePath()))
|
||||
@ -508,7 +491,7 @@ bool World::destroy()
|
||||
|
||||
bool World::operator==(const World& other) const
|
||||
{
|
||||
return is_valid == other.is_valid && folderName() == other.folderName();
|
||||
return m_isValid == other.m_isValid && folderName() == other.folderName();
|
||||
}
|
||||
|
||||
bool World::isSymLinkUnder(const QString& instPath) const
|
||||
@ -531,3 +514,8 @@ bool World::isMoreThanOneHardLink() const
|
||||
}
|
||||
return FS::hardLinkCount(m_containerFile.absoluteFilePath()) > 1;
|
||||
}
|
||||
|
||||
void World::setSize(int64_t size)
|
||||
{
|
||||
m_size = size;
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ class World {
|
||||
QDateTime lastPlayed() const { return m_lastPlayed; }
|
||||
GameType gameType() const { return m_gameType; }
|
||||
int64_t seed() const { return m_randomSeed; }
|
||||
bool isValid() const { return is_valid; }
|
||||
bool isValid() const { return m_isValid; }
|
||||
bool isOnFS() const { return m_containerFile.isDir(); }
|
||||
QFileInfo container() const { return m_containerFile; }
|
||||
// delete all the files of this world
|
||||
@ -54,6 +54,8 @@ class World {
|
||||
bool rename(const QString& to);
|
||||
bool install(const QString& to, const QString& name = QString());
|
||||
|
||||
void setSize(int64_t size);
|
||||
|
||||
// WEAK compare operator - used for replacing worlds
|
||||
bool operator==(const World& other) const;
|
||||
|
||||
@ -83,10 +85,10 @@ class World {
|
||||
QString m_folderName;
|
||||
QString m_actualName;
|
||||
QString m_iconFile;
|
||||
QDateTime levelDatTime;
|
||||
QDateTime m_levelDatTime;
|
||||
QDateTime m_lastPlayed;
|
||||
int64_t m_size;
|
||||
int64_t m_randomSeed = 0;
|
||||
GameType m_gameType;
|
||||
bool is_valid = false;
|
||||
bool m_isValid = false;
|
||||
};
|
||||
|
@ -37,13 +37,14 @@
|
||||
|
||||
#include <FileSystem.h>
|
||||
#include <QDebug>
|
||||
#include <QDirIterator>
|
||||
#include <QFileSystemWatcher>
|
||||
#include <QMimeData>
|
||||
#include <QString>
|
||||
#include <QThreadPool>
|
||||
#include <QUrl>
|
||||
#include <QUuid>
|
||||
#include <Qt>
|
||||
#include "Application.h"
|
||||
|
||||
WorldList::WorldList(const QString& dir, BaseInstance* instance) : QAbstractListModel(), m_instance(instance), m_dir(dir)
|
||||
{
|
||||
@ -51,18 +52,18 @@ WorldList::WorldList(const QString& dir, BaseInstance* instance) : QAbstractList
|
||||
m_dir.setFilter(QDir::Readable | QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs);
|
||||
m_dir.setSorting(QDir::Name | QDir::IgnoreCase | QDir::LocaleAware);
|
||||
m_watcher = new QFileSystemWatcher(this);
|
||||
is_watching = false;
|
||||
m_isWatching = false;
|
||||
connect(m_watcher, &QFileSystemWatcher::directoryChanged, this, &WorldList::directoryChanged);
|
||||
}
|
||||
|
||||
void WorldList::startWatching()
|
||||
{
|
||||
if (is_watching) {
|
||||
if (m_isWatching) {
|
||||
return;
|
||||
}
|
||||
update();
|
||||
is_watching = m_watcher->addPath(m_dir.absolutePath());
|
||||
if (is_watching) {
|
||||
m_isWatching = m_watcher->addPath(m_dir.absolutePath());
|
||||
if (m_isWatching) {
|
||||
qDebug() << "Started watching " << m_dir.absolutePath();
|
||||
} else {
|
||||
qDebug() << "Failed to start watching " << m_dir.absolutePath();
|
||||
@ -71,11 +72,11 @@ void WorldList::startWatching()
|
||||
|
||||
void WorldList::stopWatching()
|
||||
{
|
||||
if (!is_watching) {
|
||||
if (!m_isWatching) {
|
||||
return;
|
||||
}
|
||||
is_watching = !m_watcher->removePath(m_dir.absolutePath());
|
||||
if (!is_watching) {
|
||||
m_isWatching = !m_watcher->removePath(m_dir.absolutePath());
|
||||
if (!m_isWatching) {
|
||||
qDebug() << "Stopped watching " << m_dir.absolutePath();
|
||||
} else {
|
||||
qDebug() << "Failed to stop watching " << m_dir.absolutePath();
|
||||
@ -101,12 +102,13 @@ bool WorldList::update()
|
||||
}
|
||||
}
|
||||
beginResetModel();
|
||||
worlds.swap(newWorlds);
|
||||
m_worlds.swap(newWorlds);
|
||||
endResetModel();
|
||||
loadWorldsAsync();
|
||||
return true;
|
||||
}
|
||||
|
||||
void WorldList::directoryChanged(QString path)
|
||||
void WorldList::directoryChanged(QString)
|
||||
{
|
||||
update();
|
||||
}
|
||||
@ -123,12 +125,12 @@ QString WorldList::instDirPath() const
|
||||
|
||||
bool WorldList::deleteWorld(int index)
|
||||
{
|
||||
if (index >= worlds.size() || index < 0)
|
||||
if (index >= m_worlds.size() || index < 0)
|
||||
return false;
|
||||
World& m = worlds[index];
|
||||
World& m = m_worlds[index];
|
||||
if (m.destroy()) {
|
||||
beginRemoveRows(QModelIndex(), index, index);
|
||||
worlds.removeAt(index);
|
||||
m_worlds.removeAt(index);
|
||||
endRemoveRows();
|
||||
emit changed();
|
||||
return true;
|
||||
@ -139,11 +141,11 @@ bool WorldList::deleteWorld(int index)
|
||||
bool WorldList::deleteWorlds(int first, int last)
|
||||
{
|
||||
for (int i = first; i <= last; i++) {
|
||||
World& m = worlds[i];
|
||||
World& m = m_worlds[i];
|
||||
m.destroy();
|
||||
}
|
||||
beginRemoveRows(QModelIndex(), first, last);
|
||||
worlds.erase(worlds.begin() + first, worlds.begin() + last + 1);
|
||||
m_worlds.erase(m_worlds.begin() + first, m_worlds.begin() + last + 1);
|
||||
endRemoveRows();
|
||||
emit changed();
|
||||
return true;
|
||||
@ -151,9 +153,9 @@ bool WorldList::deleteWorlds(int first, int last)
|
||||
|
||||
bool WorldList::resetIcon(int row)
|
||||
{
|
||||
if (row >= worlds.size() || row < 0)
|
||||
if (row >= m_worlds.size() || row < 0)
|
||||
return false;
|
||||
World& m = worlds[row];
|
||||
World& m = m_worlds[row];
|
||||
if (m.resetIcon()) {
|
||||
emit dataChanged(index(row), index(row), { WorldList::IconFileRole });
|
||||
return true;
|
||||
@ -174,12 +176,12 @@ QVariant WorldList::data(const QModelIndex& index, int role) const
|
||||
int row = index.row();
|
||||
int column = index.column();
|
||||
|
||||
if (row < 0 || row >= worlds.size())
|
||||
if (row < 0 || row >= m_worlds.size())
|
||||
return QVariant();
|
||||
|
||||
QLocale locale;
|
||||
|
||||
auto& world = worlds[row];
|
||||
auto& world = m_worlds[row];
|
||||
switch (role) {
|
||||
case Qt::DisplayRole:
|
||||
switch (column) {
|
||||
@ -339,9 +341,9 @@ QMimeData* WorldList::mimeData(const QModelIndexList& indexes) const
|
||||
if (idx.column() != 0)
|
||||
continue;
|
||||
int row = idx.row();
|
||||
if (row < 0 || row >= this->worlds.size())
|
||||
if (row < 0 || row >= this->m_worlds.size())
|
||||
continue;
|
||||
worlds_.append(this->worlds[row]);
|
||||
worlds_.append(this->m_worlds[row]);
|
||||
}
|
||||
if (!worlds_.size()) {
|
||||
return new QMimeData();
|
||||
@ -393,7 +395,7 @@ bool WorldList::dropMimeData(const QMimeData* data,
|
||||
return false;
|
||||
// files dropped from outside?
|
||||
if (data->hasUrls()) {
|
||||
bool was_watching = is_watching;
|
||||
bool was_watching = m_isWatching;
|
||||
if (was_watching)
|
||||
stopWatching();
|
||||
auto urls = data->urls();
|
||||
@ -416,4 +418,44 @@ bool WorldList::dropMimeData(const QMimeData* data,
|
||||
return false;
|
||||
}
|
||||
|
||||
int64_t calculateWorldSize(const QFileInfo& file)
|
||||
{
|
||||
if (file.isFile() && file.suffix() == "zip") {
|
||||
return file.size();
|
||||
} else if (file.isDir()) {
|
||||
QDirIterator it(file.absoluteFilePath(), QDir::Files, QDirIterator::Subdirectories);
|
||||
int64_t total = 0;
|
||||
while (it.hasNext()) {
|
||||
it.next();
|
||||
total += it.fileInfo().size();
|
||||
}
|
||||
return total;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void WorldList::loadWorldsAsync()
|
||||
{
|
||||
for (int i = 0; i < m_worlds.size(); ++i) {
|
||||
auto file = m_worlds.at(i).container();
|
||||
int row = i;
|
||||
QThreadPool::globalInstance()->start([this, file, row]() mutable {
|
||||
auto size = calculateWorldSize(file);
|
||||
|
||||
QMetaObject::invokeMethod(
|
||||
this,
|
||||
[this, size, row, file]() {
|
||||
if (row < m_worlds.size() && m_worlds[row].container() == file) {
|
||||
m_worlds[row].setSize(size);
|
||||
|
||||
// Notify views
|
||||
QModelIndex modelIndex = index(row);
|
||||
emit dataChanged(modelIndex, modelIndex, { SizeRole });
|
||||
}
|
||||
},
|
||||
Qt::QueuedConnection);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
#include "WorldList.moc"
|
||||
|
@ -40,9 +40,9 @@ class WorldList : public QAbstractListModel {
|
||||
virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
|
||||
virtual int columnCount(const QModelIndex& parent) const;
|
||||
|
||||
size_t size() const { return worlds.size(); };
|
||||
size_t size() const { return m_worlds.size(); };
|
||||
bool empty() const { return size() == 0; }
|
||||
World& operator[](size_t index) { return worlds[index]; }
|
||||
World& operator[](size_t index) { return m_worlds[index]; }
|
||||
|
||||
/// Reloads the mod list and returns true if the list changed.
|
||||
virtual bool update();
|
||||
@ -82,10 +82,11 @@ class WorldList : public QAbstractListModel {
|
||||
|
||||
QString instDirPath() const;
|
||||
|
||||
const QList<World>& allWorlds() const { return worlds; }
|
||||
const QList<World>& allWorlds() const { return m_worlds; }
|
||||
|
||||
private slots:
|
||||
void directoryChanged(QString path);
|
||||
void loadWorldsAsync();
|
||||
|
||||
signals:
|
||||
void changed();
|
||||
@ -93,7 +94,7 @@ class WorldList : public QAbstractListModel {
|
||||
protected:
|
||||
BaseInstance* m_instance;
|
||||
QFileSystemWatcher* m_watcher;
|
||||
bool is_watching;
|
||||
bool m_isWatching;
|
||||
QDir m_dir;
|
||||
QList<World> worlds;
|
||||
QList<World> m_worlds;
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user