Signed-off-by: Trial97 <alexandru.tripon97@gmail.com>
This commit is contained in:
Trial97 2023-07-02 12:50:45 +03:00
commit 6c4cf085e0
No known key found for this signature in database
GPG Key ID: 55EF5DA53DB36318
52 changed files with 299 additions and 1677 deletions

4
.git-blame-ignore-revs Normal file
View File

@ -0,0 +1,4 @@
# .git-blame-ignore-revs
# tabs -> spaces
bbb3b3e6f6e3c0f95873f22e6d0a4aaf350f49d9

View File

@ -594,7 +594,7 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv)
// Java Settings // Java Settings
m_settings->registerSetting("JavaPath", ""); m_settings->registerSetting("JavaPath", "");
m_settings->registerSetting("JavaTimestamp", 0); m_settings->registerSetting("JavaSignature", "");
m_settings->registerSetting("JavaArchitecture", ""); m_settings->registerSetting("JavaArchitecture", "");
m_settings->registerSetting("JavaRealArchitecture", ""); m_settings->registerSetting("JavaRealArchitecture", "");
m_settings->registerSetting("JavaVersion", ""); m_settings->registerSetting("JavaVersion", "");

View File

@ -377,8 +377,6 @@ set(MINECRAFT_SOURCES
minecraft/services/SkinDelete.cpp minecraft/services/SkinDelete.cpp
minecraft/services/SkinDelete.h minecraft/services/SkinDelete.h
mojang/PackageManifest.h
mojang/PackageManifest.cpp
minecraft/Agent.h) minecraft/Agent.h)
# the screenshots feature # the screenshots feature
@ -686,6 +684,7 @@ SET(LAUNCHER_SOURCES
VersionProxyModel.h VersionProxyModel.h
VersionProxyModel.cpp VersionProxyModel.cpp
Markdown.h Markdown.h
Markdown.cpp
# Super secret! # Super secret!
KonamiCode.h KonamiCode.h
@ -829,8 +828,8 @@ SET(LAUNCHER_SOURCES
ui/pages/global/APIPage.h ui/pages/global/APIPage.h
# GUI - platform pages # GUI - platform pages
ui/pages/modplatform/VanillaPage.cpp ui/pages/modplatform/CustomPage.cpp
ui/pages/modplatform/VanillaPage.h ui/pages/modplatform/CustomPage.h
ui/pages/modplatform/ResourcePage.cpp ui/pages/modplatform/ResourcePage.cpp
ui/pages/modplatform/ResourcePage.h ui/pages/modplatform/ResourcePage.h
@ -1036,7 +1035,7 @@ qt_wrap_ui(LAUNCHER_UI
ui/pages/instance/ScreenshotsPage.ui ui/pages/instance/ScreenshotsPage.ui
ui/pages/modplatform/atlauncher/AtlOptionalModDialog.ui ui/pages/modplatform/atlauncher/AtlOptionalModDialog.ui
ui/pages/modplatform/atlauncher/AtlPage.ui ui/pages/modplatform/atlauncher/AtlPage.ui
ui/pages/modplatform/VanillaPage.ui ui/pages/modplatform/CustomPage.ui
ui/pages/modplatform/ResourcePage.ui ui/pages/modplatform/ResourcePage.ui
ui/pages/modplatform/flame/FlamePage.ui ui/pages/modplatform/flame/FlamePage.ui
ui/pages/modplatform/legacy_ftb/Page.ui ui/pages/modplatform/legacy_ftb/Page.ui

View File

@ -40,6 +40,7 @@
#include <QFileSystemModel> #include <QFileSystemModel>
#include <QSortFilterProxyModel> #include <QSortFilterProxyModel>
#include <QStack> #include <QStack>
#include <algorithm>
#include "FileSystem.h" #include "FileSystem.h"
#include "SeparatorPrefixTree.h" #include "SeparatorPrefixTree.h"
#include "StringUtils.h" #include "StringUtils.h"
@ -254,3 +255,25 @@ bool FileIgnoreProxy::filterAcceptsColumn(int source_column, const QModelIndex&
return true; return true;
} }
bool FileIgnoreProxy::filterAcceptsRow(int sourceRow, const QModelIndex& sourceParent) const
{
QModelIndex index = sourceModel()->index(sourceRow, 0, sourceParent);
QFileSystemModel* fsm = qobject_cast<QFileSystemModel*>(sourceModel());
auto fileInfo = fsm->fileInfo(index);
return !ignoreFile(fileInfo);
}
bool FileIgnoreProxy::ignoreFile(QFileInfo fileInfo) const
{
auto fileName = fileInfo.fileName();
auto path = relPath(fileInfo.absoluteFilePath());
return std::any_of(m_ignoreFiles.cbegin(), m_ignoreFiles.cend(), [fileName](auto iFileName) { return fileName == iFileName; }) ||
m_ignoreFilePaths.covers(path);
}
bool FileIgnoreProxy::filterFile(const QString& fileName) const
{
return blocked.covers(fileName) || ignoreFile(QFileInfo(QDir(root), fileName));
}

View File

@ -36,6 +36,7 @@
#pragma once #pragma once
#include <QFileInfo>
#include <QSortFilterProxyModel> #include <QSortFilterProxyModel>
#include "SeparatorPrefixTree.h" #include "SeparatorPrefixTree.h"
@ -63,10 +64,22 @@ class FileIgnoreProxy : public QSortFilterProxyModel {
inline const SeparatorPrefixTree<'/'>& blockedPaths() const { return blocked; } inline const SeparatorPrefixTree<'/'>& blockedPaths() const { return blocked; }
inline SeparatorPrefixTree<'/'>& blockedPaths() { return blocked; } inline SeparatorPrefixTree<'/'>& blockedPaths() { return blocked; }
// list of file names that need to be removed completely from model
inline QStringList& ignoreFilesWithName() { return m_ignoreFiles; }
// list of relative paths that need to be removed completely from model
inline SeparatorPrefixTree<'/'>& ignoreFilesWithPath() { return m_ignoreFilePaths; }
bool filterFile(const QString& fileName) const;
protected: protected:
bool filterAcceptsColumn(int source_column, const QModelIndex& source_parent) const; bool filterAcceptsColumn(int source_column, const QModelIndex& source_parent) const;
bool filterAcceptsRow(int source_row, const QModelIndex& source_parent) const;
bool ignoreFile(QFileInfo file) const;
private: private:
const QString root; const QString root;
SeparatorPrefixTree<'/'> blocked; SeparatorPrefixTree<'/'> blocked;
QStringList m_ignoreFiles;
SeparatorPrefixTree<'/'> m_ignoreFilePaths;
}; };

View File

@ -102,7 +102,7 @@ namespace fs = ghc::filesystem;
#include <linux/fs.h> #include <linux/fs.h>
#include <sys/ioctl.h> #include <sys/ioctl.h>
#include <unistd.h> #include <unistd.h>
#elif defined(Q_OS_MACOS) || defined(Q_OS_OPENBSD) #elif defined(Q_OS_MACOS)
#include <sys/attr.h> #include <sys/attr.h>
#include <sys/clonefile.h> #include <sys/clonefile.h>
#elif defined(Q_OS_WIN) #elif defined(Q_OS_WIN)
@ -372,7 +372,7 @@ void create_link::make_link_list(const QString& offset)
auto src_path = source_it.next(); auto src_path = source_it.next();
auto relative_path = src_dir.relativeFilePath(src_path); auto relative_path = src_dir.relativeFilePath(src_path);
if (m_max_depth >= 0 && pathDepth(relative_path) > m_max_depth){ if (m_max_depth >= 0 && pathDepth(relative_path) > m_max_depth) {
relative_path = pathTruncate(relative_path, m_max_depth); relative_path = pathTruncate(relative_path, m_max_depth);
src_path = src_dir.filePath(relative_path); src_path = src_dir.filePath(relative_path);
if (linkedPaths.contains(src_path)) { if (linkedPaths.contains(src_path)) {
@ -663,7 +663,7 @@ QString pathTruncate(const QString& path, int depth)
QString trunc = QFileInfo(path).path(); QString trunc = QFileInfo(path).path();
if (pathDepth(trunc) > depth ) { if (pathDepth(trunc) > depth) {
return pathTruncate(trunc, depth); return pathTruncate(trunc, depth);
} }
@ -769,6 +769,9 @@ QString getDesktopDir()
// Cross-platform Shortcut creation // Cross-platform Shortcut creation
bool createShortcut(QString destination, QString target, QStringList args, QString name, QString icon) bool createShortcut(QString destination, QString target, QStringList args, QString name, QString icon)
{ {
if (destination.isEmpty()) {
destination = PathCombine(getDesktopDir(), RemoveInvalidFilenameChars(name));
}
#if defined(Q_OS_MACOS) #if defined(Q_OS_MACOS)
destination += ".command"; destination += ".command";
@ -791,6 +794,8 @@ bool createShortcut(QString destination, QString target, QStringList args, QStri
return true; return true;
#elif defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD) #elif defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
if (!destination.endsWith(".desktop")) // in case of isFlatpak destination is already populated
destination += ".desktop";
QFile f(destination); QFile f(destination);
f.open(QIODevice::WriteOnly | QIODevice::Text); f.open(QIODevice::WriteOnly | QIODevice::Text);
QTextStream stream(&f); QTextStream stream(&f);
@ -974,7 +979,7 @@ FilesystemType getFilesystemType(const QString& name)
{ {
for (auto iter = s_filesystem_type_names.constBegin(); iter != s_filesystem_type_names.constEnd(); ++iter) { for (auto iter = s_filesystem_type_names.constBegin(); iter != s_filesystem_type_names.constEnd(); ++iter) {
auto fs_names = iter.value(); auto fs_names = iter.value();
if(fs_names.contains(name.toUpper())) if (fs_names.contains(name.toUpper()))
return iter.key(); return iter.key();
} }
return FilesystemType::UNKNOWN; return FilesystemType::UNKNOWN;
@ -1151,7 +1156,7 @@ bool clone_file(const QString& src, const QString& dst, std::error_code& ec)
return false; return false;
} }
#elif defined(Q_OS_MACOS) || defined(Q_OS_OPENBSD) #elif defined(Q_OS_MACOS)
if (!macos_bsd_clonefile(src_path, dst_path, ec)) { if (!macos_bsd_clonefile(src_path, dst_path, ec)) {
qDebug() << "failed macos_bsd_clonefile:"; qDebug() << "failed macos_bsd_clonefile:";
@ -1380,7 +1385,7 @@ bool linux_ficlone(const std::string& src_path, const std::string& dst_path, std
return true; return true;
} }
#elif defined(Q_OS_MACOS) || defined(Q_OS_OPENBSD) #elif defined(Q_OS_MACOS)
bool macos_bsd_clonefile(const std::string& src_path, const std::string& dst_path, std::error_code& ec) bool macos_bsd_clonefile(const std::string& src_path, const std::string& dst_path, std::error_code& ec)
{ {

31
launcher/Markdown.cpp Normal file
View File

@ -0,0 +1,31 @@
// SPDX-License-Identifier: GPL-3.0-only
/*
* Prism Launcher - Minecraft Launcher
* Copyright (C) 2023 Joshua Goins <josh@redstrate.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 "Markdown.h"
QString markdownToHTML(const QString& markdown)
{
const QByteArray markdownData = markdown.toUtf8();
char* buffer = cmark_markdown_to_html(markdownData.constData(), markdownData.length(), CMARK_OPT_NOBREAKS | CMARK_OPT_UNSAFE);
QString htmlStr(buffer);
free(buffer);
return htmlStr;
}

View File

@ -21,14 +21,4 @@
#include <QString> #include <QString>
#include <cmark.h> #include <cmark.h>
static QString markdownToHTML(const QString& markdown) QString markdownToHTML(const QString& markdown);
{
const QByteArray markdownData = markdown.toUtf8();
char* buffer = cmark_markdown_to_html(markdownData.constData(), markdownData.length(), CMARK_OPT_NOBREAKS | CMARK_OPT_UNSAFE);
QString htmlStr(buffer);
free(buffer);
return htmlStr;
}

View File

@ -81,15 +81,20 @@ void CheckJava::executeTask()
} }
QFileInfo javaInfo(realJavaPath); QFileInfo javaInfo(realJavaPath);
qlonglong javaUnixTime = javaInfo.lastModified().toMSecsSinceEpoch(); qint64 javaUnixTime = javaInfo.lastModified().toMSecsSinceEpoch();
auto storedUnixTime = settings->get("JavaTimestamp").toLongLong(); auto storedSignature = settings->get("JavaSignature").toString();
auto storedArchitecture = settings->get("JavaArchitecture").toString(); auto storedArchitecture = settings->get("JavaArchitecture").toString();
auto storedRealArchitecture = settings->get("JavaRealArchitecture").toString(); auto storedRealArchitecture = settings->get("JavaRealArchitecture").toString();
auto storedVersion = settings->get("JavaVersion").toString(); auto storedVersion = settings->get("JavaVersion").toString();
auto storedVendor = settings->get("JavaVendor").toString(); auto storedVendor = settings->get("JavaVendor").toString();
m_javaUnixTime = javaUnixTime;
QCryptographicHash hash(QCryptographicHash::Sha1);
hash.addData(QByteArray::number(javaUnixTime));
hash.addData(m_javaPath.toUtf8());
m_javaSignature = hash.result().toHex();
// if timestamps are not the same, or something is missing, check! // if timestamps are not the same, or something is missing, check!
if (javaUnixTime != storedUnixTime || storedVersion.size() == 0 if (m_javaSignature != storedSignature || storedVersion.size() == 0
|| storedArchitecture.size() == 0 || storedRealArchitecture.size() == 0 || storedArchitecture.size() == 0 || storedRealArchitecture.size() == 0
|| storedVendor.size() == 0) || storedVendor.size() == 0)
{ {
@ -140,7 +145,7 @@ void CheckJava::checkJavaFinished(JavaCheckResult result)
instance->settings()->set("JavaArchitecture", result.mojangPlatform); instance->settings()->set("JavaArchitecture", result.mojangPlatform);
instance->settings()->set("JavaRealArchitecture", result.realPlatform); instance->settings()->set("JavaRealArchitecture", result.realPlatform);
instance->settings()->set("JavaVendor", result.javaVendor); instance->settings()->set("JavaVendor", result.javaVendor);
instance->settings()->set("JavaTimestamp", m_javaUnixTime); instance->settings()->set("JavaSignature", m_javaSignature);
emitSucceeded(); emitSucceeded();
return; return;
} }

View File

@ -40,6 +40,6 @@ private:
private: private:
QString m_javaPath; QString m_javaPath;
qlonglong m_javaUnixTime; QString m_javaSignature;
JavaCheckerPtr m_JavaChecker; JavaCheckerPtr m_JavaChecker;
}; };

View File

@ -148,7 +148,7 @@ void MinecraftInstance::loadSpecificSettings()
m_settings->registerOverride(global_settings->getSetting("IgnoreJavaCompatibility"), javaOrLocation); m_settings->registerOverride(global_settings->getSetting("IgnoreJavaCompatibility"), javaOrLocation);
// special! // special!
m_settings->registerPassthrough(global_settings->getSetting("JavaTimestamp"), javaOrLocation); m_settings->registerPassthrough(global_settings->getSetting("JavaSignature"), javaOrLocation);
m_settings->registerPassthrough(global_settings->getSetting("JavaArchitecture"), javaOrLocation); m_settings->registerPassthrough(global_settings->getSetting("JavaArchitecture"), javaOrLocation);
m_settings->registerPassthrough(global_settings->getSetting("JavaRealArchitecture"), javaOrLocation); m_settings->registerPassthrough(global_settings->getSetting("JavaRealArchitecture"), javaOrLocation);
m_settings->registerPassthrough(global_settings->getSetting("JavaVersion"), javaOrLocation); m_settings->registerPassthrough(global_settings->getSetting("JavaVersion"), javaOrLocation);

View File

@ -77,24 +77,28 @@ class FlameAPI : public NetworkResourceAPI {
[[nodiscard]] std::optional<QString> getVersionsURL(VersionSearchArgs const& args) const override [[nodiscard]] std::optional<QString> getVersionsURL(VersionSearchArgs const& args) const override
{ {
auto mappedModLoader = getMappedModLoader(args.loaders.value());
auto addonId = args.pack.addonId.toString(); auto addonId = args.pack.addonId.toString();
if (args.loaders.value() & Quilt) {
auto overide = ModPlatform::getOverrideDeps();
auto over = std::find_if(overide.cbegin(), overide.cend(), [addonId](auto dep) {
return dep.provider == ModPlatform::ResourceProvider::FLAME && addonId == dep.quilt;
});
if (over != overide.cend()) {
mappedModLoader = 5;
}
}
QString url{ QString("https://api.curseforge.com/v1/mods/%1/files?pageSize=10000&").arg(addonId) }; QString url{ QString("https://api.curseforge.com/v1/mods/%1/files?pageSize=10000&").arg(addonId) };
QStringList get_parameters; QStringList get_parameters;
if (args.mcVersions.has_value()) if (args.mcVersions.has_value())
get_parameters.append(QString("gameVersion=%1").arg(args.mcVersions.value().front().toString())); get_parameters.append(QString("gameVersion=%1").arg(args.mcVersions.value().front().toString()));
if (args.loaders.has_value())
if (args.loaders.has_value()) {
int mappedModLoader = getMappedModLoader(args.loaders.value());
if (args.loaders.value() & Quilt) {
auto overide = ModPlatform::getOverrideDeps();
auto over = std::find_if(overide.cbegin(), overide.cend(), [addonId](auto dep) {
return dep.provider == ModPlatform::ResourceProvider::FLAME && addonId == dep.quilt;
});
if (over != overide.cend()) {
mappedModLoader = 5;
}
}
get_parameters.append(QString("modLoaderType=%1").arg(mappedModLoader)); get_parameters.append(QString("modLoaderType=%1").arg(mappedModLoader));
}
return url + get_parameters.join('&'); return url + get_parameters.join('&');
}; };

View File

@ -1,427 +0,0 @@
#include "PackageManifest.h"
#include <Json.h>
#include <QDir>
#include <QDirIterator>
#include <QCryptographicHash>
#include <QDebug>
#ifndef Q_OS_WIN32
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#endif
namespace mojang_files {
const Hash hash_of_empty_string = "da39a3ee5e6b4b0d3255bfef95601890afd80709";
int Path::compare(const Path& rhs) const
{
auto left_cursor = begin();
auto left_end = end();
auto right_cursor = rhs.begin();
auto right_end = rhs.end();
while (left_cursor != left_end && right_cursor != right_end)
{
if(*left_cursor < *right_cursor)
{
return -1;
}
else if(*left_cursor > *right_cursor)
{
return 1;
}
left_cursor++;
right_cursor++;
}
if(left_cursor == left_end)
{
if(right_cursor == right_end)
{
return 0;
}
return -1;
}
return 1;
}
void Package::addFile(const Path& path, const File& file) {
addFolder(path.parent_path());
files[path] = file;
}
void Package::addFolder(Path folder) {
if(!folder.has_parent_path()) {
return;
}
do {
folders.insert(folder);
folder = folder.parent_path();
} while(folder.has_parent_path());
}
void Package::addLink(const Path& path, const Path& target) {
addFolder(path.parent_path());
symlinks[path] = target;
}
void Package::addSource(const FileSource& source) {
sources[source.hash] = source;
}
namespace {
void fromJson(QJsonDocument & doc, Package & out) {
std::set<Path> seen_paths;
if (!doc.isObject())
{
throw JSONValidationError("file manifest is not an object");
}
QJsonObject root = doc.object();
auto filesObj = Json::ensureObject(root, "files");
auto iter = filesObj.begin();
while (iter != filesObj.end())
{
Path objectPath = Path(iter.key());
auto value = iter.value();
iter++;
if(seen_paths.count(objectPath)) {
throw JSONValidationError("duplicate path inside manifest, the manifest is invalid");
}
if (!value.isObject())
{
throw JSONValidationError("file entry inside manifest is not an an object");
}
seen_paths.insert(objectPath);
auto fileObject = value.toObject();
auto type = Json::requireString(fileObject, "type");
if(type == "directory") {
out.addFolder(objectPath);
continue;
}
else if(type == "file") {
FileSource bestSource;
File file;
file.executable = Json::ensureBoolean(fileObject, QString("executable"), false);
auto downloads = Json::requireObject(fileObject, "downloads");
for(auto iter2 = downloads.begin(); iter2 != downloads.end(); iter2++) {
FileSource source;
auto downloadObject = Json::requireObject(iter2.value());
source.hash = Json::requireString(downloadObject, "sha1");
source.size = Json::requireInteger(downloadObject, "size");
source.url = Json::requireString(downloadObject, "url");
auto compression = iter2.key();
if(compression == "raw") {
file.hash = source.hash;
file.size = source.size;
source.compression = Compression::Raw;
}
else if (compression == "lzma") {
source.compression = Compression::Lzma;
}
else {
continue;
}
bestSource.upgrade(source);
}
if(bestSource.isBad()) {
throw JSONValidationError("No valid compression method for file " + iter.key());
}
out.addFile(objectPath, file);
out.addSource(bestSource);
}
else if(type == "link") {
auto target = Json::requireString(fileObject, "target");
out.symlinks[objectPath] = target;
out.addLink(objectPath, target);
}
else {
throw JSONValidationError("Invalid item type in manifest: " + type);
}
}
// make sure the containing folder exists
out.folders.insert(Path());
}
}
Package Package::fromManifestContents(const QByteArray& contents)
{
Package out;
try
{
auto doc = Json::requireDocument(contents, "Manifest");
fromJson(doc, out);
return out;
}
catch (const Exception &e)
{
qDebug() << QString("Unable to parse manifest: %1").arg(e.cause());
out.valid = false;
return out;
}
}
Package Package::fromManifestFile(const QString & filename) {
Package out;
try
{
auto doc = Json::requireDocument(filename, filename);
fromJson(doc, out);
return out;
}
catch (const Exception &e)
{
qDebug() << QString("Unable to parse manifest file %1: %2").arg(filename, e.cause());
out.valid = false;
return out;
}
}
#ifndef Q_OS_WIN32
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
namespace {
// FIXME: Qt obscures symlink targets by making them absolute. that is useless. this is the workaround - we do it ourselves
bool actually_read_symlink_target(const QString & filepath, Path & out)
{
struct ::stat st;
// FIXME: here, we assume the native filesystem encoding. May the Gods have mercy upon our Souls.
QByteArray nativePath = filepath.toUtf8();
const char * filepath_cstr = nativePath.data();
if (lstat(filepath_cstr, &st) != 0)
{
return false;
}
auto size = st.st_size ? st.st_size + 1 : PATH_MAX;
std::string temp(size, '\0');
// because we don't realiably know how long the damn thing actually is, we loop and expand. POSIX is naff
do
{
auto link_length = ::readlink(filepath_cstr, &temp[0], temp.size());
if(link_length == -1)
{
return false;
}
if(std::string::size_type(link_length) < temp.size())
{
// buffer was long enough and we managed to read the link target. RETURN here.
temp.resize(link_length);
out = Path(QString::fromUtf8(temp.c_str()));
return true;
}
temp.resize(temp.size() * 2);
} while (true);
}
}
#endif
// FIXME: Qt filesystem abstraction is bad, but ... let's hope it doesn't break too much?
// FIXME: The error handling is just DEFICIENT
Package Package::fromInspectedFolder(const QString& folderPath)
{
QDir root(folderPath);
Package out;
QDirIterator iterator(folderPath, QDir::NoDotAndDotDot | QDir::AllEntries | QDir::System | QDir::Hidden, QDirIterator::Subdirectories);
while(iterator.hasNext()) {
iterator.next();
auto fileInfo = iterator.fileInfo();
auto relPath = root.relativeFilePath(fileInfo.filePath());
// FIXME: this is probably completely busted on Windows anyway, so just disable it.
// Qt makes shit up and doesn't understand the platform details
// TODO: Actually use a filesystem library that isn't terrible and has decen license.
// I only know one, and I wrote it. Sadly, currently proprietary. PAIN.
#ifndef Q_OS_WIN32
if(fileInfo.isSymLink()) {
Path targetPath;
if(!actually_read_symlink_target(fileInfo.filePath(), targetPath)) {
qCritical() << "Folder inspection: Unknown filesystem object:" << fileInfo.absoluteFilePath();
out.valid = false;
}
out.addLink(relPath, targetPath);
}
else
#endif
if(fileInfo.isDir()) {
out.addFolder(relPath);
}
else if(fileInfo.isFile()) {
File f;
f.executable = fileInfo.isExecutable();
f.size = fileInfo.size();
// FIXME: async / optimize the hashing
QFile input(fileInfo.absoluteFilePath());
if(!input.open(QIODevice::ReadOnly)) {
qCritical() << "Folder inspection: Failed to open file:" << fileInfo.absoluteFilePath();
out.valid = false;
break;
}
f.hash = QCryptographicHash::hash(input.readAll(), QCryptographicHash::Sha1).toHex().constData();
out.addFile(relPath, f);
}
else {
// Something else... oh my
qCritical() << "Folder inspection: Unknown filesystem object:" << fileInfo.absoluteFilePath();
out.valid = false;
break;
}
}
out.folders.insert(Path("."));
out.valid = true;
return out;
}
namespace {
struct shallow_first_sort
{
bool operator()(const Path &lhs, const Path &rhs) const
{
auto lhs_depth = lhs.length();
auto rhs_depth = rhs.length();
if(lhs_depth < rhs_depth)
{
return true;
}
else if(lhs_depth == rhs_depth)
{
if(lhs < rhs)
{
return true;
}
}
return false;
}
};
struct deep_first_sort
{
bool operator()(const Path &lhs, const Path &rhs) const
{
auto lhs_depth = lhs.length();
auto rhs_depth = rhs.length();
if(lhs_depth > rhs_depth)
{
return true;
}
else if(lhs_depth == rhs_depth)
{
if(lhs < rhs)
{
return true;
}
}
return false;
}
};
}
UpdateOperations UpdateOperations::resolve(const Package& from, const Package& to)
{
UpdateOperations out;
if(!from.valid || !to.valid) {
out.valid = false;
return out;
}
// Files
for(auto iter = from.files.begin(); iter != from.files.end(); iter++) {
const auto &current_hash = iter->second.hash;
const auto &current_executable = iter->second.executable;
const auto &path = iter->first;
auto iter2 = to.files.find(path);
if(iter2 == to.files.end()) {
// removed
out.deletes.push_back(path);
continue;
}
auto new_hash = iter2->second.hash;
auto new_executable = iter2->second.executable;
if (current_hash != new_hash) {
out.deletes.push_back(path);
out.downloads.emplace(
std::pair<Path, FileDownload>{
path,
FileDownload(to.sources.at(iter2->second.hash), iter2->second.executable)
}
);
}
else if (current_executable != new_executable) {
out.executable_fixes[path] = new_executable;
}
}
for(auto iter = to.files.begin(); iter != to.files.end(); iter++) {
auto path = iter->first;
if(!from.files.count(path)) {
out.downloads.emplace(
std::pair<Path, FileDownload>{
path,
FileDownload(to.sources.at(iter->second.hash), iter->second.executable)
}
);
}
}
// Folders
std::set<Path, deep_first_sort> remove_folders;
std::set<Path, shallow_first_sort> make_folders;
for(auto from_path: from.folders) {
auto iter = to.folders.find(from_path);
if(iter == to.folders.end()) {
remove_folders.insert(from_path);
}
}
for(auto & rmdir: remove_folders) {
out.rmdirs.push_back(rmdir);
}
for(auto to_path: to.folders) {
auto iter = from.folders.find(to_path);
if(iter == from.folders.end()) {
make_folders.insert(to_path);
}
}
for(auto & mkdir: make_folders) {
out.mkdirs.push_back(mkdir);
}
// Symlinks
for(auto iter = from.symlinks.begin(); iter != from.symlinks.end(); iter++) {
const auto &current_target = iter->second;
const auto &path = iter->first;
auto iter2 = to.symlinks.find(path);
if(iter2 == to.symlinks.end()) {
// removed
out.deletes.push_back(path);
continue;
}
const auto &new_target = iter2->second;
if (current_target != new_target) {
out.deletes.push_back(path);
out.mklinks[path] = iter2->second;
}
}
for(auto iter = to.symlinks.begin(); iter != to.symlinks.end(); iter++) {
auto path = iter->first;
if(!from.symlinks.count(path)) {
out.mklinks[path] = iter->second;
}
}
out.valid = true;
return out;
}
}

View File

@ -1,171 +0,0 @@
#pragma once
#include <QString>
#include <map>
#include <set>
#include <QStringList>
#include "tasks/Task.h"
namespace mojang_files {
using Hash = QString;
extern const Hash empty_hash;
// simple-ish path implementation. assumes always relative and does not allow '..' entries
class Path
{
public:
using parts_type = QStringList;
Path() = default;
Path(QString string) {
auto parts_in = string.split('/');
for(auto & part: parts_in) {
if(part.isEmpty() || part == ".") {
continue;
}
if(part == "..") {
if(parts.size()) {
parts.pop_back();
}
continue;
}
parts.push_back(part);
}
}
bool has_parent_path() const
{
return parts.size() > 0;
}
Path parent_path() const
{
if (parts.empty())
return Path();
return Path(parts.begin(), std::prev(parts.end()));
}
bool empty() const
{
return parts.empty();
}
int length() const
{
return parts.length();
}
bool operator==(const Path & rhs) const {
return parts == rhs.parts;
}
bool operator!=(const Path & rhs) const {
return parts != rhs.parts;
}
inline bool operator<(const Path& rhs) const
{
return compare(rhs) < 0;
}
parts_type::const_iterator begin() const
{
return parts.begin();
}
parts_type::const_iterator end() const
{
return parts.end();
}
QString toString() const {
return parts.join("/");
}
private:
Path(const parts_type::const_iterator & start, const parts_type::const_iterator & end) {
auto cursor = start;
while(cursor != end) {
parts.push_back(*cursor);
cursor++;
}
}
int compare(const Path& p) const;
parts_type parts;
};
enum class Compression {
Raw,
Lzma,
Unknown
};
struct FileSource
{
Compression compression = Compression::Unknown;
Hash hash;
QString url;
std::size_t size = 0;
void upgrade(const FileSource & other) {
if(compression == Compression::Unknown || other.size < size) {
*this = other;
}
}
bool isBad() const {
return compression == Compression::Unknown;
}
};
struct File
{
Hash hash;
bool executable;
std::uint64_t size = 0;
};
struct Package {
static Package fromInspectedFolder(const QString &folderPath);
static Package fromManifestFile(const QString &path);
static Package fromManifestContents(const QByteArray& contents);
explicit operator bool() const
{
return valid;
}
void addFolder(Path folder);
void addFile(const Path & path, const File & file);
void addLink(const Path & path, const Path & target);
void addSource(const FileSource & source);
std::map<Hash, FileSource> sources;
bool valid = true;
std::set<Path> folders;
std::map<Path, File> files;
std::map<Path, Path> symlinks;
};
struct FileDownload : FileSource
{
FileDownload(const FileSource& source, bool executable) {
static_cast<FileSource &> (*this) = source;
this->executable = executable;
}
bool executable = false;
};
struct UpdateOperations {
static UpdateOperations resolve(const Package & from, const Package & to);
bool valid = false;
std::vector<Path> deletes;
std::vector<Path> rmdirs;
std::vector<Path> mkdirs;
std::map<Path, FileDownload> downloads;
std::map<Path, Path> mklinks;
std::map<Path, bool> executable_fixes;
};
}

View File

@ -16,7 +16,6 @@
<file>scalable/jarmods.svg</file> <file>scalable/jarmods.svg</file>
<file>scalable/java.svg</file> <file>scalable/java.svg</file>
<file>scalable/language.svg</file> <file>scalable/language.svg</file>
<file>scalable/launcher.svg</file>
<file>scalable/loadermods.svg</file> <file>scalable/loadermods.svg</file>
<file>scalable/log.svg</file> <file>scalable/log.svg</file>
<file>scalable/minecraft.svg</file> <file>scalable/minecraft.svg</file>

View File

@ -1,57 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg width="48" height="48" version="1.1" viewBox="0 0 12.7 12.7" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<title>Prism Launcher Logo</title>
<g stroke-width=".26458">
<path d="m6.35 6.35" fill="#99cd61"/>
<path d="m6.35 0.52917-2.5208 4.3656 2.5208 1.4552 2.5203-1.4552 0.10955-3.0996c-1.1511-0.66459-2.3388-1.2661-2.6298-1.2661z" fill="#df6277"/>
<path d="m8.9798 1.7952-2.6298 4.5548 2.5203 1.4552 2.5208-4.3656c-0.14552-0.25205-1.2601-0.97975-2.4112-1.6443z" fill="#fb9168"/>
<path d="m11.391 3.4396-5.041 2.9104 2.5203 1.4552 2.7389-1.4552c0-1.3292-0.072554-2.6584-0.21808-2.9104z" fill="#f3db6c"/>
<path d="m6.35 6.35v2.9104h5.041c0.14552-0.25205 0.21807-1.5812 0.21808-2.9104h-5.2591z" fill="#7ab392"/>
<path d="m6.35 6.35v2.9104l2.6298 1.6443c1.1511-0.66459 2.2657-1.3923 2.4112-1.6443l-5.041-2.9104z" fill="#4b7cbc"/>
<path d="m6.35 6.35-2.5208 1.4552 2.5208 4.3656c0.29104 0 1.4787-0.60148 2.6298-1.2661l-2.6298-4.5548z" fill="#6f488c"/>
<path d="m3.8292 4.8948-2.5203 4.3656c0.29104 0.5041 4.459 2.9104 5.041 2.9104v-5.8208l-2.5208-1.4552z" fill="#4d3f33"/>
<path d="m1.309 3.4396c-0.29104 0.5041-0.29104 5.3167 0 5.8208l5.041-2.9104v-2.9104h-5.041z" fill="#7a573b"/>
<path d="m6.35 0.52917c-0.58208-2e-8 -4.75 2.4063-5.041 2.9104l5.041 2.9104v-5.8208z" fill="#99cd61"/>
</g>
<g transform="matrix(.88 0 0 .88 -10.906 -1.2421)">
<g transform="translate(13.26 2.2776)">
<path transform="matrix(.96975 0 0 .96975 .1921 .1921)" d="m6.3498 2.9393c-0.34105 0-2.7827 1.4099-2.9532 1.7052l2.9532 5.1157 2.9538-5.1157c-0.17052-0.29535-2.6127-1.7052-2.9538-1.7052z" fill="#fff" stroke-width=".26458"/>
</g>
<path d="m16.746 6.9737 2.8639 4.9609c0.33073 0 2.6991-1.3672 2.8644-1.6536 0.16536-0.28642 0.16536-3.0209 0-3.3073l-2.8644 1.6536z" fill="#dfdfdf" stroke-width=".26458"/>
</g>
<path d="m3.8299 4.8948c-0.14551 0.25205-0.14553 2.6584 0 2.9104 0.14553 0.25204 2.2292 1.4552 2.5203 1.4552v-2.9104z" fill="#d6d2d2" stroke-width=".26458"/>
<metadata>
<rdf:RDF>
<cc:Work rdf:about="">
<dc:title>Prism Launcher Logo</dc:title>
<dc:date>19/10/2022</dc:date>
<dc:creator>
<cc:Agent>
<dc:title>Prism Launcher</dc:title>
</cc:Agent>
</dc:creator>
<dc:contributor>
<cc:Agent>
<dc:title>AutiOne, Boba, ely, Fulmine, gon sawa, Pankakes, tobimori, Zeke</dc:title>
</cc:Agent>
</dc:contributor>
<dc:source>https://github.com/PrismLauncher/PrismLauncher</dc:source>
<dc:publisher>
<cc:Agent>
<dc:title>Prism Launcher</dc:title>
</cc:Agent>
</dc:publisher>
<cc:license rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/"/>
</cc:Work>
<cc:License rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
<cc:permits rdf:resource="http://creativecommons.org/ns#Reproduction"/>
<cc:permits rdf:resource="http://creativecommons.org/ns#Distribution"/>
<cc:requires rdf:resource="http://creativecommons.org/ns#Notice"/>
<cc:requires rdf:resource="http://creativecommons.org/ns#Attribution"/>
<cc:permits rdf:resource="http://creativecommons.org/ns#DerivativeWorks"/>
<cc:requires rdf:resource="http://creativecommons.org/ns#ShareAlike"/>
</cc:License>
</rdf:RDF>
</metadata>
</svg>

Before

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -1,57 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg width="48" height="48" version="1.1" viewBox="0 0 12.7 12.7" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<title>Prism Launcher Logo</title>
<g stroke-width=".26458">
<path d="m6.35 6.35" fill="#99cd61"/>
<path d="m6.35 0.52917-2.5208 4.3656 2.5208 1.4552 2.5203-1.4552 0.10955-3.0996c-1.1511-0.66459-2.3388-1.2661-2.6298-1.2661z" fill="#df6277"/>
<path d="m8.9798 1.7952-2.6298 4.5548 2.5203 1.4552 2.5208-4.3656c-0.14552-0.25205-1.2601-0.97975-2.4112-1.6443z" fill="#fb9168"/>
<path d="m11.391 3.4396-5.041 2.9104 2.5203 1.4552 2.7389-1.4552c0-1.3292-0.072554-2.6584-0.21808-2.9104z" fill="#f3db6c"/>
<path d="m6.35 6.35v2.9104h5.041c0.14552-0.25205 0.21807-1.5812 0.21808-2.9104h-5.2591z" fill="#7ab392"/>
<path d="m6.35 6.35v2.9104l2.6298 1.6443c1.1511-0.66459 2.2657-1.3923 2.4112-1.6443l-5.041-2.9104z" fill="#4b7cbc"/>
<path d="m6.35 6.35-2.5208 1.4552 2.5208 4.3656c0.29104 0 1.4787-0.60148 2.6298-1.2661l-2.6298-4.5548z" fill="#6f488c"/>
<path d="m3.8292 4.8948-2.5203 4.3656c0.29104 0.5041 4.459 2.9104 5.041 2.9104v-5.8208l-2.5208-1.4552z" fill="#4d3f33"/>
<path d="m1.309 3.4396c-0.29104 0.5041-0.29104 5.3167 0 5.8208l5.041-2.9104v-2.9104h-5.041z" fill="#7a573b"/>
<path d="m6.35 0.52917c-0.58208-2e-8 -4.75 2.4063-5.041 2.9104l5.041 2.9104v-5.8208z" fill="#99cd61"/>
</g>
<g transform="matrix(.88 0 0 .88 -10.906 -1.2421)">
<g transform="translate(13.26 2.2776)">
<path transform="matrix(.96975 0 0 .96975 .1921 .1921)" d="m6.3498 2.9393c-0.34105 0-2.7827 1.4099-2.9532 1.7052l2.9532 5.1157 2.9538-5.1157c-0.17052-0.29535-2.6127-1.7052-2.9538-1.7052z" fill="#fff" stroke-width=".26458"/>
</g>
<path d="m16.746 6.9737 2.8639 4.9609c0.33073 0 2.6991-1.3672 2.8644-1.6536 0.16536-0.28642 0.16536-3.0209 0-3.3073l-2.8644 1.6536z" fill="#dfdfdf" stroke-width=".26458"/>
</g>
<path d="m3.8299 4.8948c-0.14551 0.25205-0.14553 2.6584 0 2.9104 0.14553 0.25204 2.2292 1.4552 2.5203 1.4552v-2.9104z" fill="#d6d2d2" stroke-width=".26458"/>
<metadata>
<rdf:RDF>
<cc:Work rdf:about="">
<dc:title>Prism Launcher Logo</dc:title>
<dc:date>19/10/2022</dc:date>
<dc:creator>
<cc:Agent>
<dc:title>Prism Launcher</dc:title>
</cc:Agent>
</dc:creator>
<dc:contributor>
<cc:Agent>
<dc:title>AutiOne, Boba, ely, Fulmine, gon sawa, Pankakes, tobimori, Zeke</dc:title>
</cc:Agent>
</dc:contributor>
<dc:source>https://github.com/PrismLauncher/PrismLauncher</dc:source>
<dc:publisher>
<cc:Agent>
<dc:title>Prism Launcher</dc:title>
</cc:Agent>
</dc:publisher>
<cc:license rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/"/>
</cc:Work>
<cc:License rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
<cc:permits rdf:resource="http://creativecommons.org/ns#Reproduction"/>
<cc:permits rdf:resource="http://creativecommons.org/ns#Distribution"/>
<cc:requires rdf:resource="http://creativecommons.org/ns#Notice"/>
<cc:requires rdf:resource="http://creativecommons.org/ns#Attribution"/>
<cc:permits rdf:resource="http://creativecommons.org/ns#DerivativeWorks"/>
<cc:requires rdf:resource="http://creativecommons.org/ns#ShareAlike"/>
</cc:License>
</rdf:RDF>
</metadata>
</svg>

Before

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -18,7 +18,6 @@
<file>scalable/jarmods.svg</file> <file>scalable/jarmods.svg</file>
<file>scalable/java.svg</file> <file>scalable/java.svg</file>
<file>scalable/language.svg</file> <file>scalable/language.svg</file>
<file>scalable/launcher.svg</file>
<file>scalable/loadermods.svg</file> <file>scalable/loadermods.svg</file>
<file>scalable/log.svg</file> <file>scalable/log.svg</file>
<file>scalable/minecraft.svg</file> <file>scalable/minecraft.svg</file>

View File

@ -1,57 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg width="48" height="48" version="1.1" viewBox="0 0 12.7 12.7" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<title>Prism Launcher Logo</title>
<g stroke-width=".26458">
<path d="m6.35 6.35" fill="#99cd61"/>
<path d="m6.35 0.52917-2.5208 4.3656 2.5208 1.4552 2.5203-1.4552 0.10955-3.0996c-1.1511-0.66459-2.3388-1.2661-2.6298-1.2661z" fill="#df6277"/>
<path d="m8.9798 1.7952-2.6298 4.5548 2.5203 1.4552 2.5208-4.3656c-0.14552-0.25205-1.2601-0.97975-2.4112-1.6443z" fill="#fb9168"/>
<path d="m11.391 3.4396-5.041 2.9104 2.5203 1.4552 2.7389-1.4552c0-1.3292-0.072554-2.6584-0.21808-2.9104z" fill="#f3db6c"/>
<path d="m6.35 6.35v2.9104h5.041c0.14552-0.25205 0.21807-1.5812 0.21808-2.9104h-5.2591z" fill="#7ab392"/>
<path d="m6.35 6.35v2.9104l2.6298 1.6443c1.1511-0.66459 2.2657-1.3923 2.4112-1.6443l-5.041-2.9104z" fill="#4b7cbc"/>
<path d="m6.35 6.35-2.5208 1.4552 2.5208 4.3656c0.29104 0 1.4787-0.60148 2.6298-1.2661l-2.6298-4.5548z" fill="#6f488c"/>
<path d="m3.8292 4.8948-2.5203 4.3656c0.29104 0.5041 4.459 2.9104 5.041 2.9104v-5.8208l-2.5208-1.4552z" fill="#4d3f33"/>
<path d="m1.309 3.4396c-0.29104 0.5041-0.29104 5.3167 0 5.8208l5.041-2.9104v-2.9104h-5.041z" fill="#7a573b"/>
<path d="m6.35 0.52917c-0.58208-2e-8 -4.75 2.4063-5.041 2.9104l5.041 2.9104v-5.8208z" fill="#99cd61"/>
</g>
<g transform="matrix(.88 0 0 .88 -10.906 -1.2421)">
<g transform="translate(13.26 2.2776)">
<path transform="matrix(.96975 0 0 .96975 .1921 .1921)" d="m6.3498 2.9393c-0.34105 0-2.7827 1.4099-2.9532 1.7052l2.9532 5.1157 2.9538-5.1157c-0.17052-0.29535-2.6127-1.7052-2.9538-1.7052z" fill="#fff" stroke-width=".26458"/>
</g>
<path d="m16.746 6.9737 2.8639 4.9609c0.33073 0 2.6991-1.3672 2.8644-1.6536 0.16536-0.28642 0.16536-3.0209 0-3.3073l-2.8644 1.6536z" fill="#dfdfdf" stroke-width=".26458"/>
</g>
<path d="m3.8299 4.8948c-0.14551 0.25205-0.14553 2.6584 0 2.9104 0.14553 0.25204 2.2292 1.4552 2.5203 1.4552v-2.9104z" fill="#d6d2d2" stroke-width=".26458"/>
<metadata>
<rdf:RDF>
<cc:Work rdf:about="">
<dc:title>Prism Launcher Logo</dc:title>
<dc:date>19/10/2022</dc:date>
<dc:creator>
<cc:Agent>
<dc:title>Prism Launcher</dc:title>
</cc:Agent>
</dc:creator>
<dc:contributor>
<cc:Agent>
<dc:title>AutiOne, Boba, ely, Fulmine, gon sawa, Pankakes, tobimori, Zeke</dc:title>
</cc:Agent>
</dc:contributor>
<dc:source>https://github.com/PrismLauncher/PrismLauncher</dc:source>
<dc:publisher>
<cc:Agent>
<dc:title>Prism Launcher</dc:title>
</cc:Agent>
</dc:publisher>
<cc:license rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/"/>
</cc:Work>
<cc:License rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
<cc:permits rdf:resource="http://creativecommons.org/ns#Reproduction"/>
<cc:permits rdf:resource="http://creativecommons.org/ns#Distribution"/>
<cc:requires rdf:resource="http://creativecommons.org/ns#Notice"/>
<cc:requires rdf:resource="http://creativecommons.org/ns#Attribution"/>
<cc:permits rdf:resource="http://creativecommons.org/ns#DerivativeWorks"/>
<cc:requires rdf:resource="http://creativecommons.org/ns#ShareAlike"/>
</cc:License>
</rdf:RDF>
</metadata>
</svg>

Before

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -18,7 +18,6 @@
<file>scalable/jarmods.svg</file> <file>scalable/jarmods.svg</file>
<file>scalable/java.svg</file> <file>scalable/java.svg</file>
<file>scalable/language.svg</file> <file>scalable/language.svg</file>
<file>scalable/launcher.svg</file>
<file>scalable/loadermods.svg</file> <file>scalable/loadermods.svg</file>
<file>scalable/log.svg</file> <file>scalable/log.svg</file>
<file>scalable/minecraft.svg</file> <file>scalable/minecraft.svg</file>

View File

@ -1,2 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg width="24" height="24" fill="#eeeeee" version="1.1" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg"><path d="m20 4h-16v16h16zm0 18h-16c-1.1046 0-2-0.89543-2-2v-16c0-1.1046 0.89543-2 2-2h16c1.1046 0 2 0.89543 2 2v16c0 1.1046-0.89543 2-2 2z"/><path d="m7.2 18c-0.225 0-0.45-0.075-0.6-0.15-0.375-0.225-0.6-0.6-0.6-1.05v-9.6c0-0.45 0.225-0.825 0.6-1.05 0.225-0.15 0.375-0.15 0.6-0.15 0.15 0 0.375 0.075 0.525 0.15l9.6 4.8c0.375 0.225 0.675 0.6 0.675 1.05 0 0.45-0.225 0.9-0.675 1.05l-9.6 4.8c-0.15 0.075-0.375 0.15-0.525 0.15z" clip-rule="evenodd" fill="#eeeeee" fill-rule="evenodd" stroke-width=".99999"/></svg>

Before

Width:  |  Height:  |  Size: 660 B

View File

@ -16,7 +16,6 @@
<file>scalable/jarmods.svg</file> <file>scalable/jarmods.svg</file>
<file>scalable/java.svg</file> <file>scalable/java.svg</file>
<file>scalable/language.svg</file> <file>scalable/language.svg</file>
<file>scalable/launcher.svg</file>
<file>scalable/loadermods.svg</file> <file>scalable/loadermods.svg</file>
<file>scalable/log.svg</file> <file>scalable/log.svg</file>
<file>scalable/minecraft.svg</file> <file>scalable/minecraft.svg</file>

View File

@ -1,57 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg width="48" height="48" version="1.1" viewBox="0 0 12.7 12.7" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<title>Prism Launcher Logo</title>
<g stroke-width=".26458">
<path d="m6.35 6.35" fill="#99cd61"/>
<path d="m6.35 0.52917-2.5208 4.3656 2.5208 1.4552 2.5203-1.4552 0.10955-3.0996c-1.1511-0.66459-2.3388-1.2661-2.6298-1.2661z" fill="#df6277"/>
<path d="m8.9798 1.7952-2.6298 4.5548 2.5203 1.4552 2.5208-4.3656c-0.14552-0.25205-1.2601-0.97975-2.4112-1.6443z" fill="#fb9168"/>
<path d="m11.391 3.4396-5.041 2.9104 2.5203 1.4552 2.7389-1.4552c0-1.3292-0.072554-2.6584-0.21808-2.9104z" fill="#f3db6c"/>
<path d="m6.35 6.35v2.9104h5.041c0.14552-0.25205 0.21807-1.5812 0.21808-2.9104h-5.2591z" fill="#7ab392"/>
<path d="m6.35 6.35v2.9104l2.6298 1.6443c1.1511-0.66459 2.2657-1.3923 2.4112-1.6443l-5.041-2.9104z" fill="#4b7cbc"/>
<path d="m6.35 6.35-2.5208 1.4552 2.5208 4.3656c0.29104 0 1.4787-0.60148 2.6298-1.2661l-2.6298-4.5548z" fill="#6f488c"/>
<path d="m3.8292 4.8948-2.5203 4.3656c0.29104 0.5041 4.459 2.9104 5.041 2.9104v-5.8208l-2.5208-1.4552z" fill="#4d3f33"/>
<path d="m1.309 3.4396c-0.29104 0.5041-0.29104 5.3167 0 5.8208l5.041-2.9104v-2.9104h-5.041z" fill="#7a573b"/>
<path d="m6.35 0.52917c-0.58208-2e-8 -4.75 2.4063-5.041 2.9104l5.041 2.9104v-5.8208z" fill="#99cd61"/>
</g>
<g transform="matrix(.88 0 0 .88 -10.906 -1.2421)">
<g transform="translate(13.26 2.2776)">
<path transform="matrix(.96975 0 0 .96975 .1921 .1921)" d="m6.3498 2.9393c-0.34105 0-2.7827 1.4099-2.9532 1.7052l2.9532 5.1157 2.9538-5.1157c-0.17052-0.29535-2.6127-1.7052-2.9538-1.7052z" fill="#fff" stroke-width=".26458"/>
</g>
<path d="m16.746 6.9737 2.8639 4.9609c0.33073 0 2.6991-1.3672 2.8644-1.6536 0.16536-0.28642 0.16536-3.0209 0-3.3073l-2.8644 1.6536z" fill="#dfdfdf" stroke-width=".26458"/>
</g>
<path d="m3.8299 4.8948c-0.14551 0.25205-0.14553 2.6584 0 2.9104 0.14553 0.25204 2.2292 1.4552 2.5203 1.4552v-2.9104z" fill="#d6d2d2" stroke-width=".26458"/>
<metadata>
<rdf:RDF>
<cc:Work rdf:about="">
<dc:title>Prism Launcher Logo</dc:title>
<dc:date>19/10/2022</dc:date>
<dc:creator>
<cc:Agent>
<dc:title>Prism Launcher</dc:title>
</cc:Agent>
</dc:creator>
<dc:contributor>
<cc:Agent>
<dc:title>AutiOne, Boba, ely, Fulmine, gon sawa, Pankakes, tobimori, Zeke</dc:title>
</cc:Agent>
</dc:contributor>
<dc:source>https://github.com/PrismLauncher/PrismLauncher</dc:source>
<dc:publisher>
<cc:Agent>
<dc:title>Prism Launcher</dc:title>
</cc:Agent>
</dc:publisher>
<cc:license rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/"/>
</cc:Work>
<cc:License rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
<cc:permits rdf:resource="http://creativecommons.org/ns#Reproduction"/>
<cc:permits rdf:resource="http://creativecommons.org/ns#Distribution"/>
<cc:requires rdf:resource="http://creativecommons.org/ns#Notice"/>
<cc:requires rdf:resource="http://creativecommons.org/ns#Attribution"/>
<cc:permits rdf:resource="http://creativecommons.org/ns#DerivativeWorks"/>
<cc:requires rdf:resource="http://creativecommons.org/ns#ShareAlike"/>
</cc:License>
</rdf:RDF>
</metadata>
</svg>

Before

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -16,7 +16,6 @@
<file>scalable/jarmods.svg</file> <file>scalable/jarmods.svg</file>
<file>scalable/java.svg</file> <file>scalable/java.svg</file>
<file>scalable/language.svg</file> <file>scalable/language.svg</file>
<file>scalable/launcher.svg</file>
<file>scalable/loadermods.svg</file> <file>scalable/loadermods.svg</file>
<file>scalable/log.svg</file> <file>scalable/log.svg</file>
<file>scalable/minecraft.svg</file> <file>scalable/minecraft.svg</file>

View File

@ -1,57 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg width="48" height="48" version="1.1" viewBox="0 0 12.7 12.7" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<title>Prism Launcher Logo</title>
<g stroke-width=".26458">
<path d="m6.35 6.35" fill="#99cd61"/>
<path d="m6.35 0.52917-2.5208 4.3656 2.5208 1.4552 2.5203-1.4552 0.10955-3.0996c-1.1511-0.66459-2.3388-1.2661-2.6298-1.2661z" fill="#df6277"/>
<path d="m8.9798 1.7952-2.6298 4.5548 2.5203 1.4552 2.5208-4.3656c-0.14552-0.25205-1.2601-0.97975-2.4112-1.6443z" fill="#fb9168"/>
<path d="m11.391 3.4396-5.041 2.9104 2.5203 1.4552 2.7389-1.4552c0-1.3292-0.072554-2.6584-0.21808-2.9104z" fill="#f3db6c"/>
<path d="m6.35 6.35v2.9104h5.041c0.14552-0.25205 0.21807-1.5812 0.21808-2.9104h-5.2591z" fill="#7ab392"/>
<path d="m6.35 6.35v2.9104l2.6298 1.6443c1.1511-0.66459 2.2657-1.3923 2.4112-1.6443l-5.041-2.9104z" fill="#4b7cbc"/>
<path d="m6.35 6.35-2.5208 1.4552 2.5208 4.3656c0.29104 0 1.4787-0.60148 2.6298-1.2661l-2.6298-4.5548z" fill="#6f488c"/>
<path d="m3.8292 4.8948-2.5203 4.3656c0.29104 0.5041 4.459 2.9104 5.041 2.9104v-5.8208l-2.5208-1.4552z" fill="#4d3f33"/>
<path d="m1.309 3.4396c-0.29104 0.5041-0.29104 5.3167 0 5.8208l5.041-2.9104v-2.9104h-5.041z" fill="#7a573b"/>
<path d="m6.35 0.52917c-0.58208-2e-8 -4.75 2.4063-5.041 2.9104l5.041 2.9104v-5.8208z" fill="#99cd61"/>
</g>
<g transform="matrix(.88 0 0 .88 -10.906 -1.2421)">
<g transform="translate(13.26 2.2776)">
<path transform="matrix(.96975 0 0 .96975 .1921 .1921)" d="m6.3498 2.9393c-0.34105 0-2.7827 1.4099-2.9532 1.7052l2.9532 5.1157 2.9538-5.1157c-0.17052-0.29535-2.6127-1.7052-2.9538-1.7052z" fill="#fff" stroke-width=".26458"/>
</g>
<path d="m16.746 6.9737 2.8639 4.9609c0.33073 0 2.6991-1.3672 2.8644-1.6536 0.16536-0.28642 0.16536-3.0209 0-3.3073l-2.8644 1.6536z" fill="#dfdfdf" stroke-width=".26458"/>
</g>
<path d="m3.8299 4.8948c-0.14551 0.25205-0.14553 2.6584 0 2.9104 0.14553 0.25204 2.2292 1.4552 2.5203 1.4552v-2.9104z" fill="#d6d2d2" stroke-width=".26458"/>
<metadata>
<rdf:RDF>
<cc:Work rdf:about="">
<dc:title>Prism Launcher Logo</dc:title>
<dc:date>19/10/2022</dc:date>
<dc:creator>
<cc:Agent>
<dc:title>Prism Launcher</dc:title>
</cc:Agent>
</dc:creator>
<dc:contributor>
<cc:Agent>
<dc:title>AutiOne, Boba, ely, Fulmine, gon sawa, Pankakes, tobimori, Zeke</dc:title>
</cc:Agent>
</dc:contributor>
<dc:source>https://github.com/PrismLauncher/PrismLauncher</dc:source>
<dc:publisher>
<cc:Agent>
<dc:title>Prism Launcher</dc:title>
</cc:Agent>
</dc:publisher>
<cc:license rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/"/>
</cc:Work>
<cc:License rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
<cc:permits rdf:resource="http://creativecommons.org/ns#Reproduction"/>
<cc:permits rdf:resource="http://creativecommons.org/ns#Distribution"/>
<cc:requires rdf:resource="http://creativecommons.org/ns#Notice"/>
<cc:requires rdf:resource="http://creativecommons.org/ns#Attribution"/>
<cc:permits rdf:resource="http://creativecommons.org/ns#DerivativeWorks"/>
<cc:requires rdf:resource="http://creativecommons.org/ns#ShareAlike"/>
</cc:License>
</rdf:RDF>
</metadata>
</svg>

Before

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -16,7 +16,6 @@
<file>scalable/jarmods.svg</file> <file>scalable/jarmods.svg</file>
<file>scalable/java.svg</file> <file>scalable/java.svg</file>
<file>scalable/language.svg</file> <file>scalable/language.svg</file>
<file>scalable/launcher.svg</file>
<file>scalable/loadermods.svg</file> <file>scalable/loadermods.svg</file>
<file>scalable/log.svg</file> <file>scalable/log.svg</file>
<file>scalable/minecraft.svg</file> <file>scalable/minecraft.svg</file>

View File

@ -1,57 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg width="48" height="48" version="1.1" viewBox="0 0 12.7 12.7" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<title>Prism Launcher Logo</title>
<g stroke-width=".26458">
<path d="m6.35 6.35" fill="#99cd61"/>
<path d="m6.35 0.52917-2.5208 4.3656 2.5208 1.4552 2.5203-1.4552 0.10955-3.0996c-1.1511-0.66459-2.3388-1.2661-2.6298-1.2661z" fill="#df6277"/>
<path d="m8.9798 1.7952-2.6298 4.5548 2.5203 1.4552 2.5208-4.3656c-0.14552-0.25205-1.2601-0.97975-2.4112-1.6443z" fill="#fb9168"/>
<path d="m11.391 3.4396-5.041 2.9104 2.5203 1.4552 2.7389-1.4552c0-1.3292-0.072554-2.6584-0.21808-2.9104z" fill="#f3db6c"/>
<path d="m6.35 6.35v2.9104h5.041c0.14552-0.25205 0.21807-1.5812 0.21808-2.9104h-5.2591z" fill="#7ab392"/>
<path d="m6.35 6.35v2.9104l2.6298 1.6443c1.1511-0.66459 2.2657-1.3923 2.4112-1.6443l-5.041-2.9104z" fill="#4b7cbc"/>
<path d="m6.35 6.35-2.5208 1.4552 2.5208 4.3656c0.29104 0 1.4787-0.60148 2.6298-1.2661l-2.6298-4.5548z" fill="#6f488c"/>
<path d="m3.8292 4.8948-2.5203 4.3656c0.29104 0.5041 4.459 2.9104 5.041 2.9104v-5.8208l-2.5208-1.4552z" fill="#4d3f33"/>
<path d="m1.309 3.4396c-0.29104 0.5041-0.29104 5.3167 0 5.8208l5.041-2.9104v-2.9104h-5.041z" fill="#7a573b"/>
<path d="m6.35 0.52917c-0.58208-2e-8 -4.75 2.4063-5.041 2.9104l5.041 2.9104v-5.8208z" fill="#99cd61"/>
</g>
<g transform="matrix(.88 0 0 .88 -10.906 -1.2421)">
<g transform="translate(13.26 2.2776)">
<path transform="matrix(.96975 0 0 .96975 .1921 .1921)" d="m6.3498 2.9393c-0.34105 0-2.7827 1.4099-2.9532 1.7052l2.9532 5.1157 2.9538-5.1157c-0.17052-0.29535-2.6127-1.7052-2.9538-1.7052z" fill="#fff" stroke-width=".26458"/>
</g>
<path d="m16.746 6.9737 2.8639 4.9609c0.33073 0 2.6991-1.3672 2.8644-1.6536 0.16536-0.28642 0.16536-3.0209 0-3.3073l-2.8644 1.6536z" fill="#dfdfdf" stroke-width=".26458"/>
</g>
<path d="m3.8299 4.8948c-0.14551 0.25205-0.14553 2.6584 0 2.9104 0.14553 0.25204 2.2292 1.4552 2.5203 1.4552v-2.9104z" fill="#d6d2d2" stroke-width=".26458"/>
<metadata>
<rdf:RDF>
<cc:Work rdf:about="">
<dc:title>Prism Launcher Logo</dc:title>
<dc:date>19/10/2022</dc:date>
<dc:creator>
<cc:Agent>
<dc:title>Prism Launcher</dc:title>
</cc:Agent>
</dc:creator>
<dc:contributor>
<cc:Agent>
<dc:title>AutiOne, Boba, ely, Fulmine, gon sawa, Pankakes, tobimori, Zeke</dc:title>
</cc:Agent>
</dc:contributor>
<dc:source>https://github.com/PrismLauncher/PrismLauncher</dc:source>
<dc:publisher>
<cc:Agent>
<dc:title>Prism Launcher</dc:title>
</cc:Agent>
</dc:publisher>
<cc:license rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/"/>
</cc:Work>
<cc:License rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
<cc:permits rdf:resource="http://creativecommons.org/ns#Reproduction"/>
<cc:permits rdf:resource="http://creativecommons.org/ns#Distribution"/>
<cc:requires rdf:resource="http://creativecommons.org/ns#Notice"/>
<cc:requires rdf:resource="http://creativecommons.org/ns#Attribution"/>
<cc:permits rdf:resource="http://creativecommons.org/ns#DerivativeWorks"/>
<cc:requires rdf:resource="http://creativecommons.org/ns#ShareAlike"/>
</cc:License>
</rdf:RDF>
</metadata>
</svg>

Before

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -16,7 +16,6 @@
<file>scalable/jarmods.svg</file> <file>scalable/jarmods.svg</file>
<file>scalable/java.svg</file> <file>scalable/java.svg</file>
<file>scalable/language.svg</file> <file>scalable/language.svg</file>
<file>scalable/launcher.svg</file>
<file>scalable/loadermods.svg</file> <file>scalable/loadermods.svg</file>
<file>scalable/log.svg</file> <file>scalable/log.svg</file>
<file>scalable/minecraft.svg</file> <file>scalable/minecraft.svg</file>

View File

@ -1,57 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg width="48" height="48" version="1.1" viewBox="0 0 12.7 12.7" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<title>Prism Launcher Logo</title>
<g stroke-width=".26458">
<path d="m6.35 6.35" fill="#99cd61"/>
<path d="m6.35 0.52917-2.5208 4.3656 2.5208 1.4552 2.5203-1.4552 0.10955-3.0996c-1.1511-0.66459-2.3388-1.2661-2.6298-1.2661z" fill="#df6277"/>
<path d="m8.9798 1.7952-2.6298 4.5548 2.5203 1.4552 2.5208-4.3656c-0.14552-0.25205-1.2601-0.97975-2.4112-1.6443z" fill="#fb9168"/>
<path d="m11.391 3.4396-5.041 2.9104 2.5203 1.4552 2.7389-1.4552c0-1.3292-0.072554-2.6584-0.21808-2.9104z" fill="#f3db6c"/>
<path d="m6.35 6.35v2.9104h5.041c0.14552-0.25205 0.21807-1.5812 0.21808-2.9104h-5.2591z" fill="#7ab392"/>
<path d="m6.35 6.35v2.9104l2.6298 1.6443c1.1511-0.66459 2.2657-1.3923 2.4112-1.6443l-5.041-2.9104z" fill="#4b7cbc"/>
<path d="m6.35 6.35-2.5208 1.4552 2.5208 4.3656c0.29104 0 1.4787-0.60148 2.6298-1.2661l-2.6298-4.5548z" fill="#6f488c"/>
<path d="m3.8292 4.8948-2.5203 4.3656c0.29104 0.5041 4.459 2.9104 5.041 2.9104v-5.8208l-2.5208-1.4552z" fill="#4d3f33"/>
<path d="m1.309 3.4396c-0.29104 0.5041-0.29104 5.3167 0 5.8208l5.041-2.9104v-2.9104h-5.041z" fill="#7a573b"/>
<path d="m6.35 0.52917c-0.58208-2e-8 -4.75 2.4063-5.041 2.9104l5.041 2.9104v-5.8208z" fill="#99cd61"/>
</g>
<g transform="matrix(.88 0 0 .88 -10.906 -1.2421)">
<g transform="translate(13.26 2.2776)">
<path transform="matrix(.96975 0 0 .96975 .1921 .1921)" d="m6.3498 2.9393c-0.34105 0-2.7827 1.4099-2.9532 1.7052l2.9532 5.1157 2.9538-5.1157c-0.17052-0.29535-2.6127-1.7052-2.9538-1.7052z" fill="#fff" stroke-width=".26458"/>
</g>
<path d="m16.746 6.9737 2.8639 4.9609c0.33073 0 2.6991-1.3672 2.8644-1.6536 0.16536-0.28642 0.16536-3.0209 0-3.3073l-2.8644 1.6536z" fill="#dfdfdf" stroke-width=".26458"/>
</g>
<path d="m3.8299 4.8948c-0.14551 0.25205-0.14553 2.6584 0 2.9104 0.14553 0.25204 2.2292 1.4552 2.5203 1.4552v-2.9104z" fill="#d6d2d2" stroke-width=".26458"/>
<metadata>
<rdf:RDF>
<cc:Work rdf:about="">
<dc:title>Prism Launcher Logo</dc:title>
<dc:date>19/10/2022</dc:date>
<dc:creator>
<cc:Agent>
<dc:title>Prism Launcher</dc:title>
</cc:Agent>
</dc:creator>
<dc:contributor>
<cc:Agent>
<dc:title>AutiOne, Boba, ely, Fulmine, gon sawa, Pankakes, tobimori, Zeke</dc:title>
</cc:Agent>
</dc:contributor>
<dc:source>https://github.com/PrismLauncher/PrismLauncher</dc:source>
<dc:publisher>
<cc:Agent>
<dc:title>Prism Launcher</dc:title>
</cc:Agent>
</dc:publisher>
<cc:license rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/"/>
</cc:Work>
<cc:License rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
<cc:permits rdf:resource="http://creativecommons.org/ns#Reproduction"/>
<cc:permits rdf:resource="http://creativecommons.org/ns#Distribution"/>
<cc:requires rdf:resource="http://creativecommons.org/ns#Notice"/>
<cc:requires rdf:resource="http://creativecommons.org/ns#Attribution"/>
<cc:permits rdf:resource="http://creativecommons.org/ns#DerivativeWorks"/>
<cc:requires rdf:resource="http://creativecommons.org/ns#ShareAlike"/>
</cc:License>
</rdf:RDF>
</metadata>
</svg>

Before

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -16,7 +16,6 @@
<file>scalable/jarmods.svg</file> <file>scalable/jarmods.svg</file>
<file>scalable/java.svg</file> <file>scalable/java.svg</file>
<file>scalable/language.svg</file> <file>scalable/language.svg</file>
<file>scalable/launcher.svg</file>
<file>scalable/loadermods.svg</file> <file>scalable/loadermods.svg</file>
<file>scalable/log.svg</file> <file>scalable/log.svg</file>
<file>scalable/minecraft.svg</file> <file>scalable/minecraft.svg</file>

View File

@ -1,57 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg width="48" height="48" version="1.1" viewBox="0 0 12.7 12.7" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<title>Prism Launcher Logo</title>
<g stroke-width=".26458">
<path d="m6.35 6.35" fill="#99cd61"/>
<path d="m6.35 0.52917-2.5208 4.3656 2.5208 1.4552 2.5203-1.4552 0.10955-3.0996c-1.1511-0.66459-2.3388-1.2661-2.6298-1.2661z" fill="#df6277"/>
<path d="m8.9798 1.7952-2.6298 4.5548 2.5203 1.4552 2.5208-4.3656c-0.14552-0.25205-1.2601-0.97975-2.4112-1.6443z" fill="#fb9168"/>
<path d="m11.391 3.4396-5.041 2.9104 2.5203 1.4552 2.7389-1.4552c0-1.3292-0.072554-2.6584-0.21808-2.9104z" fill="#f3db6c"/>
<path d="m6.35 6.35v2.9104h5.041c0.14552-0.25205 0.21807-1.5812 0.21808-2.9104h-5.2591z" fill="#7ab392"/>
<path d="m6.35 6.35v2.9104l2.6298 1.6443c1.1511-0.66459 2.2657-1.3923 2.4112-1.6443l-5.041-2.9104z" fill="#4b7cbc"/>
<path d="m6.35 6.35-2.5208 1.4552 2.5208 4.3656c0.29104 0 1.4787-0.60148 2.6298-1.2661l-2.6298-4.5548z" fill="#6f488c"/>
<path d="m3.8292 4.8948-2.5203 4.3656c0.29104 0.5041 4.459 2.9104 5.041 2.9104v-5.8208l-2.5208-1.4552z" fill="#4d3f33"/>
<path d="m1.309 3.4396c-0.29104 0.5041-0.29104 5.3167 0 5.8208l5.041-2.9104v-2.9104h-5.041z" fill="#7a573b"/>
<path d="m6.35 0.52917c-0.58208-2e-8 -4.75 2.4063-5.041 2.9104l5.041 2.9104v-5.8208z" fill="#99cd61"/>
</g>
<g transform="matrix(.88 0 0 .88 -10.906 -1.2421)">
<g transform="translate(13.26 2.2776)">
<path transform="matrix(.96975 0 0 .96975 .1921 .1921)" d="m6.3498 2.9393c-0.34105 0-2.7827 1.4099-2.9532 1.7052l2.9532 5.1157 2.9538-5.1157c-0.17052-0.29535-2.6127-1.7052-2.9538-1.7052z" fill="#fff" stroke-width=".26458"/>
</g>
<path d="m16.746 6.9737 2.8639 4.9609c0.33073 0 2.6991-1.3672 2.8644-1.6536 0.16536-0.28642 0.16536-3.0209 0-3.3073l-2.8644 1.6536z" fill="#dfdfdf" stroke-width=".26458"/>
</g>
<path d="m3.8299 4.8948c-0.14551 0.25205-0.14553 2.6584 0 2.9104 0.14553 0.25204 2.2292 1.4552 2.5203 1.4552v-2.9104z" fill="#d6d2d2" stroke-width=".26458"/>
<metadata>
<rdf:RDF>
<cc:Work rdf:about="">
<dc:title>Prism Launcher Logo</dc:title>
<dc:date>19/10/2022</dc:date>
<dc:creator>
<cc:Agent>
<dc:title>Prism Launcher</dc:title>
</cc:Agent>
</dc:creator>
<dc:contributor>
<cc:Agent>
<dc:title>AutiOne, Boba, ely, Fulmine, gon sawa, Pankakes, tobimori, Zeke</dc:title>
</cc:Agent>
</dc:contributor>
<dc:source>https://github.com/PrismLauncher/PrismLauncher</dc:source>
<dc:publisher>
<cc:Agent>
<dc:title>Prism Launcher</dc:title>
</cc:Agent>
</dc:publisher>
<cc:license rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/"/>
</cc:Work>
<cc:License rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
<cc:permits rdf:resource="http://creativecommons.org/ns#Reproduction"/>
<cc:permits rdf:resource="http://creativecommons.org/ns#Distribution"/>
<cc:requires rdf:resource="http://creativecommons.org/ns#Notice"/>
<cc:requires rdf:resource="http://creativecommons.org/ns#Attribution"/>
<cc:permits rdf:resource="http://creativecommons.org/ns#DerivativeWorks"/>
<cc:requires rdf:resource="http://creativecommons.org/ns#ShareAlike"/>
</cc:License>
</rdf:RDF>
</metadata>
</svg>

Before

Width:  |  Height:  |  Size: 3.4 KiB

View File

@ -225,6 +225,13 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new Ui::MainWi
// disabled until we have an instance selected // disabled until we have an instance selected
ui->instanceToolBar->setEnabled(false); ui->instanceToolBar->setEnabled(false);
setInstanceActionsEnabled(false); setInstanceActionsEnabled(false);
// add a close button at the end of the main toolbar when running on gamescope / steam deck
// FIXME: detect if we don't have server side decorations instead
if (qgetenv("XDG_CURRENT_DESKTOP") == "gamescope") {
ui->mainToolBar->addAction(ui->actionCloseWindow);
}
} }
// add the toolbar toggles to the view menu // add the toolbar toggles to the view menu
@ -1528,140 +1535,113 @@ void MainWindow::on_actionKillInstance_triggered()
void MainWindow::on_actionCreateInstanceShortcut_triggered() void MainWindow::on_actionCreateInstanceShortcut_triggered()
{ {
if (m_selectedInstance) if (!m_selectedInstance)
{ return;
auto desktopPath = FS::getDesktopDir(); auto desktopPath = FS::getDesktopDir();
if (desktopPath.isEmpty()) { if (desktopPath.isEmpty()) {
// TODO come up with an alternative solution (open "save file" dialog) // TODO come up with an alternative solution (open "save file" dialog)
QMessageBox::critical(this, tr("Create instance shortcut"), tr("Couldn't find desktop?!")); QMessageBox::critical(this, tr("Create instance shortcut"), tr("Couldn't find desktop?!"));
return; return;
} }
QString desktopFilePath;
QString appPath = QApplication::applicationFilePath();
QString iconPath;
QStringList args;
#if defined(Q_OS_MACOS) #if defined(Q_OS_MACOS)
QString appPath = QApplication::applicationFilePath(); if (appPath.startsWith("/private/var/")) {
if (appPath.startsWith("/private/var/")) { QMessageBox::critical(this, tr("Create instance shortcut"),
QMessageBox::critical(this, tr("Create instance shortcut"), tr("The launcher is in the folder it was extracted from, therefore it cannot create shortcuts.")); tr("The launcher is in the folder it was extracted from, therefore it cannot create shortcuts."));
return; return;
} }
if (FS::createShortcut(FS::PathCombine(desktopPath, m_selectedInstance->name()),
appPath, { "--launch", m_selectedInstance->id() },
m_selectedInstance->name(), "")) {
QMessageBox::information(this, tr("Create instance shortcut"), tr("Created a shortcut to this instance on your desktop!"));
}
else
{
QMessageBox::critical(this, tr("Create instance shortcut"), tr("Failed to create instance shortcut!"));
}
#elif defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD) #elif defined(Q_OS_LINUX) || defined(Q_OS_FREEBSD) || defined(Q_OS_OPENBSD)
QString appPath = QApplication::applicationFilePath(); if (appPath.startsWith("/tmp/.mount_")) {
if (appPath.startsWith("/tmp/.mount_")) { // AppImage!
// AppImage! appPath = QProcessEnvironment::systemEnvironment().value(QStringLiteral("APPIMAGE"));
appPath = QProcessEnvironment::systemEnvironment().value(QStringLiteral("APPIMAGE")); if (appPath.isEmpty()) {
if (appPath.isEmpty()) QMessageBox::critical(this, tr("Create instance shortcut"),
{ tr("Launcher is running as misconfigured AppImage? ($APPIMAGE environment variable is missing)"));
QMessageBox::critical(this, tr("Create instance shortcut"), tr("Launcher is running as misconfigured AppImage? ($APPIMAGE environment variable is missing)")); } else if (appPath.endsWith("/")) {
} appPath.chop(1);
else if (appPath.endsWith("/"))
{
appPath.chop(1);
}
} }
}
auto icon = APPLICATION->icons()->icon(m_selectedInstance->iconKey()); auto icon = APPLICATION->icons()->icon(m_selectedInstance->iconKey());
if (icon == nullptr) if (icon == nullptr) {
{ icon = APPLICATION->icons()->icon("grass");
icon = APPLICATION->icons()->icon("grass"); }
}
QString iconPath = FS::PathCombine(m_selectedInstance->instanceRoot(), "icon.png"); iconPath = FS::PathCombine(m_selectedInstance->instanceRoot(), "icon.png");
QFile iconFile(iconPath); QFile iconFile(iconPath);
if (!iconFile.open(QFile::WriteOnly)) if (!iconFile.open(QFile::WriteOnly)) {
{ QMessageBox::critical(this, tr("Create instance shortcut"), tr("Failed to create icon for shortcut."));
QMessageBox::critical(this, tr("Create instance shortcut"), tr("Failed to create icon for shortcut.")); return;
return; }
} bool success = icon->icon().pixmap(64, 64).save(&iconFile, "PNG");
bool success = icon->icon().pixmap(64, 64).save(&iconFile, "PNG"); iconFile.close();
iconFile.close();
if (!success) if (!success) {
{ iconFile.remove();
iconFile.remove(); QMessageBox::critical(this, tr("Create instance shortcut"), tr("Failed to create icon for shortcut."));
QMessageBox::critical(this, tr("Create instance shortcut"), tr("Failed to create icon for shortcut.")); return;
return; }
}
if (DesktopServices::isFlatpak()) {
desktopFilePath = FS::PathCombine(desktopPath, FS::RemoveInvalidFilenameChars(m_selectedInstance->name()) + ".desktop");
QFileDialog fileDialog;
// workaround to make sure the portal file dialog opens in the desktop directory
fileDialog.setDirectoryUrl(desktopPath);
desktopFilePath = fileDialog.getSaveFileName(this, tr("Create Shortcut"), desktopFilePath, tr("Desktop Entries (*.desktop)"));
if (desktopFilePath.isEmpty())
return; // file dialog canceled by user
appPath = "flatpak";
QString flatpakAppId = BuildConfig.LAUNCHER_DESKTOPFILENAME;
flatpakAppId.remove(".desktop");
args.append({ "run", flatpakAppId });
}
QString desktopFilePath = FS::PathCombine(desktopPath, m_selectedInstance->name() + ".desktop");
QStringList args;
if (DesktopServices::isFlatpak()) {
QFileDialog fileDialog;
// workaround to make sure the portal file dialog opens in the desktop directory
fileDialog.setDirectoryUrl(desktopPath);
desktopFilePath = fileDialog.getSaveFileName(
this, tr("Create Shortcut"), desktopFilePath,
tr("Desktop Entries (*.desktop)"));
if (desktopFilePath.isEmpty())
return; // file dialog canceled by user
appPath = "flatpak";
QString flatpakAppId = BuildConfig.LAUNCHER_DESKTOPFILENAME;
flatpakAppId.remove(".desktop");
args.append({ "run", flatpakAppId });
}
args.append({ "--launch", m_selectedInstance->id() });
if (FS::createShortcut(desktopFilePath, appPath, args, m_selectedInstance->name(), iconPath)) {
QMessageBox::information(this, tr("Create instance shortcut"), tr("Created a shortcut to this instance on your desktop!"));
}
else
{
iconFile.remove();
QMessageBox::critical(this, tr("Create instance shortcut"), tr("Failed to create instance shortcut!"));
}
#elif defined(Q_OS_WIN) #elif defined(Q_OS_WIN)
auto icon = APPLICATION->icons()->icon(m_selectedInstance->iconKey()); auto icon = APPLICATION->icons()->icon(m_selectedInstance->iconKey());
if (icon == nullptr) if (icon == nullptr) {
{ icon = APPLICATION->icons()->icon("grass");
icon = APPLICATION->icons()->icon("grass"); }
}
QString iconPath = FS::PathCombine(m_selectedInstance->instanceRoot(), "icon.ico"); iconPath = FS::PathCombine(m_selectedInstance->instanceRoot(), "icon.ico");
// part of fix for weird bug involving the window icon being replaced // part of fix for weird bug involving the window icon being replaced
// dunno why it happens, but this 2-line fix seems to be enough, so w/e // dunno why it happens, but this 2-line fix seems to be enough, so w/e
auto appIcon = APPLICATION->getThemedIcon("logo"); auto appIcon = APPLICATION->getThemedIcon("logo");
QFile iconFile(iconPath); QFile iconFile(iconPath);
if (!iconFile.open(QFile::WriteOnly)) if (!iconFile.open(QFile::WriteOnly)) {
{ QMessageBox::critical(this, tr("Create instance shortcut"), tr("Failed to create icon for shortcut."));
QMessageBox::critical(this, tr("Create instance shortcut"), tr("Failed to create icon for shortcut.")); return;
return; }
} bool success = icon->icon().pixmap(64, 64).save(&iconFile, "ICO");
bool success = icon->icon().pixmap(64, 64).save(&iconFile, "ICO"); iconFile.close();
iconFile.close();
// restore original window icon // restore original window icon
QGuiApplication::setWindowIcon(appIcon); QGuiApplication::setWindowIcon(appIcon);
if (!success) if (!success) {
{ iconFile.remove();
iconFile.remove(); QMessageBox::critical(this, tr("Create instance shortcut"), tr("Failed to create icon for shortcut."));
QMessageBox::critical(this, tr("Create instance shortcut"), tr("Failed to create icon for shortcut.")); return;
return; }
}
if (FS::createShortcut(FS::PathCombine(desktopPath, m_selectedInstance->name()),
QApplication::applicationFilePath(), { "--launch", m_selectedInstance->id() },
m_selectedInstance->name(), iconPath)) {
QMessageBox::information(this, tr("Create instance shortcut"), tr("Created a shortcut to this instance on your desktop!"));
}
else
{
iconFile.remove();
QMessageBox::critical(this, tr("Create instance shortcut"), tr("Failed to create instance shortcut!"));
}
#else #else
QMessageBox::critical(this, tr("Create instance shortcut"), tr("Not supported on your platform!")); QMessageBox::critical(this, tr("Create instance shortcut"), tr("Not supported on your platform!"));
return;
#endif #endif
args.append({ "--launch", m_selectedInstance->id() });
if (FS::createShortcut(desktopFilePath, appPath, args, m_selectedInstance->name(), iconPath)) {
QMessageBox::information(this, tr("Create instance shortcut"), tr("Created a shortcut to this instance on your desktop!"));
} else {
#if not defined(Q_OS_MACOS)
iconFile.remove();
#endif
QMessageBox::critical(this, tr("Create instance shortcut"), tr("Failed to create instance shortcut!"));
} }
} }

View File

@ -35,24 +35,26 @@
*/ */
#include "ExportInstanceDialog.h" #include "ExportInstanceDialog.h"
#include "ui_ExportInstanceDialog.h"
#include <BaseInstance.h> #include <BaseInstance.h>
#include <MMCZip.h> #include <MMCZip.h>
#include <QFileDialog> #include <QFileDialog>
#include <QMessageBox>
#include <QFileSystemModel> #include <QFileSystemModel>
#include <QMessageBox>
#include "FileIgnoreProxy.h"
#include "ui_ExportInstanceDialog.h"
#include <QSortFilterProxyModel>
#include <QDebug>
#include <QSaveFile>
#include <QStack>
#include <QFileInfo>
#include "SeparatorPrefixTree.h"
#include "Application.h"
#include <icons/IconList.h>
#include <FileSystem.h> #include <FileSystem.h>
#include <icons/IconList.h>
#include <QDebug>
#include <QFileInfo>
#include <QSaveFile>
#include <QSortFilterProxyModel>
#include <QStack>
#include <functional>
#include "Application.h"
#include "SeparatorPrefixTree.h"
ExportInstanceDialog::ExportInstanceDialog(InstancePtr instance, QWidget *parent) ExportInstanceDialog::ExportInstanceDialog(InstancePtr instance, QWidget* parent)
: QDialog(parent), ui(new Ui::ExportInstanceDialog), m_instance(instance) : QDialog(parent), ui(new Ui::ExportInstanceDialog), m_instance(instance)
{ {
ui->setupUi(this); ui->setupUi(this);
@ -60,8 +62,12 @@ ExportInstanceDialog::ExportInstanceDialog(InstancePtr instance, QWidget *parent
model->setIconProvider(&icons); model->setIconProvider(&icons);
auto root = instance->instanceRoot(); auto root = instance->instanceRoot();
proxyModel = new FileIgnoreProxy(root, this); proxyModel = new FileIgnoreProxy(root, this);
loadPackIgnore();
proxyModel->setSourceModel(model); proxyModel->setSourceModel(model);
auto prefix = QDir(instance->instanceRoot()).relativeFilePath(instance->gameRoot());
proxyModel->ignoreFilesWithPath().insert({ FS::PathCombine(prefix, "logs"), FS::PathCombine(prefix, "crash-reports") });
proxyModel->ignoreFilesWithName().append({ ".DS_Store", "thumbs.db", "Thumbs.db" });
loadPackIgnore();
ui->treeView->setModel(proxyModel); ui->treeView->setModel(proxyModel);
ui->treeView->setRootIndex(proxyModel->mapFromSource(model->index(root))); ui->treeView->setRootIndex(proxyModel->mapFromSource(model->index(root)));
ui->treeView->sortByColumn(0, Qt::AscendingOrder); ui->treeView->sortByColumn(0, Qt::AscendingOrder);
@ -133,11 +139,9 @@ bool ExportInstanceDialog::doExport()
SaveIcon(m_instance); SaveIcon(m_instance);
auto & blocked = proxyModel->blockedPaths();
using std::placeholders::_1;
auto files = QFileInfoList(); auto files = QFileInfoList();
if (!MMCZip::collectFileListRecursively(m_instance->instanceRoot(), nullptr, &files, if (!MMCZip::collectFileListRecursively(m_instance->instanceRoot(), nullptr, &files,
std::bind(&SeparatorPrefixTree<'/'>::covers, blocked, _1))) { std::bind(&FileIgnoreProxy::filterFile, proxyModel, std::placeholders::_1))) {
QMessageBox::warning(this, tr("Error"), tr("Unable to export instance")); QMessageBox::warning(this, tr("Error"), tr("Unable to export instance"));
return false; return false;
} }

View File

@ -60,8 +60,9 @@ ExportPackDialog::ExportPackDialog(InstancePtr instance, QWidget* parent, ModPla
// use the game root - everything outside cannot be exported // use the game root - everything outside cannot be exported
const QDir root(instance->gameRoot()); const QDir root(instance->gameRoot());
proxy = new FileIgnoreProxy(instance->gameRoot(), this); proxy = new FileIgnoreProxy(instance->gameRoot(), this);
proxy->ignoreFilesWithPath().insert({ "logs", "crash-reports" });
proxy->ignoreFilesWithName().append({ ".DS_Store", "thumbs.db", "Thumbs.db" });
proxy->setSourceModel(model); proxy->setSourceModel(model);
proxy->setFilterRegularExpression("^(?!(\\.DS_Store)|([tT]humbs\\.db)).+$");
const QDir::Filters filter(QDir::AllEntries | QDir::NoDotAndDotDot | QDir::AllDirs | QDir::Hidden); const QDir::Filters filter(QDir::AllEntries | QDir::NoDotAndDotDot | QDir::AllDirs | QDir::Hidden);
@ -114,10 +115,10 @@ void ExportPackDialog::done(int result)
Task* task; Task* task;
if (m_provider == ModPlatform::ResourceProvider::MODRINTH) if (m_provider == ModPlatform::ResourceProvider::MODRINTH)
task = new ModrinthPackExportTask(ui->name->text(), ui->version->text(), ui->summary->text(), instance, output, task = new ModrinthPackExportTask(ui->name->text(), ui->version->text(), ui->summary->text(), instance, output,
[this](const QString& path) { return proxy->blockedPaths().covers(path); }); std::bind(&FileIgnoreProxy::filterFile, proxy, std::placeholders::_1));
else else
task = new FlamePackExportTask(ui->name->text(), ui->version->text(), ui->summary->text(), instance, output, task = new FlamePackExportTask(ui->name->text(), ui->version->text(), ui->summary->text(), instance, output,
[this](const QString& path) { return proxy->blockedPaths().covers(path); }); std::bind(&FileIgnoreProxy::filterFile, proxy, std::placeholders::_1));
connect(task, &Task::failed, connect(task, &Task::failed,
[this](const QString reason) { CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show(); }); [this](const QString reason) { CustomMessageBox::selectable(this, tr("Error"), reason, QMessageBox::Critical)->show(); });

View File

@ -54,7 +54,7 @@
#include <utility> #include <utility>
#include "ui/widgets/PageContainer.h" #include "ui/widgets/PageContainer.h"
#include "ui/pages/modplatform/VanillaPage.h" #include "ui/pages/modplatform/CustomPage.h"
#include "ui/pages/modplatform/atlauncher/AtlPage.h" #include "ui/pages/modplatform/atlauncher/AtlPage.h"
#include "ui/pages/modplatform/legacy_ftb/Page.h" #include "ui/pages/modplatform/legacy_ftb/Page.h"
#include "ui/pages/modplatform/flame/FlamePage.h" #include "ui/pages/modplatform/flame/FlamePage.h"
@ -162,7 +162,7 @@ QList<BasePage *> NewInstanceDialog::getPages()
importPage = new ImportPage(this); importPage = new ImportPage(this);
pages.append(new VanillaPage(this)); pages.append(new CustomPage(this));
pages.append(importPage); pages.append(importPage);
pages.append(new AtlPage(this)); pages.append(new AtlPage(this));
if (APPLICATION->capabilities() & Application::SupportsFlame) if (APPLICATION->capabilities() & Application::SupportsFlame)

View File

@ -44,7 +44,7 @@
class BasePage { class BasePage {
public: public:
using updateExtraInfoFunc = std::function<void(QString)>; using updateExtraInfoFunc = std::function<void(QString, QString)>;
virtual ~BasePage() {} virtual ~BasePage() {}
virtual QString id() const = 0; virtual QString id() const = 0;
virtual QString displayName() const = 0; virtual QString displayName() const = 0;

View File

@ -83,7 +83,7 @@ ExternalResourcesPage::ExternalResourcesPage(BaseInstance* instance, std::shared
connect(selection_model, &QItemSelectionModel::currentChanged, this, &ExternalResourcesPage::current); connect(selection_model, &QItemSelectionModel::currentChanged, this, &ExternalResourcesPage::current);
auto updateExtra = [this]() { auto updateExtra = [this]() {
if (updateExtraInfo) if (updateExtraInfo)
updateExtraInfo(extraHeaderInfoString()); updateExtraInfo(id(), extraHeaderInfoString());
}; };
connect(selection_model, &QItemSelectionModel::selectionChanged, this, updateExtra); connect(selection_model, &QItemSelectionModel::selectionChanged, this, updateExtra);
connect(model.get(), &ResourceFolderModel::updateFinished, this, updateExtra); connect(model.get(), &ResourceFolderModel::updateFinished, this, updateExtra);

View File

@ -85,12 +85,12 @@ void InstanceSettingsPage::globalSettingsButtonClicked(bool)
case 0: case 0:
APPLICATION->ShowGlobalSettings(this, "java-settings"); APPLICATION->ShowGlobalSettings(this, "java-settings");
return; return;
case 1:
APPLICATION->ShowGlobalSettings(this, "minecraft-settings");
return;
case 2: case 2:
APPLICATION->ShowGlobalSettings(this, "custom-commands"); APPLICATION->ShowGlobalSettings(this, "custom-commands");
return; return;
default:
APPLICATION->ShowGlobalSettings(this, "minecraft-settings");
return;
} }
} }

View File

@ -205,7 +205,7 @@ ModrinthManagedPackPage::ModrinthManagedPackPage(BaseInstance* inst, InstanceWin
{ {
Q_ASSERT(inst->isManagedPack()); Q_ASSERT(inst->isManagedPack());
connect(ui->versionsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(suggestVersion())); connect(ui->versionsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(suggestVersion()));
connect(ui->updateButton, &QPushButton::pressed, this, &ModrinthManagedPackPage::update); connect(ui->updateButton, &QPushButton::clicked, this, &ModrinthManagedPackPage::update);
} }
// MODRINTH // MODRINTH
@ -332,7 +332,7 @@ FlameManagedPackPage::FlameManagedPackPage(BaseInstance* inst, InstanceWindow* i
{ {
Q_ASSERT(inst->isManagedPack()); Q_ASSERT(inst->isManagedPack());
connect(ui->versionsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(suggestVersion())); connect(ui->versionsComboBox, SIGNAL(currentIndexChanged(int)), this, SLOT(suggestVersion()));
connect(ui->updateButton, &QPushButton::pressed, this, &FlameManagedPackPage::update); connect(ui->updateButton, &QPushButton::clicked, this, &FlameManagedPackPage::update);
} }
void FlameManagedPackPage::parseManagedPack() void FlameManagedPackPage::parseManagedPack()

View File

@ -36,6 +36,7 @@
*/ */
#include "ScreenshotsPage.h" #include "ScreenshotsPage.h"
#include "BuildConfig.h"
#include "ui_ScreenshotsPage.h" #include "ui_ScreenshotsPage.h"
#include <QModelIndex> #include <QModelIndex>
@ -380,16 +381,18 @@ void ScreenshotsPage::on_actionUpload_triggered()
if (selection.isEmpty()) if (selection.isEmpty())
return; return;
QString text; QString text;
QUrl baseUrl(BuildConfig.IMGUR_BASE_URL);
if (selection.size() > 1) if (selection.size() > 1)
text = tr("You are about to upload %1 screenshots.\n\n" text = tr("You are about to upload %1 screenshots to %2.\n"
"You should double-check for personal information.\n\n"
"Are you sure?") "Are you sure?")
.arg(selection.size()); .arg(QString::number(selection.size()), baseUrl.host());
else else
text = text = tr("You are about to upload the selected screenshot to %1.\n"
tr("You are about to upload the selected screenshot.\n\n" "You should double-check for personal information.\n\n"
"Are you sure?"); "Are you sure?")
.arg(baseUrl.host());
auto response = CustomMessageBox::selectable(this, "Confirm Upload", text, QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No, auto response = CustomMessageBox::selectable(this, "Confirm Upload", text, QMessageBox::Warning, QMessageBox::Yes | QMessageBox::No,
QMessageBox::No) QMessageBox::No)

View File

@ -287,7 +287,6 @@ void VersionPage::updateButtons(int row)
ui->actionAdd_Empty->setEnabled(controlsEnabled); ui->actionAdd_Empty->setEnabled(controlsEnabled);
ui->actionImport_Components->setEnabled(controlsEnabled); ui->actionImport_Components->setEnabled(controlsEnabled);
ui->actionReload->setEnabled(controlsEnabled); ui->actionReload->setEnabled(controlsEnabled);
ui->actionInstall_mods->setEnabled(controlsEnabled);
ui->actionReplace_Minecraft_jar->setEnabled(controlsEnabled); ui->actionReplace_Minecraft_jar->setEnabled(controlsEnabled);
ui->actionAdd_to_Minecraft_jar->setEnabled(controlsEnabled); ui->actionAdd_to_Minecraft_jar->setEnabled(controlsEnabled);
ui->actionAdd_Agents->setEnabled(controlsEnabled); ui->actionAdd_Agents->setEnabled(controlsEnabled);

View File

@ -102,7 +102,6 @@
<addaction name="actionInstall_Fabric"/> <addaction name="actionInstall_Fabric"/>
<addaction name="actionInstall_Quilt"/> <addaction name="actionInstall_Quilt"/>
<addaction name="actionInstall_LiteLoader"/> <addaction name="actionInstall_LiteLoader"/>
<addaction name="actionInstall_mods"/>
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="actionAdd_to_Minecraft_jar"/> <addaction name="actionAdd_to_Minecraft_jar"/>
<addaction name="actionReplace_Minecraft_jar"/> <addaction name="actionReplace_Minecraft_jar"/>
@ -112,7 +111,6 @@
<addaction name="separator"/> <addaction name="separator"/>
<addaction name="actionMinecraftFolder"/> <addaction name="actionMinecraftFolder"/>
<addaction name="actionLibrariesFolder"/> <addaction name="actionLibrariesFolder"/>
<addaction name="separator"/>
<addaction name="actionReload"/> <addaction name="actionReload"/>
<addaction name="actionDownload_All"/> <addaction name="actionDownload_All"/>
</widget> </widget>
@ -204,14 +202,6 @@
<string>Install the LiteLoader package.</string> <string>Install the LiteLoader package.</string>
</property> </property>
</action> </action>
<action name="actionInstall_mods">
<property name="text">
<string>Install mods</string>
</property>
<property name="toolTip">
<string>Install normal mods.</string>
</property>
</action>
<action name="actionAdd_to_Minecraft_jar"> <action name="actionAdd_to_Minecraft_jar">
<property name="text"> <property name="text">
<string>Add to Minecraft.jar</string> <string>Add to Minecraft.jar</string>

View File

@ -33,8 +33,8 @@
* limitations under the License. * limitations under the License.
*/ */
#include "VanillaPage.h" #include "CustomPage.h"
#include "ui_VanillaPage.h" #include "ui_CustomPage.h"
#include <QTabBar> #include <QTabBar>
@ -46,32 +46,32 @@
#include "minecraft/VanillaInstanceCreationTask.h" #include "minecraft/VanillaInstanceCreationTask.h"
#include "ui/dialogs/NewInstanceDialog.h" #include "ui/dialogs/NewInstanceDialog.h"
VanillaPage::VanillaPage(NewInstanceDialog *dialog, QWidget *parent) CustomPage::CustomPage(NewInstanceDialog *dialog, QWidget *parent)
: QWidget(parent), dialog(dialog), ui(new Ui::VanillaPage) : QWidget(parent), dialog(dialog), ui(new Ui::CustomPage)
{ {
ui->setupUi(this); ui->setupUi(this);
ui->tabWidget->tabBar()->hide(); ui->tabWidget->tabBar()->hide();
connect(ui->versionList, &VersionSelectWidget::selectedVersionChanged, this, &VanillaPage::setSelectedVersion); connect(ui->versionList, &VersionSelectWidget::selectedVersionChanged, this, &CustomPage::setSelectedVersion);
filterChanged(); filterChanged();
connect(ui->alphaFilter, &QCheckBox::stateChanged, this, &VanillaPage::filterChanged); connect(ui->alphaFilter, &QCheckBox::stateChanged, this, &CustomPage::filterChanged);
connect(ui->betaFilter, &QCheckBox::stateChanged, this, &VanillaPage::filterChanged); connect(ui->betaFilter, &QCheckBox::stateChanged, this, &CustomPage::filterChanged);
connect(ui->snapshotFilter, &QCheckBox::stateChanged, this, &VanillaPage::filterChanged); connect(ui->snapshotFilter, &QCheckBox::stateChanged, this, &CustomPage::filterChanged);
connect(ui->oldSnapshotFilter, &QCheckBox::stateChanged, this, &VanillaPage::filterChanged); connect(ui->oldSnapshotFilter, &QCheckBox::stateChanged, this, &CustomPage::filterChanged);
connect(ui->releaseFilter, &QCheckBox::stateChanged, this, &VanillaPage::filterChanged); connect(ui->releaseFilter, &QCheckBox::stateChanged, this, &CustomPage::filterChanged);
connect(ui->experimentsFilter, &QCheckBox::stateChanged, this, &VanillaPage::filterChanged); connect(ui->experimentsFilter, &QCheckBox::stateChanged, this, &CustomPage::filterChanged);
connect(ui->refreshBtn, &QPushButton::clicked, this, &VanillaPage::refresh); connect(ui->refreshBtn, &QPushButton::clicked, this, &CustomPage::refresh);
connect(ui->loaderVersionList, &VersionSelectWidget::selectedVersionChanged, this, &VanillaPage::setSelectedLoaderVersion); connect(ui->loaderVersionList, &VersionSelectWidget::selectedVersionChanged, this, &CustomPage::setSelectedLoaderVersion);
connect(ui->noneFilter, &QRadioButton::toggled, this, &VanillaPage::loaderFilterChanged); connect(ui->noneFilter, &QRadioButton::toggled, this, &CustomPage::loaderFilterChanged);
connect(ui->forgeFilter, &QRadioButton::toggled, this, &VanillaPage::loaderFilterChanged); connect(ui->forgeFilter, &QRadioButton::toggled, this, &CustomPage::loaderFilterChanged);
connect(ui->fabricFilter, &QRadioButton::toggled, this, &VanillaPage::loaderFilterChanged); connect(ui->fabricFilter, &QRadioButton::toggled, this, &CustomPage::loaderFilterChanged);
connect(ui->quiltFilter, &QRadioButton::toggled, this, &VanillaPage::loaderFilterChanged); connect(ui->quiltFilter, &QRadioButton::toggled, this, &CustomPage::loaderFilterChanged);
connect(ui->liteLoaderFilter, &QRadioButton::toggled, this, &VanillaPage::loaderFilterChanged); connect(ui->liteLoaderFilter, &QRadioButton::toggled, this, &CustomPage::loaderFilterChanged);
connect(ui->loaderRefreshBtn, &QPushButton::clicked, this, &VanillaPage::loaderRefresh); connect(ui->loaderRefreshBtn, &QPushButton::clicked, this, &CustomPage::loaderRefresh);
} }
void VanillaPage::openedImpl() void CustomPage::openedImpl()
{ {
if(!initialized) if(!initialized)
{ {
@ -85,19 +85,19 @@ void VanillaPage::openedImpl()
} }
} }
void VanillaPage::refresh() void CustomPage::refresh()
{ {
ui->versionList->loadList(); ui->versionList->loadList();
} }
void VanillaPage::loaderRefresh() void CustomPage::loaderRefresh()
{ {
if(ui->noneFilter->isChecked()) if(ui->noneFilter->isChecked())
return; return;
ui->loaderVersionList->loadList(); ui->loaderVersionList->loadList();
} }
void VanillaPage::filterChanged() void CustomPage::filterChanged()
{ {
QStringList out; QStringList out;
if(ui->alphaFilter->isChecked()) if(ui->alphaFilter->isChecked())
@ -116,7 +116,7 @@ void VanillaPage::filterChanged()
ui->versionList->setFilter(BaseVersionList::TypeRole, new RegexpFilter(regexp, false)); ui->versionList->setFilter(BaseVersionList::TypeRole, new RegexpFilter(regexp, false));
} }
void VanillaPage::loaderFilterChanged() void CustomPage::loaderFilterChanged()
{ {
QString minecraftVersion; QString minecraftVersion;
if (m_selectedVersion) if (m_selectedVersion)
@ -172,37 +172,37 @@ void VanillaPage::loaderFilterChanged()
ui->loaderVersionList->setEmptyString(tr("No versions are currently available for Minecraft %1").arg(minecraftVersion)); ui->loaderVersionList->setEmptyString(tr("No versions are currently available for Minecraft %1").arg(minecraftVersion));
} }
VanillaPage::~VanillaPage() CustomPage::~CustomPage()
{ {
delete ui; delete ui;
} }
bool VanillaPage::shouldDisplay() const bool CustomPage::shouldDisplay() const
{ {
return true; return true;
} }
void VanillaPage::retranslate() void CustomPage::retranslate()
{ {
ui->retranslateUi(this); ui->retranslateUi(this);
} }
BaseVersion::Ptr VanillaPage::selectedVersion() const BaseVersion::Ptr CustomPage::selectedVersion() const
{ {
return m_selectedVersion; return m_selectedVersion;
} }
BaseVersion::Ptr VanillaPage::selectedLoaderVersion() const BaseVersion::Ptr CustomPage::selectedLoaderVersion() const
{ {
return m_selectedLoaderVersion; return m_selectedLoaderVersion;
} }
QString VanillaPage::selectedLoader() const QString CustomPage::selectedLoader() const
{ {
return m_selectedLoader; return m_selectedLoader;
} }
void VanillaPage::suggestCurrent() void CustomPage::suggestCurrent()
{ {
if (!isOpened) if (!isOpened)
{ {
@ -227,14 +227,14 @@ void VanillaPage::suggestCurrent()
dialog->setSuggestedIcon("default"); dialog->setSuggestedIcon("default");
} }
void VanillaPage::setSelectedVersion(BaseVersion::Ptr version) void CustomPage::setSelectedVersion(BaseVersion::Ptr version)
{ {
m_selectedVersion = version; m_selectedVersion = version;
suggestCurrent(); suggestCurrent();
loaderFilterChanged(); loaderFilterChanged();
} }
void VanillaPage::setSelectedLoaderVersion(BaseVersion::Ptr version) void CustomPage::setSelectedLoaderVersion(BaseVersion::Ptr version)
{ {
m_selectedLoaderVersion = version; m_selectedLoaderVersion = version;
suggestCurrent(); suggestCurrent();

View File

@ -43,21 +43,21 @@
namespace Ui namespace Ui
{ {
class VanillaPage; class CustomPage;
} }
class NewInstanceDialog; class NewInstanceDialog;
class VanillaPage : public QWidget, public BasePage class CustomPage : public QWidget, public BasePage
{ {
Q_OBJECT Q_OBJECT
public: public:
explicit VanillaPage(NewInstanceDialog *dialog, QWidget *parent = 0); explicit CustomPage(NewInstanceDialog *dialog, QWidget *parent = 0);
virtual ~VanillaPage(); virtual ~CustomPage();
virtual QString displayName() const override virtual QString displayName() const override
{ {
return tr("Vanilla"); return tr("Custom");
} }
virtual QIcon icon() const override virtual QIcon icon() const override
{ {
@ -96,7 +96,7 @@ private:
private: private:
bool initialized = false; bool initialized = false;
NewInstanceDialog *dialog = nullptr; NewInstanceDialog *dialog = nullptr;
Ui::VanillaPage *ui = nullptr; Ui::CustomPage *ui = nullptr;
bool m_versionSetByUser = false; bool m_versionSetByUser = false;
BaseVersion::Ptr m_selectedVersion; BaseVersion::Ptr m_selectedVersion;
BaseVersion::Ptr m_selectedLoaderVersion; BaseVersion::Ptr m_selectedLoaderVersion;

View File

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0"> <ui version="4.0">
<class>VanillaPage</class> <class>CustomPage</class>
<widget class="QWidget" name="VanillaPage"> <widget class="QWidget" name="CustomPage">
<property name="geometry"> <property name="geometry">
<rect> <rect>
<x>0</x> <x>0</x>

View File

@ -116,8 +116,8 @@ Page::Page(NewInstanceDialog* dialog, QWidget *parent)
connect(ui->thirdPartyPackList->selectionModel(), &QItemSelectionModel::currentChanged, this, &Page::onThirdPartyPackSelectionChanged); connect(ui->thirdPartyPackList->selectionModel(), &QItemSelectionModel::currentChanged, this, &Page::onThirdPartyPackSelectionChanged);
connect(ui->privatePackList->selectionModel(), &QItemSelectionModel::currentChanged, this, &Page::onPrivatePackSelectionChanged); connect(ui->privatePackList->selectionModel(), &QItemSelectionModel::currentChanged, this, &Page::onPrivatePackSelectionChanged);
connect(ui->addPackBtn, &QPushButton::pressed, this, &Page::onAddPackClicked); connect(ui->addPackBtn, &QPushButton::clicked, this, &Page::onAddPackClicked);
connect(ui->removePackBtn, &QPushButton::pressed, this, &Page::onRemovePackClicked); connect(ui->removePackBtn, &QPushButton::clicked, this, &Page::onRemovePackClicked);
connect(ui->tabWidget, &QTabWidget::currentChanged, this, &Page::onTabChanged); connect(ui->tabWidget, &QTabWidget::currentChanged, this, &Page::onTabChanged);

View File

@ -59,7 +59,7 @@ void SetupWizard::pageChanged(int id)
{ {
setButtonLayout({QWizard::CustomButton1, QWizard::Stretch, QWizard::BackButton, QWizard::NextButton, QWizard::FinishButton}); setButtonLayout({QWizard::CustomButton1, QWizard::Stretch, QWizard::BackButton, QWizard::NextButton, QWizard::FinishButton});
auto customButton = button(QWizard::CustomButton1); auto customButton = button(QWizard::CustomButton1);
connect(customButton, &QAbstractButton::pressed, [&](){ connect(customButton, &QAbstractButton::clicked, [&](){
auto basePagePtr = getCurrentBasePage(); auto basePagePtr = getCurrentBasePage();
if(basePagePtr) if(basePagePtr)
{ {

View File

@ -14,9 +14,6 @@
*/ */
#include "ModListView.h" #include "ModListView.h"
#include "minecraft/mod/ModFolderModel.h"
#include <QHeaderView> #include <QHeaderView>
#include <QMouseEvent> #include <QMouseEvent>
#include <QPainter> #include <QPainter>
@ -65,19 +62,6 @@ void ModListView::setModel ( QAbstractItemModel* model )
for(int i = 1; i < head->count(); i++) for(int i = 1; i < head->count(); i++)
head->setSectionResizeMode(i, QHeaderView::ResizeToContents); head->setSectionResizeMode(i, QHeaderView::ResizeToContents);
} }
auto real_model = model;
if (auto proxy_model = dynamic_cast<QSortFilterProxyModel*>(model); proxy_model)
real_model = proxy_model->sourceModel();
if (auto mod_model = dynamic_cast<ModFolderModel*>(real_model); mod_model) {
connect(mod_model, &ModFolderModel::updateFinished, this, [this, mod_model]{
auto mods = mod_model->allMods();
// Hide the 'Provider' column if no mod has a defined provider!
setColumnHidden(ModFolderModel::Columns::ProviderColumn,
std::none_of(mods.constBegin(), mods.constEnd(), [](auto const mod){ return mod->provider().has_value(); }));
});
}
} }
void ModListView::setResizeModes(const QList<QHeaderView::ResizeMode> &modes) void ModListView::setResizeModes(const QList<QHeaderView::ResizeMode> &modes)

View File

@ -93,8 +93,8 @@ PageContainer::PageContainer(BasePageProvider *pageProvider, QString defaultId,
page->listIndex = counter; page->listIndex = counter;
page->setParentContainer(this); page->setParentContainer(this);
counter++; counter++;
page->updateExtraInfo = [this](QString info) { page->updateExtraInfo = [this](QString id, QString info) {
if (m_currentPage) if (m_currentPage && id == m_currentPage->id())
m_header->setText(m_currentPage->displayName() + info); m_header->setText(m_currentPage->displayName() + info);
}; };
} }

View File

@ -67,7 +67,4 @@ else
fi fi
# replace icon in themes # replace icon in themes
for dir in ../launcher/resources/*/scalable cp -v org.prismlauncher.PrismLauncher.svg "../launcher/resources/multimc/scalable/launcher.svg"
do
cp -v org.prismlauncher.PrismLauncher.svg "$dir/launcher.svg"
done

View File

@ -9,9 +9,6 @@ ecm_add_test(GZip_test.cpp LINK_LIBRARIES Launcher_logic Qt${QT_VERSION_MAJOR}::
ecm_add_test(GradleSpecifier_test.cpp LINK_LIBRARIES Launcher_logic Qt${QT_VERSION_MAJOR}::Test ecm_add_test(GradleSpecifier_test.cpp LINK_LIBRARIES Launcher_logic Qt${QT_VERSION_MAJOR}::Test
TEST_NAME GradleSpecifier) TEST_NAME GradleSpecifier)
ecm_add_test(PackageManifest_test.cpp LINK_LIBRARIES Launcher_logic Qt${QT_VERSION_MAJOR}::Test
TEST_NAME PackageManifest)
ecm_add_test(MojangVersionFormat_test.cpp LINK_LIBRARIES Launcher_logic Qt${QT_VERSION_MAJOR}::Test ecm_add_test(MojangVersionFormat_test.cpp LINK_LIBRARIES Launcher_logic Qt${QT_VERSION_MAJOR}::Test
TEST_NAME MojangVersionFormat) TEST_NAME MojangVersionFormat)

View File

@ -1,343 +0,0 @@
#include <QTest>
#include <QDebug>
#include <mojang/PackageManifest.h>
using namespace mojang_files;
QDebug operator<<(QDebug debug, const Path &path)
{
debug << path.toString();
return debug;
}
class PackageManifestTest : public QObject
{
Q_OBJECT
private slots:
void test_parse();
void test_parse_file();
void test_inspect();
#ifndef Q_OS_WIN32
void test_inspect_symlinks();
#endif
void mkdir_deep();
void rmdir_deep();
void identical_file();
void changed_file();
void added_file();
void removed_file();
};
namespace {
QByteArray basic_manifest = R"END(
{
"files": {
"a/b.txt": {
"type": "file",
"downloads": {
"raw": {
"url": "http://dethware.org/b.txt",
"sha1": "da39a3ee5e6b4b0d3255bfef95601890afd80709",
"size": 0
}
},
"executable": true
},
"a/b/c": {
"type": "directory"
},
"a/b/c.txt": {
"type": "link",
"target": "../b.txt"
}
}
}
)END";
}
void PackageManifestTest::test_parse()
{
auto manifest = Package::fromManifestContents(basic_manifest);
QVERIFY(manifest.valid == true);
QVERIFY(manifest.files.size() == 1);
QVERIFY(manifest.files.count(Path("a/b.txt")));
auto &file = manifest.files[Path("a/b.txt")];
QVERIFY(file.executable == true);
QVERIFY(file.hash == "da39a3ee5e6b4b0d3255bfef95601890afd80709");
QVERIFY(file.size == 0);
QVERIFY(manifest.folders.size() == 4);
QVERIFY(manifest.folders.count(Path(".")));
QVERIFY(manifest.folders.count(Path("a")));
QVERIFY(manifest.folders.count(Path("a/b")));
QVERIFY(manifest.folders.count(Path("a/b/c")));
QVERIFY(manifest.symlinks.size() == 1);
auto symlinkPath = Path("a/b/c.txt");
QVERIFY(manifest.symlinks.count(symlinkPath));
auto &symlink = manifest.symlinks[symlinkPath];
QVERIFY(symlink == Path("../b.txt"));
QVERIFY(manifest.sources.size() == 1);
}
void PackageManifestTest::test_parse_file() {
auto path = QFINDTESTDATA("testdata/PackageManifest/1.8.0_202-x64.json");
auto manifest = Package::fromManifestFile(path);
QVERIFY(manifest.valid == true);
}
void PackageManifestTest::test_inspect() {
auto path = QFINDTESTDATA("testdata/PackageManifest/inspect_win/");
auto manifest = Package::fromInspectedFolder(path);
QVERIFY(manifest.valid == true);
QVERIFY(manifest.files.size() == 2);
QVERIFY(manifest.files.count(Path("a/b.txt")));
auto &file1 = manifest.files[Path("a/b.txt")];
QVERIFY(file1.executable == false);
QVERIFY(file1.hash == "da39a3ee5e6b4b0d3255bfef95601890afd80709");
QVERIFY(file1.size == 0);
QVERIFY(manifest.files.count(Path("a/b/b.txt")));
auto &file2 = manifest.files[Path("a/b/b.txt")];
QVERIFY(file2.executable == false);
QVERIFY(file2.hash == "da39a3ee5e6b4b0d3255bfef95601890afd80709");
QVERIFY(file2.size == 0);
QVERIFY(manifest.folders.size() == 3);
QVERIFY(manifest.folders.count(Path(".")));
QVERIFY(manifest.folders.count(Path("a")));
QVERIFY(manifest.folders.count(Path("a/b")));
QVERIFY(manifest.symlinks.size() == 0);
}
#ifndef Q_OS_WIN32
void PackageManifestTest::test_inspect_symlinks() {
auto path = QFINDTESTDATA("testdata/PackageManifest/inspect/");
auto manifest = Package::fromInspectedFolder(path);
QVERIFY(manifest.valid == true);
QVERIFY(manifest.files.size() == 1);
QVERIFY(manifest.files.count(Path("a/b.txt")));
auto &file = manifest.files[Path("a/b.txt")];
QVERIFY(file.executable == true);
QVERIFY(file.hash == "da39a3ee5e6b4b0d3255bfef95601890afd80709");
QVERIFY(file.size == 0);
QVERIFY(manifest.folders.size() == 3);
QVERIFY(manifest.folders.count(Path(".")));
QVERIFY(manifest.folders.count(Path("a")));
QVERIFY(manifest.folders.count(Path("a/b")));
QVERIFY(manifest.symlinks.size() == 1);
QVERIFY(manifest.symlinks.count(Path("a/b/b.txt")));
qDebug() << manifest.symlinks[Path("a/b/b.txt")];
QVERIFY(manifest.symlinks[Path("a/b/b.txt")] == Path("../b.txt"));
}
#endif
void PackageManifestTest::mkdir_deep() {
Package from;
auto to = Package::fromManifestContents(R"END(
{
"files": {
"a/b/c/d/e": {
"type": "directory"
}
}
}
)END");
auto operations = UpdateOperations::resolve(from, to);
QVERIFY(operations.deletes.size() == 0);
QVERIFY(operations.rmdirs.size() == 0);
QVERIFY(operations.mkdirs.size() == 6);
QVERIFY(operations.mkdirs[0] == Path("."));
QVERIFY(operations.mkdirs[1] == Path("a"));
QVERIFY(operations.mkdirs[2] == Path("a/b"));
QVERIFY(operations.mkdirs[3] == Path("a/b/c"));
QVERIFY(operations.mkdirs[4] == Path("a/b/c/d"));
QVERIFY(operations.mkdirs[5] == Path("a/b/c/d/e"));
QVERIFY(operations.downloads.size() == 0);
QVERIFY(operations.mklinks.size() == 0);
QVERIFY(operations.executable_fixes.size() == 0);
}
void PackageManifestTest::rmdir_deep() {
Package to;
auto from = Package::fromManifestContents(R"END(
{
"files": {
"a/b/c/d/e": {
"type": "directory"
}
}
}
)END");
auto operations = UpdateOperations::resolve(from, to);
QVERIFY(operations.deletes.size() == 0);
QVERIFY(operations.rmdirs.size() == 6);
QVERIFY(operations.rmdirs[0] == Path("a/b/c/d/e"));
QVERIFY(operations.rmdirs[1] == Path("a/b/c/d"));
QVERIFY(operations.rmdirs[2] == Path("a/b/c"));
QVERIFY(operations.rmdirs[3] == Path("a/b"));
QVERIFY(operations.rmdirs[4] == Path("a"));
QVERIFY(operations.rmdirs[5] == Path("."));
QVERIFY(operations.mkdirs.size() == 0);
QVERIFY(operations.downloads.size() == 0);
QVERIFY(operations.mklinks.size() == 0);
QVERIFY(operations.executable_fixes.size() == 0);
}
void PackageManifestTest::identical_file() {
QByteArray manifest = R"END(
{
"files": {
"a/b/c/d/empty.txt": {
"type": "file",
"downloads": {
"raw": {
"url": "http://dethware.org/empty.txt",
"sha1": "da39a3ee5e6b4b0d3255bfef95601890afd80709",
"size": 0
}
},
"executable": false
}
}
}
)END";
auto from = Package::fromManifestContents(manifest);
auto to = Package::fromManifestContents(manifest);
auto operations = UpdateOperations::resolve(from, to);
QVERIFY(operations.deletes.size() == 0);
QVERIFY(operations.rmdirs.size() == 0);
QVERIFY(operations.mkdirs.size() == 0);
QVERIFY(operations.downloads.size() == 0);
QVERIFY(operations.mklinks.size() == 0);
QVERIFY(operations.executable_fixes.size() == 0);
}
void PackageManifestTest::changed_file() {
auto from = Package::fromManifestContents(R"END(
{
"files": {
"a/b/c/d/file": {
"type": "file",
"downloads": {
"raw": {
"url": "http://dethware.org/empty.txt",
"sha1": "da39a3ee5e6b4b0d3255bfef95601890afd80709",
"size": 0
}
},
"executable": false
}
}
}
)END");
auto to = Package::fromManifestContents(R"END(
{
"files": {
"a/b/c/d/file": {
"type": "file",
"downloads": {
"raw": {
"url": "http://dethware.org/space.txt",
"sha1": "dd122581c8cd44d0227f9c305581ffcb4b6f1b46",
"size": 1
}
},
"executable": false
}
}
}
)END");
auto operations = UpdateOperations::resolve(from, to);
QVERIFY(operations.deletes.size() == 1);
QCOMPARE(operations.deletes[0], Path("a/b/c/d/file"));
QVERIFY(operations.rmdirs.size() == 0);
QVERIFY(operations.mkdirs.size() == 0);
QVERIFY(operations.downloads.size() == 1);
QVERIFY(operations.mklinks.size() == 0);
QVERIFY(operations.executable_fixes.size() == 0);
}
void PackageManifestTest::added_file() {
auto from = Package::fromManifestContents(R"END(
{
"files": {
"a/b/c/d": {
"type": "directory"
}
}
}
)END");
auto to = Package::fromManifestContents(R"END(
{
"files": {
"a/b/c/d/file": {
"type": "file",
"downloads": {
"raw": {
"url": "http://dethware.org/space.txt",
"sha1": "dd122581c8cd44d0227f9c305581ffcb4b6f1b46",
"size": 1
}
},
"executable": false
}
}
}
)END");
auto operations = UpdateOperations::resolve(from, to);
QVERIFY(operations.deletes.size() == 0);
QVERIFY(operations.rmdirs.size() == 0);
QVERIFY(operations.mkdirs.size() == 0);
QVERIFY(operations.downloads.size() == 1);
QVERIFY(operations.mklinks.size() == 0);
QVERIFY(operations.executable_fixes.size() == 0);
}
void PackageManifestTest::removed_file() {
auto from = Package::fromManifestContents(R"END(
{
"files": {
"a/b/c/d/file": {
"type": "file",
"downloads": {
"raw": {
"url": "http://dethware.org/space.txt",
"sha1": "dd122581c8cd44d0227f9c305581ffcb4b6f1b46",
"size": 1
}
},
"executable": false
}
}
}
)END");
auto to = Package::fromManifestContents(R"END(
{
"files": {
"a/b/c/d": {
"type": "directory"
}
}
}
)END");
auto operations = UpdateOperations::resolve(from, to);
QVERIFY(operations.deletes.size() == 1);
QCOMPARE(operations.deletes[0], Path("a/b/c/d/file"));
QVERIFY(operations.rmdirs.size() == 0);
QVERIFY(operations.mkdirs.size() == 0);
QVERIFY(operations.downloads.size() == 0);
QVERIFY(operations.mklinks.size() == 0);
QVERIFY(operations.executable_fixes.size() == 0);
}
QTEST_GUILESS_MAIN(PackageManifestTest)
#include "PackageManifest_test.moc"