aboutsummaryrefslogtreecommitdiff
path: root/launcher/minecraft/legacy/LegacyModList.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'launcher/minecraft/legacy/LegacyModList.cpp')
-rw-r--r--launcher/minecraft/legacy/LegacyModList.cpp136
1 files changed, 136 insertions, 0 deletions
diff --git a/launcher/minecraft/legacy/LegacyModList.cpp b/launcher/minecraft/legacy/LegacyModList.cpp
new file mode 100644
index 00000000..7301eb8c
--- /dev/null
+++ b/launcher/minecraft/legacy/LegacyModList.cpp
@@ -0,0 +1,136 @@
+/* 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 "LegacyModList.h"
+#include <FileSystem.h>
+#include <QString>
+#include <QDebug>
+
+LegacyModList::LegacyModList(const QString &dir, const QString &list_file)
+ : m_dir(dir), m_list_file(list_file)
+{
+ FS::ensureFolderPathExists(m_dir.absolutePath());
+ m_dir.setFilter(QDir::Readable | QDir::NoDotAndDotDot | QDir::Files | QDir::Dirs | QDir::NoSymLinks);
+ m_dir.setSorting(QDir::Name | QDir::IgnoreCase | QDir::LocaleAware);
+}
+
+ struct OrderItem
+ {
+ QString id;
+ bool enabled = false;
+ };
+ typedef QList<OrderItem> OrderList;
+
+static void internalSort(QList<LegacyModList::Mod> &what)
+{
+ auto predicate = [](const LegacyModList::Mod &left, const LegacyModList::Mod &right)
+ {
+ return left.fileName().localeAwareCompare(right.fileName()) < 0;
+ };
+ std::sort(what.begin(), what.end(), predicate);
+}
+
+static OrderList readListFile(const QString &m_list_file)
+{
+ OrderList itemList;
+ if (m_list_file.isNull() || m_list_file.isEmpty())
+ return itemList;
+
+ QFile textFile(m_list_file);
+ if (!textFile.open(QIODevice::ReadOnly | QIODevice::Text))
+ return OrderList();
+
+ QTextStream textStream;
+ textStream.setAutoDetectUnicode(true);
+ textStream.setDevice(&textFile);
+ while (true)
+ {
+ QString line = textStream.readLine();
+ if (line.isNull() || line.isEmpty())
+ break;
+ else
+ {
+ OrderItem it;
+ it.enabled = !line.endsWith(".disabled");
+ if (!it.enabled)
+ {
+ line.chop(9);
+ }
+ it.id = line;
+ itemList.append(it);
+ }
+ }
+ textFile.close();
+ return itemList;
+}
+
+bool LegacyModList::update()
+{
+ if (!m_dir.exists() || !m_dir.isReadable())
+ return false;
+
+ QList<Mod> orderedMods;
+ QList<Mod> newMods;
+ m_dir.refresh();
+ auto folderContents = m_dir.entryInfoList();
+
+ // first, process the ordered items (if any)
+ OrderList listOrder = readListFile(m_list_file);
+ for (auto item : listOrder)
+ {
+ QFileInfo infoEnabled(m_dir.filePath(item.id));
+ QFileInfo infoDisabled(m_dir.filePath(item.id + ".disabled"));
+ int idxEnabled = folderContents.indexOf(infoEnabled);
+ int idxDisabled = folderContents.indexOf(infoDisabled);
+ bool isEnabled;
+ // if both enabled and disabled versions are present, it's a special case...
+ if (idxEnabled >= 0 && idxDisabled >= 0)
+ {
+ // we only process the one we actually have in the order file.
+ // and exactly as we have it.
+ // THIS IS A CORNER CASE
+ isEnabled = item.enabled;
+ }
+ else
+ {
+ // only one is present.
+ // we pick the one that we found.
+ // we assume the mod was enabled/disabled by external means
+ isEnabled = idxEnabled >= 0;
+ }
+ int idx = isEnabled ? idxEnabled : idxDisabled;
+ QFileInfo &info = isEnabled ? infoEnabled : infoDisabled;
+ // if the file from the index file exists
+ if (idx != -1)
+ {
+ // remove from the actual folder contents list
+ folderContents.takeAt(idx);
+ // append the new mod
+ orderedMods.append(info);
+ }
+ }
+ // if there are any untracked files... append them sorted at the end
+ if (folderContents.size())
+ {
+ for (auto entry : folderContents)
+ {
+ newMods.append(entry);
+ }
+ internalSort(newMods);
+ orderedMods.append(newMods);
+ }
+ mods.swap(orderedMods);
+ return true;
+}