aboutsummaryrefslogtreecommitdiff
path: root/launcher/minecraft/mod
diff options
context:
space:
mode:
Diffstat (limited to 'launcher/minecraft/mod')
-rw-r--r--launcher/minecraft/mod/MetadataHandler.h59
-rw-r--r--launcher/minecraft/mod/Mod.cpp226
-rw-r--r--launcher/minecraft/mod/Mod.h145
-rw-r--r--launcher/minecraft/mod/ModDetails.h66
-rw-r--r--launcher/minecraft/mod/ModFolderLoadTask.cpp18
-rw-r--r--launcher/minecraft/mod/ModFolderLoadTask.h29
-rw-r--r--launcher/minecraft/mod/ModFolderModel.cpp117
-rw-r--r--launcher/minecraft/mod/ModFolderModel.h63
-rw-r--r--launcher/minecraft/mod/ModFolderModel_test.cpp47
-rw-r--r--launcher/minecraft/mod/ResourcePackFolderModel.cpp35
-rw-r--r--launcher/minecraft/mod/TexturePackFolderModel.cpp35
-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.cpp57
-rw-r--r--launcher/minecraft/mod/tasks/LocalModUpdateTask.h44
-rw-r--r--launcher/minecraft/mod/tasks/ModFolderLoadTask.cpp104
-rw-r--r--launcher/minecraft/mod/tasks/ModFolderLoadTask.h71
-rw-r--r--launcher/minecraft/mod/testdata/test_folder/assets/minecraft/textures/blah.txt1
-rw-r--r--launcher/minecraft/mod/testdata/test_folder/pack.mcmeta6
-rw-r--r--launcher/minecraft/mod/testdata/test_folder/pack.nfo1
20 files changed, 888 insertions, 266 deletions
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..742709e3 100644
--- a/launcher/minecraft/mod/Mod.cpp
+++ b/launcher/minecraft/mod/Mod.cpp
@@ -1,24 +1,49 @@
-/* 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>
+* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+*
+* 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 +51,67 @@ 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))
+ , 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 +120,126 @@ 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) {
+ m_localDetails->status = status;
+ } else {
+ m_temp_status = status;
+ }
}
+void Mod::setMetadata(Metadata::ModStruct* metadata)
+{
+ if (status() == ModStatus::NoMetadata)
+ setStatus(ModStatus::Installed);
+ if (m_localDetails) {
+ m_localDetails->metadata.reset(metadata);
+ } else {
+ m_temp_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
+ // "ModMetadataDisabled" 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
+{
+ if (!m_localDetails)
+ return m_temp_status;
+ return details().status;
+}
+
+auto Mod::metadata() -> std::shared_ptr<Metadata::ModStruct>
+{
+ if (m_localDetails)
+ return m_localDetails->metadata;
+ return m_temp_metadata;
+}
+
+auto Mod::metadata() const -> const std::shared_ptr<Metadata::ModStruct>
+{
+ if (m_localDetails)
+ return m_localDetails->metadata;
+ return m_temp_metadata;
+}
+
+void Mod::finishResolvingWithDetails(std::shared_ptr<ModDetails> details)
+{
+ m_resolving = false;
+ m_resolved = true;
+ m_localDetails = details;
+
+ if (m_localDetails && m_temp_metadata && m_temp_metadata->isValid()) {
+ m_localDetails->metadata = m_temp_metadata;
+ if (status() == ModStatus::NoMetadata)
+ setStatus(ModStatus::Installed);
+ }
+
+ setStatus(m_temp_status);
+}
diff --git a/launcher/minecraft/mod/Mod.h b/launcher/minecraft/mod/Mod.h
index 921faeb1..5f9c4684 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,73 @@ 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() -> std::shared_ptr<Metadata::ModStruct>;
+ auto metadata() const -> const std::shared_ptr<Metadata::ModStruct>;
- 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;
+
+ /* Set the mod status while it doesn't have local details just yet */
+ ModStatus m_temp_status = ModStatus::NotInstalled;
+
+ 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..5ee08cbf 100644
--- a/launcher/minecraft/mod/ModFolderModel.cpp
+++ b/launcher/minecraft/mod/ModFolderModel.cpp
@@ -1,32 +1,55 @@
-/* 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>
+* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+*
+* 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 "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"
-ModFolderModel::ModFolderModel(const QString &dir) : QAbstractListModel(), m_dir(dir)
+#include "minecraft/mod/tasks/LocalModParseTask.h"
+#include "minecraft/mod/tasks/ModFolderLoadTask.h"
+
+ModFolderModel::ModFolderModel(const QString &dir, bool is_indexed) : QAbstractListModel(), m_dir(dir), m_is_indexed(is_indexed)
{
FS::ensureFolderPathExists(m_dir.absolutePath());
m_dir.setFilter(QDir::Readable | QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs);
@@ -79,19 +102,31 @@ bool ModFolderModel::update()
return true;
}
- auto task = new ModFolderLoadTask(m_dir);
+ auto index_dir = indexDir();
+ auto task = new ModFolderLoadTask(dir(), index_dir, m_is_indexed);
+
m_update = task->result();
+
QThreadPool *threadPool = QThreadPool::globalInstance();
connect(task, &ModFolderLoadTask::succeeded, this, &ModFolderModel::finishUpdate);
+
threadPool->start(task);
return true;
}
void ModFolderModel::finishUpdate()
{
+#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
+ auto currentList = modsIndex.keys();
+ QSet<QString> currentSet(currentList.begin(), currentList.end());
+ auto & newMods = m_update->mods;
+ auto newList = newMods.keys();
+ QSet<QString> newSet(newList.begin(), newList.end());
+#else
QSet<QString> currentSet = modsIndex.keys().toSet();
auto & newMods = m_update->mods;
QSet<QString> newSet = newMods.keys().toSet();
+#endif
// see if the kept mods changed in some way
{
@@ -140,12 +175,16 @@ void ModFolderModel::finishUpdate()
{
QSet<QString> added = newSet;
added.subtract(currentSet);
- beginInsertRows(QModelIndex(), mods.size(), mods.size() + added.size() - 1);
- for(auto & addedMod: added) {
- mods.append(newMods[addedMod]);
- resolveMod(mods.last());
+
+ // When you have a Qt build with assertions turned on, proceeding here will abort the application
+ if (added.size() > 0) {
+ beginInsertRows(QModelIndex(), mods.size(), mods.size() + added.size() - 1);
+ for (auto& addedMod : added) {
+ mods.append(newMods[addedMod]);
+ resolveMod(mods.last());
+ }
+ endInsertRows();
}
- endInsertRows();
}
// update index
@@ -153,7 +192,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 +213,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++;
@@ -278,7 +317,8 @@ bool ModFolderModel::installMod(const QString &filename)
return false;
}
FS::updateTimestamp(newpath);
- installedMod.repath(newpath);
+ QFileInfo newpathInfo(newpath);
+ installedMod.repath(newpathInfo);
update();
return true;
}
@@ -296,7 +336,8 @@ bool ModFolderModel::installMod(const QString &filename)
qWarning() << "Copy of folder from" << originalPath << "to" << newpath << "has (potentially partially) failed.";
return false;
}
- installedMod.repath(newpath);
+ QFileInfo newpathInfo(newpath);
+ installedMod.repath(newpathInfo);
update();
return true;
}
@@ -333,8 +374,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 +426,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 +481,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..24b4d358 100644
--- a/launcher/minecraft/mod/ModFolderModel.h
+++ b/launcher/minecraft/mod/ModFolderModel.h
@@ -1,17 +1,38 @@
-/* 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>
+* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+*
+* 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
@@ -24,8 +45,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;
@@ -52,7 +73,7 @@ public:
Enable,
Toggle
};
- ModFolderModel(const QString &dir);
+ ModFolderModel(const QString &dir, bool is_indexed = false);
virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
@@ -108,11 +129,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;
@@ -141,6 +167,7 @@ protected:
bool scheduled_update = false;
bool interaction_disabled = false;
QDir m_dir;
+ bool m_is_indexed;
QMap<QString, int> modsIndex;
QMap<int, LocalModParseTask::ResultPtr> activeTickets;
int nextResolutionTicket = 0;
diff --git a/launcher/minecraft/mod/ModFolderModel_test.cpp b/launcher/minecraft/mod/ModFolderModel_test.cpp
index 76f16ed5..b4d37ce5 100644
--- a/launcher/minecraft/mod/ModFolderModel_test.cpp
+++ b/launcher/minecraft/mod/ModFolderModel_test.cpp
@@ -1,7 +1,40 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+* PolyMC - Minecraft Launcher
+* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+*
+* 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 <QTest>
#include <QTemporaryDir>
-#include "TestUtil.h"
#include "FileSystem.h"
#include "minecraft/mod/ModFolderModel.h"
@@ -16,7 +49,7 @@ slots:
void test_1178()
{
// source
- QString source = QFINDTESTDATA("data/test_folder");
+ QString source = QFINDTESTDATA("testdata/test_folder");
// sanity check
QVERIFY(!source.endsWith('/'));
@@ -32,8 +65,11 @@ slots:
{
QString folder = source;
QTemporaryDir tempDir;
- ModFolderModel m(tempDir.path());
+ QEventLoop loop;
+ ModFolderModel m(tempDir.path(), true);
+ connect(&m, &ModFolderModel::updateFinished, &loop, &QEventLoop::quit);
m.installMod(folder);
+ loop.exec();
verify(tempDir.path());
}
@@ -41,8 +77,11 @@ slots:
{
QString folder = source + '/';
QTemporaryDir tempDir;
- ModFolderModel m(tempDir.path());
+ QEventLoop loop;
+ ModFolderModel m(tempDir.path(), true);
+ connect(&m, &ModFolderModel::updateFinished, &loop, &QEventLoop::quit);
m.installMod(folder);
+ loop.exec();
verify(tempDir.path());
}
}
diff --git a/launcher/minecraft/mod/ResourcePackFolderModel.cpp b/launcher/minecraft/mod/ResourcePackFolderModel.cpp
index f3d7f566..276804ed 100644
--- a/launcher/minecraft/mod/ResourcePackFolderModel.cpp
+++ b/launcher/minecraft/mod/ResourcePackFolderModel.cpp
@@ -1,3 +1,38 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+* PolyMC - Minecraft Launcher
+* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+*
+* 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 "ResourcePackFolderModel.h"
ResourcePackFolderModel::ResourcePackFolderModel(const QString &dir) : ModFolderModel(dir) {
diff --git a/launcher/minecraft/mod/TexturePackFolderModel.cpp b/launcher/minecraft/mod/TexturePackFolderModel.cpp
index d5956da1..e3a22219 100644
--- a/launcher/minecraft/mod/TexturePackFolderModel.cpp
+++ b/launcher/minecraft/mod/TexturePackFolderModel.cpp
@@ -1,3 +1,38 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+* PolyMC - Minecraft Launcher
+* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+*
+* 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 "TexturePackFolderModel.h"
TexturePackFolderModel::TexturePackFolderModel(const QString &dir) : ModFolderModel(dir) {
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..1bdecb8c
--- /dev/null
+++ b/launcher/minecraft/mod/tasks/LocalModUpdateTask.cpp
@@ -0,0 +1,57 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+* PolyMC - Minecraft Launcher
+* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
+* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+*
+* 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"
+
+#ifdef Q_OS_WIN32
+#include <windows.h>
+#endif
+
+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));
+ }
+
+#ifdef Q_OS_WIN32
+ SetFileAttributesA(index_dir.path().toStdString().c_str(), FILE_ATTRIBUTE_HIDDEN | FILE_ATTRIBUTE_NOT_CONTENT_INDEXED);
+#endif
+}
+
+void LocalModUpdateTask::executeTask()
+{
+ setStatus(tr("Updating index for mod:\n%1").arg(m_mod.name));
+
+ 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..276414e4
--- /dev/null
+++ b/launcher/minecraft/mod/tasks/ModFolderLoadTask.cpp
@@ -0,0 +1,104 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+* PolyMC - Minecraft Launcher
+* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
+* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+*
+* 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, bool is_indexed)
+ : m_mods_dir(mods_dir), m_index_dir(index_dir), m_is_indexed(is_indexed), m_result(new Result())
+{}
+
+void ModFolderLoadTask::run()
+{
+ if (m_is_indexed) {
+ // 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 (mod.enabled()) {
+ 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);
+ }
+ }
+ else {
+ QString chopped_id = mod.internal_id().chopped(9);
+ if (m_result->mods.contains(chopped_id)) {
+ m_result->mods[mod.internal_id()] = mod;
+
+ auto metadata = m_result->mods[chopped_id].metadata();
+ if (metadata) {
+ mod.setMetadata(new Metadata::ModStruct(*metadata));
+
+ m_result->mods[mod.internal_id()].setStatus(ModStatus::Installed);
+ m_result->mods.remove(chopped_id);
+ }
+ }
+ 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..088f873e
--- /dev/null
+++ b/launcher/minecraft/mod/tasks/ModFolderLoadTask.h
@@ -0,0 +1,71 @@
+// SPDX-License-Identifier: GPL-3.0-only
+/*
+* PolyMC - Minecraft Launcher
+* Copyright (c) 2022 flowln <flowlnlnln@gmail.com>
+* Copyright (C) 2022 Sefa Eyeoglu <contact@scrumplex.net>
+*
+* 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, bool is_indexed);
+ void run();
+signals:
+ void succeeded();
+
+private:
+ void getFromMetadata();
+
+private:
+ QDir& m_mods_dir, m_index_dir;
+ bool m_is_indexed;
+ ResultPtr m_result;
+};
diff --git a/launcher/minecraft/mod/testdata/test_folder/assets/minecraft/textures/blah.txt b/launcher/minecraft/mod/testdata/test_folder/assets/minecraft/textures/blah.txt
new file mode 100644
index 00000000..8d1c8b69
--- /dev/null
+++ b/launcher/minecraft/mod/testdata/test_folder/assets/minecraft/textures/blah.txt
@@ -0,0 +1 @@
+
diff --git a/launcher/minecraft/mod/testdata/test_folder/pack.mcmeta b/launcher/minecraft/mod/testdata/test_folder/pack.mcmeta
new file mode 100644
index 00000000..67ee0434
--- /dev/null
+++ b/launcher/minecraft/mod/testdata/test_folder/pack.mcmeta
@@ -0,0 +1,6 @@
+{
+ "pack": {
+ "pack_format": 1,
+ "description": "Some resource pack maybe"
+ }
+}
diff --git a/launcher/minecraft/mod/testdata/test_folder/pack.nfo b/launcher/minecraft/mod/testdata/test_folder/pack.nfo
new file mode 100644
index 00000000..8d1c8b69
--- /dev/null
+++ b/launcher/minecraft/mod/testdata/test_folder/pack.nfo
@@ -0,0 +1 @@
+