diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index cff07b4b..70997e51 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -318,6 +318,8 @@ set(MINECRAFT_SOURCES minecraft/mod/ModDetails.h minecraft/mod/ModFolderModel.h minecraft/mod/ModFolderModel.cpp + minecraft/mod/Resource.h + minecraft/mod/Resource.cpp minecraft/mod/ResourcePackFolderModel.h minecraft/mod/ResourcePackFolderModel.cpp minecraft/mod/TexturePackFolderModel.h diff --git a/launcher/MMCZip.cpp b/launcher/MMCZip.cpp index 04ca5094..9f4e968f 100644 --- a/launcher/MMCZip.cpp +++ b/launcher/MMCZip.cpp @@ -148,7 +148,7 @@ bool MMCZip::createModdedJar(QString sourceJarPath, QString targetJarPath, const // do not merge disabled mods. if (!mod->enabled()) continue; - if (mod->type() == Mod::MOD_ZIPFILE) + if (mod->type() == ResourceType::ZIPFILE) { if (!mergeZipFiles(&zipOut, mod->fileinfo(), addedFiles)) { @@ -158,7 +158,7 @@ bool MMCZip::createModdedJar(QString sourceJarPath, QString targetJarPath, const return false; } } - else if (mod->type() == Mod::MOD_SINGLEFILE) + else if (mod->type() == ResourceType::SINGLEFILE) { // FIXME: buggy - does not work with addedFiles auto filename = mod->fileinfo(); @@ -171,7 +171,7 @@ bool MMCZip::createModdedJar(QString sourceJarPath, QString targetJarPath, const } addedFiles.insert(filename.fileName()); } - else if (mod->type() == Mod::MOD_FOLDER) + else if (mod->type() == ResourceType::FOLDER) { // untested, but seems to be unused / not possible to reach // FIXME: buggy - does not work with addedFiles diff --git a/launcher/minecraft/MinecraftInstance.cpp b/launcher/minecraft/MinecraftInstance.cpp index c677b677..b42aeda3 100644 --- a/launcher/minecraft/MinecraftInstance.cpp +++ b/launcher/minecraft/MinecraftInstance.cpp @@ -714,7 +714,7 @@ QStringList MinecraftInstance::verboseDescription(AuthSessionPtr session, Minecr }); for(auto mod: modList) { - if(mod->type() == Mod::MOD_FOLDER) + if(mod->type() == ResourceType::FOLDER) { out << u8" [🖿] " + mod->fileinfo().completeBaseName() + " (folder)"; continue; diff --git a/launcher/minecraft/mod/Mod.cpp b/launcher/minecraft/mod/Mod.cpp index 588d76e3..f28fd32a 100644 --- a/launcher/minecraft/mod/Mod.cpp +++ b/launcher/minecraft/mod/Mod.cpp @@ -36,13 +36,10 @@ #include "Mod.h" +#include #include #include -#include -#include - -#include "Application.h" #include "MetadataHandler.h" namespace { @@ -51,75 +48,27 @@ ModDetails invalidDetails; } -Mod::Mod(const QFileInfo& file) +Mod::Mod(const QFileInfo& file) : Resource(file) { - repath(file); - m_changedDateTime = file.lastModified(); + m_enabled = (file.suffix() != "disabled"); } Mod::Mod(const QDir& mods_dir, const Metadata::ModStruct& metadata) - : m_file(mods_dir.absoluteFilePath(metadata.filename)) - , m_internal_id(metadata.filename) - , m_name(metadata.name) + : Mod(mods_dir.absoluteFilePath(metadata.filename)) { - if (m_file.isDir()) { - m_type = MOD_FOLDER; - } else { - if (metadata.filename.endsWith(".zip") || metadata.filename.endsWith(".jar")) - m_type = MOD_ZIPFILE; - else if (metadata.filename.endsWith(".litemod")) - m_type = MOD_LITEMOD; - else - m_type = MOD_SINGLEFILE; - } - - m_enabled = true; - m_changedDateTime = m_file.lastModified(); - + m_name = metadata.name; m_temp_metadata = std::make_shared(std::move(metadata)); } -void Mod::repath(const QFileInfo& file) -{ - m_file = file; - QString name_base = file.fileName(); - - m_type = Mod::MOD_UNKNOWN; - - m_internal_id = name_base; - - if (m_file.isDir()) { - m_type = MOD_FOLDER; - m_name = name_base; - } else if (m_file.isFile()) { - if (name_base.endsWith(".disabled")) { - m_enabled = false; - name_base.chop(9); - } else { - m_enabled = true; - } - if (name_base.endsWith(".zip") || name_base.endsWith(".jar")) { - m_type = MOD_ZIPFILE; - name_base.chop(4); - } else if (name_base.endsWith(".litemod")) { - m_type = MOD_LITEMOD; - name_base.chop(8); - } else { - m_type = MOD_SINGLEFILE; - } - m_name = name_base; - } -} - auto Mod::enable(bool value) -> bool { - if (m_type == Mod::MOD_UNKNOWN || m_type == Mod::MOD_FOLDER) + if (m_type == ResourceType::UNKNOWN || m_type == ResourceType::FOLDER) return false; if (m_enabled == value) return false; - QString path = m_file.absoluteFilePath(); + QString path = m_file_info.absoluteFilePath(); QFile file(path); if (value) { if (!path.endsWith(".disabled")) @@ -136,7 +85,7 @@ auto Mod::enable(bool value) -> bool } if (status() == ModStatus::NoMetadata) - repath(QFileInfo(path)); + setFile(QFileInfo(path)); m_enabled = value; return true; @@ -175,8 +124,7 @@ auto Mod::destroy(QDir& index_dir, bool preserve_metadata) -> bool } } - m_type = MOD_UNKNOWN; - return FS::deletePath(m_file.filePath()); + return Resource::destroy(); } auto Mod::details() const -> const ModDetails& @@ -239,8 +187,8 @@ auto Mod::metadata() const -> const std::shared_ptr void Mod::finishResolvingWithDetails(std::shared_ptr details) { - m_resolving = false; - m_resolved = true; + m_is_resolving = false; + m_is_resolved = true; m_localDetails = details; setStatus(m_temp_status); diff --git a/launcher/minecraft/mod/Mod.h b/launcher/minecraft/mod/Mod.h index 7a13e44b..313c478c 100644 --- a/launcher/minecraft/mod/Mod.h +++ b/launcher/minecraft/mod/Mod.h @@ -39,38 +39,23 @@ #include #include -#include "QObjectPtr.h" +#include "Resource.h" #include "ModDetails.h" -class Mod : public QObject +class Mod : public Resource { Q_OBJECT public: - enum ModType - { - MOD_UNKNOWN, //!< Indicates an unspecified mod type. - MOD_ZIPFILE, //!< The mod is a zip file containing the mod's class files. - MOD_SINGLEFILE, //!< The mod is a single file (not a zip file). - MOD_FOLDER, //!< The mod is in a folder on the filesystem. - MOD_LITEMOD, //!< The mod is a litemod - }; - using Ptr = shared_qobject_ptr; Mod() = default; Mod(const QFileInfo &file); explicit Mod(const QDir& mods_dir, const Metadata::ModStruct& metadata); - auto fileinfo() const -> QFileInfo { return m_file; } - auto dateTimeChanged() const -> QDateTime { return m_changedDateTime; } - auto internal_id() const -> QString { return m_internal_id; } - auto type() const -> ModType { return m_type; } auto enabled() const -> bool { return m_enabled; } - auto valid() const -> bool { return m_type != MOD_UNKNOWN; } - auto details() const -> const ModDetails&; - auto name() const -> QString; + auto name() const -> QString override; auto version() const -> QString; auto homeurl() const -> QString; auto description() const -> QString; @@ -85,31 +70,12 @@ public: auto enable(bool value) -> bool; - // delete all the files of this mod + // Delete all the files of this mod auto destroy(QDir& index_dir, bool preserve_metadata = false) -> bool; - // change the mod's filesystem path (used by mod lists for *MAGIC* purposes) - void repath(const QFileInfo &file); - - auto shouldResolve() const -> bool { return !m_resolving && !m_resolved; } - auto isResolving() const -> bool { return m_resolving; } - auto resolutionTicket() const -> int { return m_resolutionTicket; } - - void setResolving(bool resolving, int resolutionTicket) { - m_resolving = resolving; - m_resolutionTicket = resolutionTicket; - } void finishResolvingWithDetails(std::shared_ptr details); protected: - QFileInfo m_file; - QDateTime m_changedDateTime; - - QString m_internal_id; - /* Name as reported via the file name */ - QString m_name; - ModType m_type = MOD_UNKNOWN; - /* If the mod has metadata, this will be filled in the constructor, and passed to * the ModDetails when calling finishResolvingWithDetails */ std::shared_ptr m_temp_metadata; @@ -120,7 +86,4 @@ protected: std::shared_ptr m_localDetails; bool m_enabled = true; - bool m_resolving = false; - bool m_resolved = false; - int m_resolutionTicket = 0; }; diff --git a/launcher/minecraft/mod/Resource.cpp b/launcher/minecraft/mod/Resource.cpp new file mode 100644 index 00000000..8771a20f --- /dev/null +++ b/launcher/minecraft/mod/Resource.cpp @@ -0,0 +1,53 @@ +#include "Resource.h" + +#include "FileSystem.h" + +Resource::Resource(QObject* parent) : QObject(parent) {} + +Resource::Resource(QFileInfo file_info) : QObject() +{ + setFile(file_info); +} + +void Resource::setFile(QFileInfo file_info) +{ + m_file_info = file_info; + parseFile(); +} + +void Resource::parseFile() +{ + QString file_name{ m_file_info.fileName() }; + + m_type = ResourceType::UNKNOWN; + + m_internal_id = file_name; + + if (m_file_info.isDir()) { + m_type = ResourceType::FOLDER; + m_name = file_name; + } else if (m_file_info.isFile()) { + if (file_name.endsWith(".disabled")) + file_name.chop(9); + + if (file_name.endsWith(".zip") || file_name.endsWith(".jar")) { + m_type = ResourceType::ZIPFILE; + file_name.chop(4); + } else if (file_name.endsWith(".litemod")) { + m_type = ResourceType::LITEMOD; + file_name.chop(8); + } else { + m_type = ResourceType::SINGLEFILE; + } + + m_name = file_name; + } + + m_changed_date_time = m_file_info.lastModified(); +} + +bool Resource::destroy() +{ + m_type = ResourceType::UNKNOWN; + return FS::deletePath(m_file_info.filePath()); +} diff --git a/launcher/minecraft/mod/Resource.h b/launcher/minecraft/mod/Resource.h new file mode 100644 index 00000000..c348c7e2 --- /dev/null +++ b/launcher/minecraft/mod/Resource.h @@ -0,0 +1,74 @@ +#pragma once + +#include +#include +#include + +#include "QObjectPtr.h" + +enum class ResourceType { + UNKNOWN, //!< Indicates an unspecified resource type. + ZIPFILE, //!< The resource is a zip file containing the resource's class files. + SINGLEFILE, //!< The resource is a single file (not a zip file). + FOLDER, //!< The resource is in a folder on the filesystem. + LITEMOD, //!< The resource is a litemod +}; + +/** General class for managed resources. It mirrors a file in disk, with some more info + * for display and house-keeping purposes. + * + * Subclass it to add additional data / behavior, such as Mods or Resource packs. + */ +class Resource : public QObject { + Q_OBJECT + Q_DISABLE_COPY(Resource) + public: + using Ptr = shared_qobject_ptr; + + Resource(QObject* parent = nullptr); + Resource(QFileInfo file_info); + ~Resource() override = default; + + void setFile(QFileInfo file_info); + void parseFile(); + + [[nodiscard]] auto fileinfo() const -> QFileInfo { return m_file_info; } + [[nodiscard]] auto dateTimeChanged() const -> QDateTime { return m_changed_date_time; } + [[nodiscard]] auto internal_id() const -> QString { return m_internal_id; } + [[nodiscard]] auto type() const -> ResourceType { return m_type; } + + [[nodiscard]] virtual auto name() const -> QString { return m_name; } + [[nodiscard]] virtual bool valid() const { return m_type != ResourceType::UNKNOWN; } + + [[nodiscard]] auto shouldResolve() const -> bool { return !m_is_resolving && !m_is_resolved; } + [[nodiscard]] auto isResolving() const -> bool { return m_is_resolving; } + [[nodiscard]] auto resolutionTicket() const -> int { return m_resolution_ticket; } + + void setResolving(bool resolving, int resolutionTicket) + { + m_is_resolving = resolving; + m_resolution_ticket = resolutionTicket; + } + + // Delete all files of this resource. + bool destroy(); + + protected: + /* The file corresponding to this resource. */ + QFileInfo m_file_info; + /* The cached date when this file was last changed. */ + QDateTime m_changed_date_time; + + /* Internal ID for internal purposes. Properties such as human-readability should not be assumed. */ + QString m_internal_id; + /* Name as reported via the file name. In the absence of a better name, this is shown to the user. */ + QString m_name; + + /* The type of file we're dealing with. */ + ResourceType m_type = ResourceType::UNKNOWN; + + /* Used to keep trach of pending / concluded actions on the resource. */ + bool m_is_resolving = false; + bool m_is_resolved = false; + int m_resolution_ticket = 0; +}; diff --git a/launcher/modplatform/EnsureMetadataTask.cpp b/launcher/modplatform/EnsureMetadataTask.cpp index 60c54c4e..21c20b28 100644 --- a/launcher/modplatform/EnsureMetadataTask.cpp +++ b/launcher/modplatform/EnsureMetadataTask.cpp @@ -110,7 +110,7 @@ void EnsureMetadataTask::executeTask() } // Folders don't have metadata - if (mod->type() == Mod::MOD_FOLDER) { + if (mod->type() == ResourceType::FOLDER) { emitReady(mod); } } diff --git a/launcher/ui/widgets/MCModInfoFrame.cpp b/launcher/ui/widgets/MCModInfoFrame.cpp index 7d78006b..22475abc 100644 --- a/launcher/ui/widgets/MCModInfoFrame.cpp +++ b/launcher/ui/widgets/MCModInfoFrame.cpp @@ -23,7 +23,7 @@ void MCModInfoFrame::updateWithMod(Mod &m) { - if (m.type() == m.MOD_FOLDER) + if (m.type() == ResourceType::FOLDER) { clear(); return;