aboutsummaryrefslogtreecommitdiff
path: root/launcher/minecraft
diff options
context:
space:
mode:
authorRachel Powers <508861+Ryex@users.noreply.github.com>2023-05-12 01:13:17 -0700
committerGitHub <noreply@github.com>2023-05-12 01:13:17 -0700
commit6b6d6a01dc9cf05715f01e3a549740b169ef9ae3 (patch)
tree8ba9746a188c39003213839825552543e3f1a48f /launcher/minecraft
parentf27716656c6f6006238203669a7a02f035733fc0 (diff)
parentc5aff7cc1ef43a1326bd3ce0c83e29669e2ff43f (diff)
downloadPrismLauncher-6b6d6a01dc9cf05715f01e3a549740b169ef9ae3.tar.gz
PrismLauncher-6b6d6a01dc9cf05715f01e3a549740b169ef9ae3.tar.bz2
PrismLauncher-6b6d6a01dc9cf05715f01e3a549740b169ef9ae3.zip
Merge branch 'develop' into fix/network_and_signals
Signed-off-by: Rachel Powers <508861+Ryex@users.noreply.github.com>
Diffstat (limited to 'launcher/minecraft')
-rw-r--r--launcher/minecraft/MinecraftInstance.cpp19
-rw-r--r--launcher/minecraft/MinecraftLoadAndCheck.cpp1
-rw-r--r--launcher/minecraft/MinecraftUpdate.cpp4
-rw-r--r--launcher/minecraft/World.cpp24
-rw-r--r--launcher/minecraft/World.h15
-rw-r--r--launcher/minecraft/WorldList.cpp34
-rw-r--r--launcher/minecraft/WorldList.h9
-rw-r--r--launcher/minecraft/mod/ModFolderModel.cpp24
-rw-r--r--launcher/minecraft/mod/ModFolderModel.h2
-rw-r--r--launcher/minecraft/mod/Resource.cpp20
-rw-r--r--launcher/minecraft/mod/Resource.h13
-rw-r--r--launcher/minecraft/mod/ResourceFolderModel.cpp32
-rw-r--r--launcher/minecraft/mod/ResourceFolderModel.h7
-rw-r--r--launcher/minecraft/mod/ResourcePackFolderModel.cpp24
-rw-r--r--launcher/minecraft/mod/ResourcePackFolderModel.h2
-rw-r--r--launcher/minecraft/mod/ShaderPackFolderModel.h4
-rw-r--r--launcher/minecraft/mod/TexturePackFolderModel.cpp4
-rw-r--r--launcher/minecraft/mod/TexturePackFolderModel.h2
-rw-r--r--launcher/minecraft/mod/tasks/LocalModParseTask.cpp6
-rw-r--r--launcher/minecraft/update/AssetUpdateTask.cpp2
-rw-r--r--launcher/minecraft/update/FMLLibrariesTask.cpp1
-rw-r--r--launcher/minecraft/update/LibrariesTask.cpp2
22 files changed, 224 insertions, 27 deletions
diff --git a/launcher/minecraft/MinecraftInstance.cpp b/launcher/minecraft/MinecraftInstance.cpp
index af4da5d0..35bef05e 100644
--- a/launcher/minecraft/MinecraftInstance.cpp
+++ b/launcher/minecraft/MinecraftInstance.cpp
@@ -925,7 +925,10 @@ QString MinecraftInstance::getStatusbarDescription()
if(m_settings->get("ShowGameTime").toBool())
{
if (lastTimePlayed() > 0) {
- description.append(tr(", last played for %1").arg(Time::prettifyDuration(lastTimePlayed())));
+ QDateTime lastLaunchTime = QDateTime::fromMSecsSinceEpoch(lastLaunch());
+ description.append(tr(", last played on %1 for %2")
+ .arg(QLocale().toString(lastLaunchTime, QLocale::ShortFormat))
+ .arg(Time::prettifyDuration(lastTimePlayed())));
}
if (totalTimePlayed() > 0) {
@@ -1111,7 +1114,7 @@ std::shared_ptr<ModFolderModel> MinecraftInstance::loaderModList() const
if (!m_loader_mod_list)
{
bool is_indexed = !APPLICATION->settings()->get("ModMetadataDisabled").toBool();
- m_loader_mod_list.reset(new ModFolderModel(modsRoot(), is_indexed));
+ m_loader_mod_list.reset(new ModFolderModel(modsRoot(), shared_from_this(), is_indexed));
m_loader_mod_list->disableInteraction(isRunning());
connect(this, &BaseInstance::runningStatusChanged, m_loader_mod_list.get(), &ModFolderModel::disableInteraction);
}
@@ -1123,7 +1126,7 @@ std::shared_ptr<ModFolderModel> MinecraftInstance::coreModList() const
if (!m_core_mod_list)
{
bool is_indexed = !APPLICATION->settings()->get("ModMetadataDisabled").toBool();
- m_core_mod_list.reset(new ModFolderModel(coreModsDir(), is_indexed));
+ m_core_mod_list.reset(new ModFolderModel(coreModsDir(), shared_from_this(), is_indexed));
m_core_mod_list->disableInteraction(isRunning());
connect(this, &BaseInstance::runningStatusChanged, m_core_mod_list.get(), &ModFolderModel::disableInteraction);
}
@@ -1135,7 +1138,7 @@ std::shared_ptr<ModFolderModel> MinecraftInstance::nilModList() const
if (!m_nil_mod_list)
{
bool is_indexed = !APPLICATION->settings()->get("ModMetadataDisabled").toBool();
- m_nil_mod_list.reset(new ModFolderModel(nilModsDir(), is_indexed, false));
+ m_nil_mod_list.reset(new ModFolderModel(nilModsDir(), shared_from_this(), is_indexed, false));
m_nil_mod_list->disableInteraction(isRunning());
connect(this, &BaseInstance::runningStatusChanged, m_nil_mod_list.get(), &ModFolderModel::disableInteraction);
}
@@ -1146,7 +1149,7 @@ std::shared_ptr<ResourcePackFolderModel> MinecraftInstance::resourcePackList() c
{
if (!m_resource_pack_list)
{
- m_resource_pack_list.reset(new ResourcePackFolderModel(resourcePacksDir()));
+ m_resource_pack_list.reset(new ResourcePackFolderModel(resourcePacksDir(), shared_from_this()));
}
return m_resource_pack_list;
}
@@ -1155,7 +1158,7 @@ std::shared_ptr<TexturePackFolderModel> MinecraftInstance::texturePackList() con
{
if (!m_texture_pack_list)
{
- m_texture_pack_list.reset(new TexturePackFolderModel(texturePacksDir()));
+ m_texture_pack_list.reset(new TexturePackFolderModel(texturePacksDir(), shared_from_this()));
}
return m_texture_pack_list;
}
@@ -1164,7 +1167,7 @@ std::shared_ptr<ShaderPackFolderModel> MinecraftInstance::shaderPackList() const
{
if (!m_shader_pack_list)
{
- m_shader_pack_list.reset(new ShaderPackFolderModel(shaderPacksDir()));
+ m_shader_pack_list.reset(new ShaderPackFolderModel(shaderPacksDir(), shared_from_this()));
}
return m_shader_pack_list;
}
@@ -1173,7 +1176,7 @@ std::shared_ptr<WorldList> MinecraftInstance::worldList() const
{
if (!m_world_list)
{
- m_world_list.reset(new WorldList(worldDir()));
+ m_world_list.reset(new WorldList(worldDir(), shared_from_this()));
}
return m_world_list;
}
diff --git a/launcher/minecraft/MinecraftLoadAndCheck.cpp b/launcher/minecraft/MinecraftLoadAndCheck.cpp
index d72bc7be..1c3f6fb7 100644
--- a/launcher/minecraft/MinecraftLoadAndCheck.cpp
+++ b/launcher/minecraft/MinecraftLoadAndCheck.cpp
@@ -22,6 +22,7 @@ void MinecraftLoadAndCheck::executeTask()
connect(m_task.get(), &Task::failed, this, &MinecraftLoadAndCheck::subtaskFailed);
connect(m_task.get(), &Task::aborted, this, [this]{ subtaskFailed(tr("Aborted")); });
connect(m_task.get(), &Task::progress, this, &MinecraftLoadAndCheck::progress);
+ connect(m_task.get(), &Task::stepProgress, this, &MinecraftLoadAndCheck::propogateStepProgress);
connect(m_task.get(), &Task::status, this, &MinecraftLoadAndCheck::setStatus);
}
diff --git a/launcher/minecraft/MinecraftUpdate.cpp b/launcher/minecraft/MinecraftUpdate.cpp
index 07ad4882..35430bb0 100644
--- a/launcher/minecraft/MinecraftUpdate.cpp
+++ b/launcher/minecraft/MinecraftUpdate.cpp
@@ -100,7 +100,9 @@ void MinecraftUpdate::next()
disconnect(task.get(), &Task::failed, this, &MinecraftUpdate::subtaskFailed);
disconnect(task.get(), &Task::aborted, this, &Task::abort);
disconnect(task.get(), &Task::progress, this, &MinecraftUpdate::progress);
+ disconnect(task.get(), &Task::stepProgress, this, &MinecraftUpdate::propogateStepProgress);
disconnect(task.get(), &Task::status, this, &MinecraftUpdate::setStatus);
+ disconnect(task.get(), &Task::details, this, &MinecraftUpdate::setDetails);
}
if(m_currentTask == m_tasks.size())
{
@@ -118,7 +120,9 @@ void MinecraftUpdate::next()
connect(task.get(), &Task::failed, this, &MinecraftUpdate::subtaskFailed);
connect(task.get(), &Task::aborted, this, &Task::abort);
connect(task.get(), &Task::progress, this, &MinecraftUpdate::progress);
+ connect(task.get(), &Task::stepProgress, this, &MinecraftUpdate::propogateStepProgress);
connect(task.get(), &Task::status, this, &MinecraftUpdate::setStatus);
+ connect(task.get(), &Task::details, this, &MinecraftUpdate::setDetails);
// if the task is already running, do not start it again
if(!task->isRunning())
{
diff --git a/launcher/minecraft/World.cpp b/launcher/minecraft/World.cpp
index d310f8b9..54fb9434 100644
--- a/launcher/minecraft/World.cpp
+++ b/launcher/minecraft/World.cpp
@@ -56,6 +56,8 @@
#include <optional>
+#include "FileSystem.h"
+
using std::optional;
using std::nullopt;
@@ -567,3 +569,25 @@ bool World::operator==(const World &other) const
{
return is_valid == other.is_valid && folderName() == other.folderName();
}
+
+bool World::isSymLinkUnder(const QString& instPath) const
+{
+ if (isSymLink())
+ return true;
+
+ auto instDir = QDir(instPath);
+
+ auto relAbsPath = instDir.relativeFilePath(m_containerFile.absoluteFilePath());
+ auto relCanonPath = instDir.relativeFilePath(m_containerFile.canonicalFilePath());
+
+ return relAbsPath != relCanonPath;
+}
+
+bool World::isMoreThanOneHardLink() const
+{
+ if (m_containerFile.isDir())
+ {
+ return FS::hardLinkCount(QDir(m_containerFile.absoluteFilePath()).filePath("level.dat")) > 1;
+ }
+ return FS::hardLinkCount(m_containerFile.absoluteFilePath()) > 1;
+}
diff --git a/launcher/minecraft/World.h b/launcher/minecraft/World.h
index 8327253a..10328cce 100644
--- a/launcher/minecraft/World.h
+++ b/launcher/minecraft/World.h
@@ -95,6 +95,21 @@ public:
// WEAK compare operator - used for replacing worlds
bool operator==(const World &other) const;
+ [[nodiscard]] auto isSymLink() const -> bool{ return m_containerFile.isSymLink(); }
+
+ /**
+ * @brief Take a instance path, checks if the file pointed to by the resource is a symlink or under a symlink in that instance
+ *
+ * @param instPath path to an instance directory
+ * @return true
+ * @return false
+ */
+ [[nodiscard]] bool isSymLinkUnder(const QString& instPath) const;
+
+ [[nodiscard]] bool isMoreThanOneHardLink() const;
+
+ QString canonicalFilePath() const { return m_containerFile.canonicalFilePath(); }
+
private:
void readFromZip(const QFileInfo &file);
void readFromFS(const QFileInfo &file);
diff --git a/launcher/minecraft/WorldList.cpp b/launcher/minecraft/WorldList.cpp
index de21c474..df6b4ecc 100644
--- a/launcher/minecraft/WorldList.cpp
+++ b/launcher/minecraft/WorldList.cpp
@@ -45,8 +45,8 @@
#include <QFileSystemWatcher>
#include <QDebug>
-WorldList::WorldList(const QString &dir)
- : QAbstractListModel(), m_dir(dir)
+WorldList::WorldList(const QString &dir, std::shared_ptr<const BaseInstance> instance)
+ : QAbstractListModel(), m_instance(instance), m_dir(dir)
{
FS::ensureFolderPathExists(m_dir.absolutePath());
m_dir.setFilter(QDir::Readable | QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs);
@@ -127,6 +127,10 @@ bool WorldList::isValid()
return m_dir.exists() && m_dir.isReadable();
}
+QString WorldList::instDirPath() const {
+ return QFileInfo(m_instance->instanceRoot()).absoluteFilePath();
+}
+
bool WorldList::deleteWorld(int index)
{
if (index >= worlds.size() || index < 0)
@@ -172,7 +176,7 @@ bool WorldList::resetIcon(int row)
int WorldList::columnCount(const QModelIndex &parent) const
{
- return parent.isValid()? 0 : 4;
+ return parent.isValid()? 0 : 5;
}
QVariant WorldList::data(const QModelIndex &index, int role) const
@@ -206,6 +210,14 @@ QVariant WorldList::data(const QModelIndex &index, int role) const
case SizeColumn:
return locale.formattedDataSize(world.bytes());
+ case InfoColumn:
+ if (world.isSymLinkUnder(instDirPath())) {
+ return tr("This world is symbolically linked from elsewhere.");
+ }
+ if (world.isMoreThanOneHardLink()) {
+ return tr("\nThis world is hard linked elsewhere.");
+ }
+ return "";
default:
return QVariant();
}
@@ -221,7 +233,16 @@ QVariant WorldList::data(const QModelIndex &index, int role) const
}
case Qt::ToolTipRole:
- {
+ {
+ if (column == InfoColumn) {
+ if (world.isSymLinkUnder(instDirPath())) {
+ return tr("Warning: This world is symbolically linked from elsewhere. Editing it will also change the original."
+ "\nCanonical Path: %1").arg(world.canonicalFilePath());
+ }
+ if (world.isMoreThanOneHardLink()) {
+ return tr("Warning: This world is hard linked elsewhere. Editing it will also change the original.");
+ }
+ }
return world.folderName();
}
case ObjectRole:
@@ -273,6 +294,9 @@ QVariant WorldList::headerData(int section, Qt::Orientation orientation, int rol
case SizeColumn:
//: World size on disk
return tr("Size");
+ case InfoColumn:
+ //: special warnings?
+ return tr("Info");
default:
return QVariant();
}
@@ -288,6 +312,8 @@ QVariant WorldList::headerData(int section, Qt::Orientation orientation, int rol
return tr("Date and time the world was last played.");
case SizeColumn:
return tr("Size of the world on disk.");
+ case InfoColumn:
+ return tr("Information and warnings about the world.");
default:
return QVariant();
}
diff --git a/launcher/minecraft/WorldList.h b/launcher/minecraft/WorldList.h
index 08294755..10fb4e3c 100644
--- a/launcher/minecraft/WorldList.h
+++ b/launcher/minecraft/WorldList.h
@@ -21,6 +21,7 @@
#include <QAbstractListModel>
#include <QMimeData>
#include "minecraft/World.h"
+#include "BaseInstance.h"
class QFileSystemWatcher;
@@ -33,7 +34,8 @@ public:
NameColumn,
GameModeColumn,
LastPlayedColumn,
- SizeColumn
+ SizeColumn,
+ InfoColumn
};
enum Roles
@@ -48,7 +50,7 @@ public:
IconFileRole
};
- WorldList(const QString &dir);
+ WorldList(const QString &dir, std::shared_ptr<const BaseInstance> instance);
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
@@ -112,6 +114,8 @@ public:
return m_dir;
}
+ QString instDirPath() const;
+
const QList<World> &allWorlds() const
{
return worlds;
@@ -124,6 +128,7 @@ signals:
void changed();
protected:
+ std::shared_ptr<const BaseInstance> m_instance;
QFileSystemWatcher *m_watcher;
bool is_watching;
QDir m_dir;
diff --git a/launcher/minecraft/mod/ModFolderModel.cpp b/launcher/minecraft/mod/ModFolderModel.cpp
index 3f31b93c..6ae25d33 100644
--- a/launcher/minecraft/mod/ModFolderModel.cpp
+++ b/launcher/minecraft/mod/ModFolderModel.cpp
@@ -39,18 +39,23 @@
#include <FileSystem.h>
#include <QDebug>
#include <QFileSystemWatcher>
+#include <QIcon>
#include <QMimeData>
#include <QString>
+#include <QStyle>
#include <QThreadPool>
#include <QUrl>
#include <QUuid>
#include <algorithm>
+#include "Application.h"
+
#include "minecraft/mod/tasks/LocalModParseTask.h"
#include "minecraft/mod/tasks/ModFolderLoadTask.h"
#include "modplatform/ModIndex.h"
-ModFolderModel::ModFolderModel(const QString &dir, bool is_indexed, bool create_dir) : ResourceFolderModel(QDir(dir), nullptr, create_dir), m_is_indexed(is_indexed)
+ModFolderModel::ModFolderModel(const QString& dir, std::shared_ptr<const BaseInstance> instance, bool is_indexed, bool create_dir)
+ : ResourceFolderModel(QDir(dir), instance, nullptr, create_dir), m_is_indexed(is_indexed)
{
m_column_sort_keys = { SortType::ENABLED, SortType::NAME, SortType::VERSION, SortType::DATE, SortType::PROVIDER };
}
@@ -97,8 +102,25 @@ QVariant ModFolderModel::data(const QModelIndex &index, int role) const
}
case Qt::ToolTipRole:
+ if (column == NAME_COLUMN) {
+ if (at(row)->isSymLinkUnder(instDirPath())) {
+ return m_resources[row]->internal_id() +
+ tr("\nWarning: This resource is symbolically linked from elsewhere. Editing it will also change the original."
+ "\nCanonical Path: %1")
+ .arg(at(row)->fileinfo().canonicalFilePath());
+ }
+ if (at(row)->isMoreThanOneHardLink()) {
+ return m_resources[row]->internal_id() +
+ tr("\nWarning: This resource is hard linked elsewhere. Editing it will also change the original.");
+ }
+ }
return m_resources[row]->internal_id();
+ case Qt::DecorationRole: {
+ if (column == NAME_COLUMN && (at(row)->isSymLinkUnder(instDirPath()) || at(row)->isMoreThanOneHardLink()))
+ return APPLICATION->getThemedIcon("status-yellow");
+ return {};
+ }
case Qt::CheckStateRole:
switch (column)
{
diff --git a/launcher/minecraft/mod/ModFolderModel.h b/launcher/minecraft/mod/ModFolderModel.h
index 84e70db9..46f5087f 100644
--- a/launcher/minecraft/mod/ModFolderModel.h
+++ b/launcher/minecraft/mod/ModFolderModel.h
@@ -75,7 +75,7 @@ public:
Enable,
Toggle
};
- ModFolderModel(const QString &dir, bool is_indexed = false, bool create_dir = true);
+ ModFolderModel(const QString &dir, std::shared_ptr<const BaseInstance> instance, bool is_indexed = false, bool create_dir = true);
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
diff --git a/launcher/minecraft/mod/Resource.cpp b/launcher/minecraft/mod/Resource.cpp
index 0d35d755..a0b8a4bb 100644
--- a/launcher/minecraft/mod/Resource.cpp
+++ b/launcher/minecraft/mod/Resource.cpp
@@ -1,6 +1,8 @@
#include "Resource.h"
+
#include <QRegularExpression>
+#include <QFileInfo>
#include "FileSystem.h"
@@ -152,3 +154,21 @@ bool Resource::destroy()
return FS::deletePath(m_file_info.filePath());
}
+
+bool Resource::isSymLinkUnder(const QString& instPath) const
+{
+ if (isSymLink())
+ return true;
+
+ auto instDir = QDir(instPath);
+
+ auto relAbsPath = instDir.relativeFilePath(m_file_info.absoluteFilePath());
+ auto relCanonPath = instDir.relativeFilePath(m_file_info.canonicalFilePath());
+
+ return relAbsPath != relCanonPath;
+}
+
+bool Resource::isMoreThanOneHardLink() const
+{
+ return FS::hardLinkCount(m_file_info.absoluteFilePath()) > 1;
+}
diff --git a/launcher/minecraft/mod/Resource.h b/launcher/minecraft/mod/Resource.h
index 0c37f3a3..a5e9ae91 100644
--- a/launcher/minecraft/mod/Resource.h
+++ b/launcher/minecraft/mod/Resource.h
@@ -94,6 +94,19 @@ class Resource : public QObject {
// Delete all files of this resource.
bool destroy();
+ [[nodiscard]] auto isSymLink() const -> bool { return m_file_info.isSymLink(); }
+
+ /**
+ * @brief Take a instance path, checks if the file pointed to by the resource is a symlink or under a symlink in that instance
+ *
+ * @param instPath path to an instance directory
+ * @return true
+ * @return false
+ */
+ [[nodiscard]] bool isSymLinkUnder(const QString& instPath) const;
+
+ [[nodiscard]] bool isMoreThanOneHardLink() const;
+
protected:
/* The file corresponding to this resource. */
QFileInfo m_file_info;
diff --git a/launcher/minecraft/mod/ResourceFolderModel.cpp b/launcher/minecraft/mod/ResourceFolderModel.cpp
index f2a77c12..e1973468 100644
--- a/launcher/minecraft/mod/ResourceFolderModel.cpp
+++ b/launcher/minecraft/mod/ResourceFolderModel.cpp
@@ -2,17 +2,22 @@
#include <QCoreApplication>
#include <QDebug>
+#include <QFileInfo>
+#include <QIcon>
#include <QMimeData>
+#include <QStyle>
#include <QThreadPool>
#include <QUrl>
+#include "Application.h"
#include "FileSystem.h"
#include "minecraft/mod/tasks/BasicFolderLoadTask.h"
#include "tasks/Task.h"
-ResourceFolderModel::ResourceFolderModel(QDir dir, QObject* parent, bool create_dir) : QAbstractListModel(parent), m_dir(dir), m_watcher(this)
+ResourceFolderModel::ResourceFolderModel(QDir dir, std::shared_ptr<const BaseInstance> instance, QObject* parent, bool create_dir)
+ : QAbstractListModel(parent), m_dir(dir), m_instance(instance), m_watcher(this)
{
if (create_dir) {
FS::ensureFolderPathExists(m_dir.absolutePath());
@@ -22,7 +27,7 @@ ResourceFolderModel::ResourceFolderModel(QDir dir, QObject* parent, bool create_
m_dir.setSorting(QDir::Name | QDir::IgnoreCase | QDir::LocaleAware);
connect(&m_watcher, &QFileSystemWatcher::directoryChanged, this, &ResourceFolderModel::directoryChanged);
- connect(&m_helper_thread_task, &ConcurrentTask::finished, this, [this]{ m_helper_thread_task.clear(); });
+ connect(&m_helper_thread_task, &ConcurrentTask::finished, this, [this] { m_helper_thread_task.clear(); });
}
ResourceFolderModel::~ResourceFolderModel()
@@ -417,7 +422,26 @@ QVariant ResourceFolderModel::data(const QModelIndex& index, int role) const
return {};
}
case Qt::ToolTipRole:
+ if (column == NAME_COLUMN) {
+ if (at(row).isSymLinkUnder(instDirPath())) {
+ return m_resources[row]->internal_id() +
+ tr("\nWarning: This resource is symbolically linked from elsewhere. Editing it will also change the original."
+ "\nCanonical Path: %1")
+ .arg(at(row).fileinfo().canonicalFilePath());;
+ }
+ if (at(row).isMoreThanOneHardLink()) {
+ return m_resources[row]->internal_id() +
+ tr("\nWarning: This resource is hard linked elsewhere. Editing it will also change the original.");
+ }
+ }
+
return m_resources[row]->internal_id();
+ case Qt::DecorationRole: {
+ if (column == NAME_COLUMN && (at(row).isSymLinkUnder(instDirPath()) || at(row).isMoreThanOneHardLink()))
+ return APPLICATION->getThemedIcon("status-yellow");
+
+ return {};
+ }
case Qt::CheckStateRole:
switch (column) {
case ACTIVE_COLUMN:
@@ -531,3 +555,7 @@ void ResourceFolderModel::enableInteraction(bool enabled)
return (compare_result.first < 0);
return (compare_result.first > 0);
}
+
+QString ResourceFolderModel::instDirPath() const {
+ return QFileInfo(m_instance->instanceRoot()).absoluteFilePath();
+}
diff --git a/launcher/minecraft/mod/ResourceFolderModel.h b/launcher/minecraft/mod/ResourceFolderModel.h
index 3bd78870..fdf5f331 100644
--- a/launcher/minecraft/mod/ResourceFolderModel.h
+++ b/launcher/minecraft/mod/ResourceFolderModel.h
@@ -9,6 +9,8 @@
#include "Resource.h"
+#include "BaseInstance.h"
+
#include "tasks/Task.h"
#include "tasks/ConcurrentTask.h"
@@ -24,7 +26,7 @@ class QSortFilterProxyModel;
class ResourceFolderModel : public QAbstractListModel {
Q_OBJECT
public:
- ResourceFolderModel(QDir, QObject* parent = nullptr, bool create_dir = true);
+ ResourceFolderModel(QDir, std::shared_ptr<const BaseInstance>, QObject* parent = nullptr, bool create_dir = true);
~ResourceFolderModel() override;
/** Starts watching the paths for changes.
@@ -125,6 +127,8 @@ class ResourceFolderModel : public QAbstractListModel {
[[nodiscard]] bool lessThan(const QModelIndex& source_left, const QModelIndex& source_right) const override;
};
+ QString instDirPath() const;
+
public slots:
void enableInteraction(bool enabled);
void disableInteraction(bool disabled) { enableInteraction(!disabled); }
@@ -187,6 +191,7 @@ class ResourceFolderModel : public QAbstractListModel {
bool m_can_interact = true;
QDir m_dir;
+ std::shared_ptr<const BaseInstance> m_instance;
QFileSystemWatcher m_watcher;
bool m_is_watching = false;
diff --git a/launcher/minecraft/mod/ResourcePackFolderModel.cpp b/launcher/minecraft/mod/ResourcePackFolderModel.cpp
index da4bd091..6eba4e2e 100644
--- a/launcher/minecraft/mod/ResourcePackFolderModel.cpp
+++ b/launcher/minecraft/mod/ResourcePackFolderModel.cpp
@@ -36,12 +36,17 @@
#include "ResourcePackFolderModel.h"
+#include <QIcon>
+#include <QStyle>
+
+#include "Application.h"
#include "Version.h"
#include "minecraft/mod/tasks/BasicFolderLoadTask.h"
#include "minecraft/mod/tasks/LocalResourcePackParseTask.h"
-ResourcePackFolderModel::ResourcePackFolderModel(const QString& dir) : ResourceFolderModel(QDir(dir))
+ResourcePackFolderModel::ResourcePackFolderModel(const QString& dir, std::shared_ptr<const BaseInstance> instance)
+ : ResourceFolderModel(QDir(dir), instance)
{
m_column_sort_keys = { SortType::ENABLED, SortType::NAME, SortType::PACK_FORMAT, SortType::DATE };
}
@@ -78,12 +83,29 @@ QVariant ResourcePackFolderModel::data(const QModelIndex& index, int role) const
default:
return {};
}
+ case Qt::DecorationRole: {
+ if (column == NAME_COLUMN && (at(row)->isSymLinkUnder(instDirPath()) || at(row)->isMoreThanOneHardLink()))
+ return APPLICATION->getThemedIcon("status-yellow");
+ return {};
+ }
case Qt::ToolTipRole: {
if (column == PackFormatColumn) {
//: The string being explained by this is in the format: ID (Lower version - Upper version)
return tr("The resource pack format ID, as well as the Minecraft versions it was designed for.");
}
+ if (column == NAME_COLUMN) {
+ if (at(row)->isSymLinkUnder(instDirPath())) {
+ return m_resources[row]->internal_id() +
+ tr("\nWarning: This resource is symbolically linked from elsewhere. Editing it will also change the original."
+ "\nCanonical Path: %1")
+ .arg(at(row)->fileinfo().canonicalFilePath());;
+ }
+ if (at(row)->isMoreThanOneHardLink()) {
+ return m_resources[row]->internal_id() +
+ tr("\nWarning: This resource is hard linked elsewhere. Editing it will also change the original.");
+ }
+ }
return m_resources[row]->internal_id();
}
case Qt::CheckStateRole:
diff --git a/launcher/minecraft/mod/ResourcePackFolderModel.h b/launcher/minecraft/mod/ResourcePackFolderModel.h
index cb620ce2..66d5a074 100644
--- a/launcher/minecraft/mod/ResourcePackFolderModel.h
+++ b/launcher/minecraft/mod/ResourcePackFolderModel.h
@@ -17,7 +17,7 @@ public:
NUM_COLUMNS
};
- explicit ResourcePackFolderModel(const QString &dir);
+ explicit ResourcePackFolderModel(const QString &dir, std::shared_ptr<const BaseInstance> instance);
[[nodiscard]] QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
diff --git a/launcher/minecraft/mod/ShaderPackFolderModel.h b/launcher/minecraft/mod/ShaderPackFolderModel.h
index a3aa958f..6f3f2811 100644
--- a/launcher/minecraft/mod/ShaderPackFolderModel.h
+++ b/launcher/minecraft/mod/ShaderPackFolderModel.h
@@ -6,5 +6,7 @@ class ShaderPackFolderModel : public ResourceFolderModel {
Q_OBJECT
public:
- explicit ShaderPackFolderModel(const QString& dir) : ResourceFolderModel(QDir(dir)) {}
+ explicit ShaderPackFolderModel(const QString& dir, std::shared_ptr<const BaseInstance> instance)
+ : ResourceFolderModel(QDir(dir), instance)
+ {}
};
diff --git a/launcher/minecraft/mod/TexturePackFolderModel.cpp b/launcher/minecraft/mod/TexturePackFolderModel.cpp
index 5a32cfaf..1e218537 100644
--- a/launcher/minecraft/mod/TexturePackFolderModel.cpp
+++ b/launcher/minecraft/mod/TexturePackFolderModel.cpp
@@ -39,7 +39,9 @@
#include "minecraft/mod/tasks/BasicFolderLoadTask.h"
#include "minecraft/mod/tasks/LocalTexturePackParseTask.h"
-TexturePackFolderModel::TexturePackFolderModel(const QString &dir) : ResourceFolderModel(QDir(dir)) {}
+TexturePackFolderModel::TexturePackFolderModel(const QString& dir, std::shared_ptr<const BaseInstance> instance)
+ : ResourceFolderModel(QDir(dir), instance)
+{}
Task* TexturePackFolderModel::createUpdateTask()
{
diff --git a/launcher/minecraft/mod/TexturePackFolderModel.h b/launcher/minecraft/mod/TexturePackFolderModel.h
index 261f83b4..246997bd 100644
--- a/launcher/minecraft/mod/TexturePackFolderModel.h
+++ b/launcher/minecraft/mod/TexturePackFolderModel.h
@@ -43,7 +43,7 @@ class TexturePackFolderModel : public ResourceFolderModel
Q_OBJECT
public:
- explicit TexturePackFolderModel(const QString &dir);
+ explicit TexturePackFolderModel(const QString &dir, std::shared_ptr<const BaseInstance> instance);
[[nodiscard]] Task* createUpdateTask() override;
[[nodiscard]] Task* createParseTask(Resource&) override;
};
diff --git a/launcher/minecraft/mod/tasks/LocalModParseTask.cpp b/launcher/minecraft/mod/tasks/LocalModParseTask.cpp
index da27a505..5342d693 100644
--- a/launcher/minecraft/mod/tasks/LocalModParseTask.cpp
+++ b/launcher/minecraft/mod/tasks/LocalModParseTask.cpp
@@ -242,7 +242,7 @@ ModDetails ReadQuiltModInfo(QByteArray contents)
return details;
}
-ModDetails ReadForgeInfo(QByteArray contents)
+ModDetails ReadForgeInfo(QString fileName)
{
ModDetails details;
// Read the data
@@ -250,7 +250,7 @@ ModDetails ReadForgeInfo(QByteArray contents)
details.mod_id = "Forge";
details.homeurl = "http://www.minecraftforge.net/forum/";
INIFile ini;
- if (!ini.loadFile(contents))
+ if (!ini.loadFile(fileName))
return details;
QString major = ini.get("forge.major.number", "0").toString();
@@ -422,7 +422,7 @@ bool processZIP(Mod& mod, ProcessingLevel level)
return false;
}
- details = ReadForgeInfo(file.readAll());
+ details = ReadForgeInfo(file.getFileName());
file.close();
zip.close();
diff --git a/launcher/minecraft/update/AssetUpdateTask.cpp b/launcher/minecraft/update/AssetUpdateTask.cpp
index 8ccb0e1d..31fd5eb1 100644
--- a/launcher/minecraft/update/AssetUpdateTask.cpp
+++ b/launcher/minecraft/update/AssetUpdateTask.cpp
@@ -45,6 +45,7 @@ void AssetUpdateTask::executeTask()
connect(downloadJob.get(), &NetJob::failed, this, &AssetUpdateTask::assetIndexFailed);
connect(downloadJob.get(), &NetJob::aborted, this, [this]{ emitFailed(tr("Aborted")); });
connect(downloadJob.get(), &NetJob::progress, this, &AssetUpdateTask::progress);
+ connect(downloadJob.get(), &NetJob::stepProgress, this, &AssetUpdateTask::propogateStepProgress);
qDebug() << m_inst->name() << ": Starting asset index download";
downloadJob->start();
@@ -83,6 +84,7 @@ void AssetUpdateTask::assetIndexFinished()
connect(downloadJob.get(), &NetJob::failed, this, &AssetUpdateTask::assetsFailed);
connect(downloadJob.get(), &NetJob::aborted, this, [this]{ emitFailed(tr("Aborted")); });
connect(downloadJob.get(), &NetJob::progress, this, &AssetUpdateTask::progress);
+ connect(downloadJob.get(), &NetJob::stepProgress, this, &AssetUpdateTask::propogateStepProgress);
downloadJob->start();
return;
}
diff --git a/launcher/minecraft/update/FMLLibrariesTask.cpp b/launcher/minecraft/update/FMLLibrariesTask.cpp
index 96fd3ba3..75e5c572 100644
--- a/launcher/minecraft/update/FMLLibrariesTask.cpp
+++ b/launcher/minecraft/update/FMLLibrariesTask.cpp
@@ -75,6 +75,7 @@ void FMLLibrariesTask::executeTask()
connect(dljob.get(), &NetJob::failed, this, &FMLLibrariesTask::fmllibsFailed);
connect(dljob.get(), &NetJob::aborted, this, [this]{ emitFailed(tr("Aborted")); });
connect(dljob.get(), &NetJob::progress, this, &FMLLibrariesTask::progress);
+ connect(dljob.get(), &NetJob::stepProgress, this, &FMLLibrariesTask::propogateStepProgress);
downloadJob.reset(dljob);
downloadJob->start();
}
diff --git a/launcher/minecraft/update/LibrariesTask.cpp b/launcher/minecraft/update/LibrariesTask.cpp
index b9410111..415b9a66 100644
--- a/launcher/minecraft/update/LibrariesTask.cpp
+++ b/launcher/minecraft/update/LibrariesTask.cpp
@@ -70,6 +70,8 @@ void LibrariesTask::executeTask()
connect(downloadJob.get(), &NetJob::failed, this, &LibrariesTask::jarlibFailed);
connect(downloadJob.get(), &NetJob::aborted, this, [this]{ emitFailed(tr("Aborted")); });
connect(downloadJob.get(), &NetJob::progress, this, &LibrariesTask::progress);
+ connect(downloadJob.get(), &NetJob::stepProgress, this, &LibrariesTask::propogateStepProgress);
+
downloadJob->start();
}