PrismLauncher/api/logic/minecraft/legacy/LegacyModList.cpp

172 lines
5.2 KiB
C++
Raw Normal View History

2019-01-16 20:14:24 +00:00
/* Copyright 2013-2019 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)
2018-07-15 13:51:05 +01:00
: m_dir(dir), m_list_file(list_file)
{
2018-07-15 13:51:05 +01:00
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);
}
2018-07-15 13:51:05 +01:00
struct OrderItem
{
QString id;
bool enabled = false;
};
typedef QList<OrderItem> OrderList;
static void internalSort(QList<Mod> &what)
{
2018-07-15 13:51:05 +01:00
auto predicate = [](const Mod &left, const Mod &right)
{
if (left.name() == right.name())
{
return left.mmc_id().localeAwareCompare(right.mmc_id()) < 0;
}
return left.name().localeAwareCompare(right.name()) < 0;
};
std::sort(what.begin(), what.end(), predicate);
}
static OrderList readListFile(const QString &m_list_file)
{
2018-07-15 13:51:05 +01:00
OrderList itemList;
if (m_list_file.isNull() || m_list_file.isEmpty())
return itemList;
2018-07-15 13:51:05 +01:00
QFile textFile(m_list_file);
if (!textFile.open(QIODevice::ReadOnly | QIODevice::Text))
return OrderList();
2018-07-15 13:51:05 +01:00
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()
{
2018-07-15 13:51:05 +01:00
if (!m_dir.exists() || !m_dir.isReadable())
return false;
2018-07-15 13:51:05 +01:00
QList<Mod> orderedMods;
QList<Mod> newMods;
m_dir.refresh();
auto folderContents = m_dir.entryInfoList();
bool orderOrStateChanged = false;
2018-07-15 13:51:05 +01:00
// 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(Mod(info));
if (isEnabled != item.enabled)
orderOrStateChanged = true;
}
else
{
orderOrStateChanged = true;
}
}
// if there are any untracked files...
if (folderContents.size())
{
// the order surely changed!
for (auto entry : folderContents)
{
newMods.append(Mod(entry));
}
internalSort(newMods);
orderedMods.append(newMods);
orderOrStateChanged = true;
}
// otherwise, if we were already tracking some mods
else if (mods.size())
{
// if the number doesn't match, order changed.
if (mods.size() != orderedMods.size())
orderOrStateChanged = true;
// if it does match, compare the mods themselves
else
for (int i = 0; i < mods.size(); i++)
{
if (!mods[i].strongCompare(orderedMods[i]))
{
orderOrStateChanged = true;
break;
}
}
}
mods.swap(orderedMods);
if (orderOrStateChanged && !m_list_file.isEmpty())
{
qDebug() << "Mod list " << m_list_file << " changed!";
}
return true;
}