diff options
Diffstat (limited to 'launcher/minecraft')
-rw-r--r-- | launcher/minecraft/MinecraftInstance.cpp | 12 | ||||
-rw-r--r-- | launcher/minecraft/mod/MetadataHandler.h | 59 | ||||
-rw-r--r-- | launcher/minecraft/mod/Mod.cpp | 205 | ||||
-rw-r--r-- | launcher/minecraft/mod/Mod.h | 141 | ||||
-rw-r--r-- | launcher/minecraft/mod/ModDetails.h | 66 | ||||
-rw-r--r-- | launcher/minecraft/mod/ModFolderLoadTask.cpp | 18 | ||||
-rw-r--r-- | launcher/minecraft/mod/ModFolderLoadTask.h | 29 | ||||
-rw-r--r-- | launcher/minecraft/mod/ModFolderModel.cpp | 38 | ||||
-rw-r--r-- | launcher/minecraft/mod/ModFolderModel.h | 11 | ||||
-rw-r--r-- | launcher/minecraft/mod/tasks/LocalModParseTask.cpp (renamed from launcher/minecraft/mod/LocalModParseTask.cpp) | 22 | ||||
-rw-r--r-- | launcher/minecraft/mod/tasks/LocalModParseTask.h (renamed from launcher/minecraft/mod/LocalModParseTask.h) | 8 | ||||
-rw-r--r-- | launcher/minecraft/mod/tasks/LocalModUpdateTask.cpp | 53 | ||||
-rw-r--r-- | launcher/minecraft/mod/tasks/LocalModUpdateTask.h | 44 | ||||
-rw-r--r-- | launcher/minecraft/mod/tasks/ModFolderLoadTask.cpp | 82 | ||||
-rw-r--r-- | launcher/minecraft/mod/tasks/ModFolderLoadTask.h | 69 |
15 files changed, 627 insertions, 230 deletions
diff --git a/launcher/minecraft/MinecraftInstance.cpp b/launcher/minecraft/MinecraftInstance.cpp index 61326fac..e99d30fe 100644 --- a/launcher/minecraft/MinecraftInstance.cpp +++ b/launcher/minecraft/MinecraftInstance.cpp @@ -168,6 +168,8 @@ MinecraftInstance::MinecraftInstance(SettingsObjectPtr globalSettings, SettingsO m_settings->registerOverride(globalSettings->getSetting("CloseAfterLaunch"), miscellaneousOverride); m_settings->registerOverride(globalSettings->getSetting("QuitAfterGameStop"), miscellaneousOverride); + m_settings->set("InstanceType", "OneSix"); + m_components.reset(new PackProfile(this)); } @@ -659,23 +661,23 @@ QStringList MinecraftInstance::verboseDescription(AuthSessionPtr session, Minecr out << QString("%1:").arg(label); auto modList = model.allMods(); std::sort(modList.begin(), modList.end(), [](Mod &a, Mod &b) { - auto aName = a.filename().completeBaseName(); - auto bName = b.filename().completeBaseName(); + auto aName = a.fileinfo().completeBaseName(); + auto bName = b.fileinfo().completeBaseName(); return aName.localeAwareCompare(bName) < 0; }); for(auto & mod: modList) { if(mod.type() == Mod::MOD_FOLDER) { - out << u8" [📁] " + mod.filename().completeBaseName() + " (folder)"; + out << u8" [📁] " + mod.fileinfo().completeBaseName() + " (folder)"; continue; } if(mod.enabled()) { - out << u8" [✔️] " + mod.filename().completeBaseName(); + out << u8" [✔️] " + mod.fileinfo().completeBaseName(); } else { - out << u8" [❌] " + mod.filename().completeBaseName() + " (disabled)"; + out << u8" [❌] " + mod.fileinfo().completeBaseName() + " (disabled)"; } } diff --git a/launcher/minecraft/mod/MetadataHandler.h b/launcher/minecraft/mod/MetadataHandler.h new file mode 100644 index 00000000..56962818 --- /dev/null +++ b/launcher/minecraft/mod/MetadataHandler.h @@ -0,0 +1,59 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* +* PolyMC - Minecraft Launcher +* Copyright (c) 2022 flowln <flowlnlnln@gmail.com> +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, version 3. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include <memory> + +#include "modplatform/packwiz/Packwiz.h" + +// launcher/minecraft/mod/Mod.h +class Mod; + +/* Abstraction file for easily changing the way metadata is stored / handled + * Needs to be a class because of -Wunused-function and no C++17 [[maybe_unused]] + * */ +class Metadata { + public: + using ModStruct = Packwiz::V1::Mod; + + static auto create(QDir& index_dir, ModPlatform::IndexedPack& mod_pack, ModPlatform::IndexedVersion& mod_version) -> ModStruct + { + return Packwiz::V1::createModFormat(index_dir, mod_pack, mod_version); + } + + static auto create(QDir& index_dir, Mod& internal_mod) -> ModStruct + { + return Packwiz::V1::createModFormat(index_dir, internal_mod); + } + + static void update(QDir& index_dir, ModStruct& mod) + { + Packwiz::V1::updateModIndex(index_dir, mod); + } + + static void remove(QDir& index_dir, QString& mod_name) + { + Packwiz::V1::deleteModIndex(index_dir, mod_name); + } + + static auto get(QDir& index_dir, QString& mod_name) -> ModStruct + { + return Packwiz::V1::getIndexForMod(index_dir, mod_name); + } +}; diff --git a/launcher/minecraft/mod/Mod.cpp b/launcher/minecraft/mod/Mod.cpp index b6bff29b..71a32d32 100644 --- a/launcher/minecraft/mod/Mod.cpp +++ b/launcher/minecraft/mod/Mod.cpp @@ -1,24 +1,48 @@ -/* Copyright 2013-2021 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// SPDX-License-Identifier: GPL-3.0-only +/* +* PolyMC - Minecraft Launcher +* Copyright (c) 2022 flowln <flowlnlnln@gmail.com> +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, version 3. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <https://www.gnu.org/licenses/>. +* +* This file incorporates work covered by the following copyright and +* permission notice: +* +* Copyright 2013-2021 MultiMC Contributors +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "Mod.h" #include <QDir> #include <QString> -#include "Mod.h" -#include <QDebug> #include <FileSystem.h> +#include <QDebug> + +#include "Application.h" +#include "MetadataHandler.h" namespace { @@ -26,57 +50,69 @@ ModDetails invalidDetails; } - -Mod::Mod(const QFileInfo &file) +Mod::Mod(const QFileInfo& file) { repath(file); m_changedDateTime = file.lastModified(); } -void Mod::repath(const QFileInfo &file) +Mod::Mod(const QDir& mods_dir, const Metadata::ModStruct& metadata) + : m_file(mods_dir.absoluteFilePath(metadata.filename)) + // It is weird, but name is not reliable for comparing with the JAR files name + // FIXME: Maybe use hash when implemented? + , m_internal_id(metadata.filename) + , m_name(metadata.name) +{ + 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_temp_metadata = std::make_shared<Metadata::ModStruct>(std::move(metadata)); +} + +void Mod::repath(const QFileInfo& file) { m_file = file; QString name_base = file.fileName(); m_type = Mod::MOD_UNKNOWN; - m_mmc_id = name_base; + m_internal_id = name_base; - if (m_file.isDir()) - { + if (m_file.isDir()) { m_type = MOD_FOLDER; m_name = name_base; - } - else if (m_file.isFile()) - { - if (name_base.endsWith(".disabled")) - { + } else if (m_file.isFile()) { + if (name_base.endsWith(".disabled")) { m_enabled = false; name_base.chop(9); - } - else - { + } else { m_enabled = true; } - if (name_base.endsWith(".zip") || name_base.endsWith(".jar")) - { + if (name_base.endsWith(".zip") || name_base.endsWith(".jar")) { m_type = MOD_ZIPFILE; name_base.chop(4); - } - else if (name_base.endsWith(".litemod")) - { + } else if (name_base.endsWith(".litemod")) { m_type = MOD_LITEMOD; name_base.chop(8); - } - else - { + } else { m_type = MOD_SINGLEFILE; } m_name = name_base; } } -bool Mod::enable(bool value) +auto Mod::enable(bool value) -> bool { if (m_type == Mod::MOD_UNKNOWN || m_type == Mod::MOD_FOLDER) return false; @@ -85,67 +121,104 @@ bool Mod::enable(bool value) return false; QString path = m_file.absoluteFilePath(); - if (value) - { - QFile foo(path); + QFile file(path); + if (value) { if (!path.endsWith(".disabled")) return false; path.chop(9); - if (!foo.rename(path)) + + if (!file.rename(path)) return false; - } - else - { - QFile foo(path); + } else { path += ".disabled"; - if (!foo.rename(path)) + + if (!file.rename(path)) return false; } - repath(QFileInfo(path)); + + if (status() == ModStatus::NoMetadata) + repath(QFileInfo(path)); + m_enabled = value; return true; } -bool Mod::destroy() +void Mod::setStatus(ModStatus status) { - m_type = MOD_UNKNOWN; - return FS::deletePath(m_file.filePath()); + if(m_localDetails.get()) + m_localDetails->status = status; } +void Mod::setMetadata(Metadata::ModStruct* metadata) +{ + if(status() == ModStatus::NoMetadata) + setStatus(ModStatus::Installed); + if(m_localDetails.get()) + m_localDetails->metadata.reset(metadata); +} -const ModDetails & Mod::details() const +auto Mod::destroy(QDir& index_dir) -> bool { - if(!m_localDetails) - return invalidDetails; - return *m_localDetails; -} + auto n = name(); + // FIXME: This can fail to remove the metadata if the + // "DontUseModMetadata" setting is on, since there could + // be a name mismatch! + Metadata::remove(index_dir, n); + m_type = MOD_UNKNOWN; + return FS::deletePath(m_file.filePath()); +} -QString Mod::version() const +auto Mod::details() const -> const ModDetails& { - return details().version; + return m_localDetails ? *m_localDetails : invalidDetails; } -QString Mod::name() const +auto Mod::name() const -> QString { - auto & d = details(); - if(!d.name.isEmpty()) { - return d.name; + auto d_name = details().name; + if (!d_name.isEmpty()) { + return d_name; } return m_name; } -QString Mod::homeurl() const +auto Mod::version() const -> QString +{ + return details().version; +} + +auto Mod::homeurl() const -> QString { return details().homeurl; } -QString Mod::description() const +auto Mod::description() const -> QString { return details().description; } -QStringList Mod::authors() const +auto Mod::authors() const -> QStringList { return details().authors; } + +auto Mod::status() const -> ModStatus +{ + return details().status; +} + +void Mod::finishResolvingWithDetails(std::shared_ptr<ModDetails> details) +{ + m_resolving = false; + m_resolved = true; + m_localDetails = details; + + if (status() != ModStatus::NoMetadata + && m_temp_metadata.get() + && m_temp_metadata->isValid() && + m_localDetails.get()) { + + m_localDetails->metadata.swap(m_temp_metadata); + } +} diff --git a/launcher/minecraft/mod/Mod.h b/launcher/minecraft/mod/Mod.h index 921faeb1..96d471b4 100644 --- a/launcher/minecraft/mod/Mod.h +++ b/launcher/minecraft/mod/Mod.h @@ -1,28 +1,46 @@ -/* Copyright 2013-2021 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ +// SPDX-License-Identifier: GPL-3.0-only +/* +* PolyMC - Minecraft Launcher +* Copyright (c) 2022 flowln <flowlnlnln@gmail.com> +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, version 3. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <https://www.gnu.org/licenses/>. +* +* This file incorporates work covered by the following copyright and +* permission notice: +* +* Copyright 2013-2021 MultiMC Contributors +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ #pragma once -#include <QFileInfo> + #include <QDateTime> +#include <QFileInfo> #include <QList> -#include <memory> #include "ModDetails.h" - - class Mod { public: @@ -32,84 +50,69 @@ public: 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 + MOD_LITEMOD, //!< The mod is a litemod }; Mod() = default; Mod(const QFileInfo &file); + explicit Mod(const QDir& mods_dir, const Metadata::ModStruct& metadata); - QFileInfo filename() const - { - return m_file; - } - QString mmc_id() const - { - return m_mmc_id; - } - ModType type() const - { - return m_type; - } - bool valid() - { - return m_type != MOD_UNKNOWN; - } + 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; } - QDateTime dateTimeChanged() const - { - return m_changedDateTime; - } + auto valid() const -> bool { return m_type != MOD_UNKNOWN; } - bool enabled() const - { - return m_enabled; - } + auto details() const -> const ModDetails&; + auto name() const -> QString; + auto version() const -> QString; + auto homeurl() const -> QString; + auto description() const -> QString; + auto authors() const -> QStringList; + auto status() const -> ModStatus; - const ModDetails &details() const; + auto metadata() const -> const std::shared_ptr<Metadata::ModStruct> { return details().metadata; }; + auto metadata() -> std::shared_ptr<Metadata::ModStruct> { return m_localDetails->metadata; }; - QString name() const; - QString version() const; - QString homeurl() const; - QString description() const; - QStringList authors() const; + void setStatus(ModStatus status); + void setMetadata(Metadata::ModStruct* metadata); - bool enable(bool value); + auto enable(bool value) -> bool; // delete all the files of this mod - bool destroy(); + auto destroy(QDir& index_dir) -> bool; // change the mod's filesystem path (used by mod lists for *MAGIC* purposes) void repath(const QFileInfo &file); - bool shouldResolve() { - return !m_resolving && !m_resolved; - } - bool isResolving() { - return m_resolving; - } - int resolutionTicket() - { - return m_resolutionTicket; - } + 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<ModDetails> details){ - m_resolving = false; - m_resolved = true; - m_localDetails = details; - } + void finishResolvingWithDetails(std::shared_ptr<ModDetails> details); protected: QFileInfo m_file; QDateTime m_changedDateTime; - QString m_mmc_id; + + 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<Metadata::ModStruct> m_temp_metadata; + std::shared_ptr<ModDetails> m_localDetails; + bool m_enabled = true; bool m_resolving = false; bool m_resolved = false; int m_resolutionTicket = 0; - ModType m_type = MOD_UNKNOWN; - std::shared_ptr<ModDetails> m_localDetails; }; diff --git a/launcher/minecraft/mod/ModDetails.h b/launcher/minecraft/mod/ModDetails.h index 6ab4aee7..3e0a7ab0 100644 --- a/launcher/minecraft/mod/ModDetails.h +++ b/launcher/minecraft/mod/ModDetails.h @@ -1,17 +1,79 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* +* PolyMC - Minecraft Launcher +* Copyright (c) 2022 flowln <flowlnlnln@gmail.com> +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, version 3. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <https://www.gnu.org/licenses/>. +* +* This file incorporates work covered by the following copyright and +* permission notice: +* +* Copyright 2013-2021 MultiMC Contributors +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + #pragma once +#include <memory> + #include <QString> #include <QStringList> +#include "minecraft/mod/MetadataHandler.h" + +enum class ModStatus { + Installed, // Both JAR and Metadata are present + NotInstalled, // Only the Metadata is present + NoMetadata, // Only the JAR is present +}; + struct ModDetails { + /* Mod ID as defined in the ModLoader-specific metadata */ QString mod_id; + + /* Human-readable name */ QString name; + + /* Human-readable mod version */ QString version; + + /* Human-readable minecraft version */ QString mcversion; + + /* URL for mod's home page */ QString homeurl; - QString updateurl; + + /* Human-readable description */ QString description; + + /* List of the author's names */ QStringList authors; - QString credits; + + /* Installation status of the mod */ + ModStatus status; + + /* Metadata information, if any */ + std::shared_ptr<Metadata::ModStruct> metadata; }; diff --git a/launcher/minecraft/mod/ModFolderLoadTask.cpp b/launcher/minecraft/mod/ModFolderLoadTask.cpp deleted file mode 100644 index 88349877..00000000 --- a/launcher/minecraft/mod/ModFolderLoadTask.cpp +++ /dev/null @@ -1,18 +0,0 @@ -#include "ModFolderLoadTask.h" -#include <QDebug> - -ModFolderLoadTask::ModFolderLoadTask(QDir dir) : - m_dir(dir), m_result(new Result()) -{ -} - -void ModFolderLoadTask::run() -{ - m_dir.refresh(); - for (auto entry : m_dir.entryInfoList()) - { - Mod m(entry); - m_result->mods[m.mmc_id()] = m; - } - emit succeeded(); -} diff --git a/launcher/minecraft/mod/ModFolderLoadTask.h b/launcher/minecraft/mod/ModFolderLoadTask.h deleted file mode 100644 index 8d720e65..00000000 --- a/launcher/minecraft/mod/ModFolderLoadTask.h +++ /dev/null @@ -1,29 +0,0 @@ -#pragma once -#include <QRunnable> -#include <QObject> -#include <QDir> -#include <QMap> -#include "Mod.h" -#include <memory> - -class ModFolderLoadTask : public QObject, public QRunnable -{ - Q_OBJECT -public: - struct Result { - QMap<QString, Mod> mods; - }; - using ResultPtr = std::shared_ptr<Result>; - ResultPtr result() const { - return m_result; - } - -public: - ModFolderLoadTask(QDir dir); - void run(); -signals: - void succeeded(); -private: - QDir m_dir; - ResultPtr m_result; -}; diff --git a/launcher/minecraft/mod/ModFolderModel.cpp b/launcher/minecraft/mod/ModFolderModel.cpp index f0c53c39..b2d8f03e 100644 --- a/launcher/minecraft/mod/ModFolderModel.cpp +++ b/launcher/minecraft/mod/ModFolderModel.cpp @@ -14,17 +14,19 @@ */ #include "ModFolderModel.h" + #include <FileSystem.h> +#include <QDebug> +#include <QFileSystemWatcher> #include <QMimeData> -#include <QUrl> -#include <QUuid> #include <QString> -#include <QFileSystemWatcher> -#include <QDebug> -#include "ModFolderLoadTask.h" #include <QThreadPool> +#include <QUrl> +#include <QUuid> #include <algorithm> -#include "LocalModParseTask.h" + +#include "minecraft/mod/tasks/LocalModParseTask.h" +#include "minecraft/mod/tasks/ModFolderLoadTask.h" ModFolderModel::ModFolderModel(const QString &dir) : QAbstractListModel(), m_dir(dir) { @@ -79,10 +81,14 @@ bool ModFolderModel::update() return true; } - auto task = new ModFolderLoadTask(m_dir); + auto index_dir = indexDir(); + auto task = new ModFolderLoadTask(dir(), index_dir); + m_update = task->result(); + QThreadPool *threadPool = QThreadPool::globalInstance(); connect(task, &ModFolderLoadTask::succeeded, this, &ModFolderModel::finishUpdate); + threadPool->start(task); return true; } @@ -153,7 +159,7 @@ void ModFolderModel::finishUpdate() modsIndex.clear(); int idx = 0; for(auto & mod: mods) { - modsIndex[mod.mmc_id()] = idx; + modsIndex[mod.internal_id()] = idx; idx++; } } @@ -174,9 +180,9 @@ void ModFolderModel::resolveMod(Mod& m) return; } - auto task = new LocalModParseTask(nextResolutionTicket, m.type(), m.filename()); + auto task = new LocalModParseTask(nextResolutionTicket, m.type(), m.fileinfo()); auto result = task->result(); - result->id = m.mmc_id(); + result->id = m.internal_id(); activeTickets.insert(nextResolutionTicket, result); m.setResolving(true, nextResolutionTicket); nextResolutionTicket++; @@ -333,8 +339,12 @@ bool ModFolderModel::deleteMods(const QModelIndexList& indexes) for (auto i: indexes) { + if(i.column() != 0) { + continue; + } Mod &m = mods[i.row()]; - m.destroy(); + auto index_dir = indexDir(); + m.destroy(index_dir); } return true; } @@ -381,7 +391,7 @@ QVariant ModFolderModel::data(const QModelIndex &index, int role) const } case Qt::ToolTipRole: - return mods[row].mmc_id(); + return mods[row].internal_id(); case Qt::CheckStateRole: switch (column) @@ -436,11 +446,11 @@ bool ModFolderModel::setModStatus(int row, ModFolderModel::ModStatusAction actio } // preserve the row, but change its ID - auto oldId = mod.mmc_id(); + auto oldId = mod.internal_id(); if(!mod.enable(!mod.enabled())) { return false; } - auto newId = mod.mmc_id(); + auto newId = mod.internal_id(); if(modsIndex.contains(newId)) { // NOTE: this could handle a corner case, where we are overwriting a file, because the same 'mod' exists both enabled and disabled // But is it necessary? diff --git a/launcher/minecraft/mod/ModFolderModel.h b/launcher/minecraft/mod/ModFolderModel.h index 62c504df..10a72691 100644 --- a/launcher/minecraft/mod/ModFolderModel.h +++ b/launcher/minecraft/mod/ModFolderModel.h @@ -24,8 +24,8 @@ #include "Mod.h" -#include "ModFolderLoadTask.h" -#include "LocalModParseTask.h" +#include "minecraft/mod/tasks/ModFolderLoadTask.h" +#include "minecraft/mod/tasks/LocalModParseTask.h" class LegacyInstance; class BaseInstance; @@ -108,11 +108,16 @@ public: bool isValid(); - QDir dir() + QDir& dir() { return m_dir; } + QDir indexDir() + { + return { QString("%1/.index").arg(dir().absolutePath()) }; + } + const QList<Mod> & allMods() { return mods; diff --git a/launcher/minecraft/mod/LocalModParseTask.cpp b/launcher/minecraft/mod/tasks/LocalModParseTask.cpp index a7bec5ae..3354732b 100644 --- a/launcher/minecraft/mod/LocalModParseTask.cpp +++ b/launcher/minecraft/mod/tasks/LocalModParseTask.cpp @@ -35,7 +35,6 @@ std::shared_ptr<ModDetails> ReadMCModInfo(QByteArray contents) details->name = name; } details->version = firstObj.value("version").toString(); - details->updateurl = firstObj.value("updateUrl").toString(); auto homeurl = firstObj.value("url").toString().trimmed(); if(!homeurl.isEmpty()) { @@ -57,7 +56,6 @@ std::shared_ptr<ModDetails> ReadMCModInfo(QByteArray contents) { details->authors.append(author.toString()); } - details->credits = firstObj.value("credits").toString(); return details; }; QJsonParseError jsonError; @@ -168,27 +166,9 @@ std::shared_ptr<ModDetails> ReadMCModTOML(QByteArray contents) } if(!authors.isEmpty()) { - // author information is stored as a string now, not a list details->authors.append(authors); } - // is credits even used anywhere? including this for completion/parity with old data version - toml_datum_t creditsDatum = toml_string_in(tomlData, "credits"); - QString credits = ""; - if(creditsDatum.ok) - { - authors = creditsDatum.u.s; - free(creditsDatum.u.s); - } - else - { - creditsDatum = toml_string_in(tomlModsTable0, "credits"); - if(creditsDatum.ok) - { - credits = creditsDatum.u.s; - free(creditsDatum.u.s); - } - } - details->credits = credits; + toml_datum_t homeurlDatum = toml_string_in(tomlData, "displayURL"); QString homeurl = ""; if(homeurlDatum.ok) diff --git a/launcher/minecraft/mod/LocalModParseTask.h b/launcher/minecraft/mod/tasks/LocalModParseTask.h index 0f119ba6..ed92394c 100644 --- a/launcher/minecraft/mod/LocalModParseTask.h +++ b/launcher/minecraft/mod/tasks/LocalModParseTask.h @@ -1,9 +1,11 @@ #pragma once -#include <QRunnable> + #include <QDebug> #include <QObject> -#include "Mod.h" -#include "ModDetails.h" +#include <QRunnable> + +#include "minecraft/mod/Mod.h" +#include "minecraft/mod/ModDetails.h" class LocalModParseTask : public QObject, public QRunnable { diff --git a/launcher/minecraft/mod/tasks/LocalModUpdateTask.cpp b/launcher/minecraft/mod/tasks/LocalModUpdateTask.cpp new file mode 100644 index 00000000..cbe16567 --- /dev/null +++ b/launcher/minecraft/mod/tasks/LocalModUpdateTask.cpp @@ -0,0 +1,53 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* +* PolyMC - Minecraft Launcher +* Copyright (c) 2022 flowln <flowlnlnln@gmail.com> +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, version 3. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#include "LocalModUpdateTask.h" + +#include "Application.h" +#include "FileSystem.h" +#include "minecraft/mod/MetadataHandler.h" + +LocalModUpdateTask::LocalModUpdateTask(QDir index_dir, ModPlatform::IndexedPack& mod, ModPlatform::IndexedVersion& mod_version) + : m_index_dir(index_dir), m_mod(mod), m_mod_version(mod_version) +{ + // Ensure a '.index' folder exists in the mods folder, and create it if it does not + if (!FS::ensureFolderPathExists(index_dir.path())) { + emitFailed(QString("Unable to create index for mod %1!").arg(m_mod.name)); + } +} + +void LocalModUpdateTask::executeTask() +{ + setStatus(tr("Updating index for mod:\n%1").arg(m_mod.name)); + + if(APPLICATION->settings()->get("DontUseModMetadata").toBool()){ + emitSucceeded(); + return; + } + + auto pw_mod = Metadata::create(m_index_dir, m_mod, m_mod_version); + Metadata::update(m_index_dir, pw_mod); + + emitSucceeded(); +} + +auto LocalModUpdateTask::abort() -> bool +{ + emitAborted(); + return true; +} diff --git a/launcher/minecraft/mod/tasks/LocalModUpdateTask.h b/launcher/minecraft/mod/tasks/LocalModUpdateTask.h new file mode 100644 index 00000000..2db183e0 --- /dev/null +++ b/launcher/minecraft/mod/tasks/LocalModUpdateTask.h @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* +* PolyMC - Minecraft Launcher +* Copyright (c) 2022 flowln <flowlnlnln@gmail.com> +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, version 3. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <https://www.gnu.org/licenses/>. +*/ + +#pragma once + +#include <QDir> + +#include "modplatform/ModIndex.h" +#include "tasks/Task.h" + +class LocalModUpdateTask : public Task { + Q_OBJECT + public: + using Ptr = shared_qobject_ptr<LocalModUpdateTask>; + + explicit LocalModUpdateTask(QDir index_dir, ModPlatform::IndexedPack& mod, ModPlatform::IndexedVersion& mod_version); + + auto canAbort() const -> bool override { return true; } + auto abort() -> bool override; + + protected slots: + //! Entry point for tasks. + void executeTask() override; + + private: + QDir m_index_dir; + ModPlatform::IndexedPack& m_mod; + ModPlatform::IndexedVersion& m_mod_version; +}; diff --git a/launcher/minecraft/mod/tasks/ModFolderLoadTask.cpp b/launcher/minecraft/mod/tasks/ModFolderLoadTask.cpp new file mode 100644 index 00000000..62d856f6 --- /dev/null +++ b/launcher/minecraft/mod/tasks/ModFolderLoadTask.cpp @@ -0,0 +1,82 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* +* PolyMC - Minecraft Launcher +* Copyright (c) 2022 flowln <flowlnlnln@gmail.com> +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, version 3. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <https://www.gnu.org/licenses/>. +* +* This file incorporates work covered by the following copyright and +* permission notice: +* +* Copyright 2013-2021 MultiMC Contributors +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#include "ModFolderLoadTask.h" + +#include "Application.h" +#include "minecraft/mod/MetadataHandler.h" + +ModFolderLoadTask::ModFolderLoadTask(QDir& mods_dir, QDir& index_dir) + : m_mods_dir(mods_dir), m_index_dir(index_dir), m_result(new Result()) +{} + +void ModFolderLoadTask::run() +{ + if (!APPLICATION->settings()->get("ModMetadataDisabled").toBool()) { + // Read metadata first + getFromMetadata(); + } + + // Read JAR files that don't have metadata + m_mods_dir.refresh(); + for (auto entry : m_mods_dir.entryInfoList()) { + Mod mod(entry); + if(m_result->mods.contains(mod.internal_id())){ + m_result->mods[mod.internal_id()].setStatus(ModStatus::Installed); + } + else { + m_result->mods[mod.internal_id()] = mod; + m_result->mods[mod.internal_id()].setStatus(ModStatus::NoMetadata); + } + } + + emit succeeded(); +} + +void ModFolderLoadTask::getFromMetadata() +{ + m_index_dir.refresh(); + for (auto entry : m_index_dir.entryList(QDir::Files)) { + auto metadata = Metadata::get(m_index_dir, entry); + + if(!metadata.isValid()){ + return; + } + + Mod mod(m_mods_dir, metadata); + mod.setStatus(ModStatus::NotInstalled); + m_result->mods[mod.internal_id()] = mod; + } +} diff --git a/launcher/minecraft/mod/tasks/ModFolderLoadTask.h b/launcher/minecraft/mod/tasks/ModFolderLoadTask.h new file mode 100644 index 00000000..89a0f84e --- /dev/null +++ b/launcher/minecraft/mod/tasks/ModFolderLoadTask.h @@ -0,0 +1,69 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* +* PolyMC - Minecraft Launcher +* Copyright (c) 2022 flowln <flowlnlnln@gmail.com> +* +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as published by +* the Free Software Foundation, version 3. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program. If not, see <https://www.gnu.org/licenses/>. +* +* This file incorporates work covered by the following copyright and +* permission notice: +* +* Copyright 2013-2021 MultiMC Contributors +* +* Licensed under the Apache License, Version 2.0 (the "License"); +* you may not use this file except in compliance with the License. +* You may obtain a copy of the License at +* +* http://www.apache.org/licenses/LICENSE-2.0 +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific language governing permissions and +* limitations under the License. +*/ + +#pragma once + +#include <QDir> +#include <QMap> +#include <QObject> +#include <QRunnable> +#include <memory> +#include "minecraft/mod/Mod.h" + +class ModFolderLoadTask : public QObject, public QRunnable +{ + Q_OBJECT +public: + struct Result { + QMap<QString, Mod> mods; + }; + using ResultPtr = std::shared_ptr<Result>; + ResultPtr result() const { + return m_result; + } + +public: + ModFolderLoadTask(QDir& mods_dir, QDir& index_dir); + void run(); +signals: + void succeeded(); + +private: + void getFromMetadata(); + +private: + QDir& m_mods_dir, m_index_dir; + ResultPtr m_result; +}; |