diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 20fe66dd..c0e5b50a 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -487,6 +487,7 @@ jobs: runs-on: ubuntu-20.04 steps: - name: Checkout + if: inputs.build_type == 'Debug' uses: actions/checkout@v3 with: submodules: 'true' @@ -524,3 +525,4 @@ jobs: with: bundle: "Prism Launcher.flatpak" manifest-path: flatpak/org.prismlauncher.PrismLauncher.yml + cache-key: flatpak-${{ github.sha }}-x86_64 diff --git a/COPYING.md b/COPYING.md index 3e35c579..dde3c727 100644 --- a/COPYING.md +++ b/COPYING.md @@ -398,3 +398,20 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +## Breeze icons + + Copyright (C) 2014 Uri Herrera and others + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 3 of the License, or (at your option) any later version. + + This library 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 + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library. If not, see . diff --git a/launcher/Application.cpp b/launcher/Application.cpp index c5594b21..4ba9eb9b 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -1,4 +1,7 @@ -// SPDX-License-Identifier: GPL-3.0-only +// SPDX-FileCopyrightText: 2022 Sefa Eyeoglu +// +// SPDX-License-Identifier: GPL-3.0-only AND Apache-2.0 + /* * Prism Launcher - Minecraft Launcher * Copyright (C) 2022 Sefa Eyeoglu @@ -38,10 +41,14 @@ #include "Application.h" #include "BuildConfig.h" +#include "DataMigrationTask.h" #include "net/PasteUpload.h" +#include "pathmatcher/MultiMatcher.h" +#include "pathmatcher/SimplePrefixMatcher.h" #include "ui/MainWindow.h" #include "ui/InstanceWindow.h" +#include "ui/dialogs/ProgressDialog.h" #include "ui/instanceview/AccessibleInstanceView.h" #include "ui/pages/BasePageProvider.h" @@ -301,22 +308,6 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv) dataPath = foo.absolutePath(); adjustedBy = "Persistent data path"; - QDir polymcData(FS::PathCombine(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation), "PolyMC")); - if (polymcData.exists()) { - dataPath = polymcData.absolutePath(); - adjustedBy = "PolyMC data path"; - } - -#ifdef Q_OS_LINUX - // TODO: this should be removed in a future version - // TODO: provide a migration path similar to macOS migration - QDir bar(FS::PathCombine(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation), "polymc")); - if (bar.exists()) { - dataPath = bar.absolutePath(); - adjustedBy = "Legacy data path"; - } -#endif - #ifndef Q_OS_MACOS if (QFile::exists(FS::PathCombine(m_rootPath, "portable.txt"))) { dataPath = m_rootPath; @@ -439,6 +430,15 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv) qDebug() << "<> Log initialized."; } + { + bool migrated = false; + + if (!migrated) + migrated = handleDataMigration(dataPath, FS::PathCombine(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation), "../../PolyMC"), "PolyMC", "polymc.cfg"); + if (!migrated) + migrated = handleDataMigration(dataPath, FS::PathCombine(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation), "../../multimc"), "MultiMC", "multimc.cfg"); + } + { qDebug() << BuildConfig.LAUNCHER_DISPLAYNAME << ", (c) 2013-2021 " << BuildConfig.LAUNCHER_COPYRIGHT; @@ -1605,3 +1605,88 @@ int Application::suitableMaxMem() return maxMemoryAlloc; } + +bool Application::handleDataMigration(const QString& currentData, + const QString& oldData, + const QString& name, + const QString& configFile) const +{ + QString nomigratePath = FS::PathCombine(currentData, name + "_nomigrate.txt"); + QStringList configPaths = { FS::PathCombine(oldData, configFile), FS::PathCombine(oldData, BuildConfig.LAUNCHER_CONFIGFILE) }; + + QLocale locale; + + // Is there a valid config at the old location? + bool configExists = false; + for (QString configPath : configPaths) { + configExists |= QFileInfo::exists(configPath); + } + + if (!configExists || QFileInfo::exists(nomigratePath)) { + qDebug() << "<> No migration needed from" << name; + return false; + } + + QString message; + bool currentExists = QFileInfo::exists(FS::PathCombine(currentData, BuildConfig.LAUNCHER_CONFIGFILE)); + + if (currentExists) { + message = tr("Old data from %1 was found, but you already have existing data for %2. Sadly you will need to migrate yourself. Do " + "you want to be reminded of the pending data migration next time you start %2?") + .arg(name, BuildConfig.LAUNCHER_DISPLAYNAME); + } else { + message = tr("It looks like you used %1 before. Do you want to migrate your data to the new location of %2?") + .arg(name, BuildConfig.LAUNCHER_DISPLAYNAME); + + QFileInfo logInfo(FS::PathCombine(oldData, name + "-0.log")); + if (logInfo.exists()) { + QString lastModified = logInfo.lastModified().toString(locale.dateFormat()); + message = tr("It looks like you used %1 on %2 before. Do you want to migrate your data to the new location of %3?") + .arg(name, lastModified, BuildConfig.LAUNCHER_DISPLAYNAME); + } + } + + QMessageBox::StandardButton askMoveDialogue = + QMessageBox::question(nullptr, BuildConfig.LAUNCHER_DISPLAYNAME, message, QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); + + auto setDoNotMigrate = [&nomigratePath] { + QFile file(nomigratePath); + file.open(QIODevice::WriteOnly); + }; + + // create no-migrate file if user doesn't want to migrate + if (askMoveDialogue != QMessageBox::Yes) { + qDebug() << "<> Migration declined for" << name; + setDoNotMigrate(); + return currentExists; // cancel further migrations, if we already have a data directory + } + + if (!currentExists) { + // Migrate! + auto matcher = std::make_shared(); + matcher->add(std::make_shared(configFile)); + matcher->add(std::make_shared( + BuildConfig.LAUNCHER_CONFIGFILE)); // it's possible that we already used that directory before + matcher->add(std::make_shared("accounts.json")); + matcher->add(std::make_shared("accounts/")); + matcher->add(std::make_shared("assets/")); + matcher->add(std::make_shared("icons/")); + matcher->add(std::make_shared("instances/")); + matcher->add(std::make_shared("libraries/")); + matcher->add(std::make_shared("mods/")); + matcher->add(std::make_shared("themes/")); + + ProgressDialog diag; + DataMigrationTask task(nullptr, oldData, currentData, matcher); + if (diag.execWithTask(&task)) { + qDebug() << "<> Migration succeeded"; + setDoNotMigrate(); + } else { + QString reason = task.failReason(); + QMessageBox::critical(nullptr, BuildConfig.LAUNCHER_DISPLAYNAME, tr("Migration failed! Reason: %1").arg(reason)); + } + } else { + qWarning() << "<> Migration was skipped, due to existing data"; + } + return true; +} diff --git a/launcher/Application.h b/launcher/Application.h index 4c2f62d4..7884227a 100644 --- a/launcher/Application.h +++ b/launcher/Application.h @@ -231,6 +231,7 @@ private slots: void setupWizardFinished(int status); private: + bool handleDataMigration(const QString & currentData, const QString & oldData, const QString & name, const QString & configFile) const; bool createSetupWizard(); void performMainStartupAction(); diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index 58d5d964..3eb765dc 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -97,6 +97,7 @@ set(PATHMATCHER_SOURCES pathmatcher/IPathMatcher.h pathmatcher/MultiMatcher.h pathmatcher/RegexpMatcher.h + pathmatcher/SimplePrefixMatcher.h ) set(NET_SOURCES @@ -575,6 +576,8 @@ SET(LAUNCHER_SOURCES # Application base Application.h Application.cpp + DataMigrationTask.h + DataMigrationTask.cpp UpdateController.cpp UpdateController.h ApplicationMessage.h @@ -598,6 +601,8 @@ SET(LAUNCHER_SOURCES resources/pe_light/pe_light.qrc resources/pe_colored/pe_colored.qrc resources/pe_blue/pe_blue.qrc + resources/breeze_dark/breeze_dark.qrc + resources/breeze_light/breeze_light.qrc resources/OSX/OSX.qrc resources/iOS/iOS.qrc resources/flat/flat.qrc @@ -960,6 +965,8 @@ qt_add_resources(LAUNCHER_RESOURCES resources/pe_light/pe_light.qrc resources/pe_colored/pe_colored.qrc resources/pe_blue/pe_blue.qrc + resources/breeze_dark/breeze_dark.qrc + resources/breeze_light/breeze_light.qrc resources/OSX/OSX.qrc resources/iOS/iOS.qrc resources/flat/flat.qrc diff --git a/launcher/DataMigrationTask.cpp b/launcher/DataMigrationTask.cpp new file mode 100644 index 00000000..27ce5f01 --- /dev/null +++ b/launcher/DataMigrationTask.cpp @@ -0,0 +1,96 @@ +// SPDX-FileCopyrightText: 2022 Sefa Eyeoglu +// +// SPDX-License-Identifier: GPL-3.0-only + +#include "DataMigrationTask.h" + +#include "FileSystem.h" + +#include +#include +#include + +#include + +DataMigrationTask::DataMigrationTask(QObject* parent, + const QString& sourcePath, + const QString& targetPath, + const IPathMatcher::Ptr pathMatcher) + : Task(parent), m_sourcePath(sourcePath), m_targetPath(targetPath), m_pathMatcher(pathMatcher), m_copy(sourcePath, targetPath) +{ + m_copy.matcher(m_pathMatcher.get()).whitelist(true); +} + +void DataMigrationTask::executeTask() +{ + setStatus(tr("Scanning files...")); + + // 1. Scan + // Check how many files we gotta copy + m_copyFuture = QtConcurrent::run(QThreadPool::globalInstance(), [&] { + return m_copy(true); // dry run to collect amount of files + }); + connect(&m_copyFutureWatcher, &QFutureWatcher::finished, this, &DataMigrationTask::dryRunFinished); + connect(&m_copyFutureWatcher, &QFutureWatcher::canceled, this, &DataMigrationTask::dryRunAborted); + m_copyFutureWatcher.setFuture(m_copyFuture); +} + +void DataMigrationTask::dryRunFinished() +{ + disconnect(&m_copyFutureWatcher, &QFutureWatcher::finished, this, &DataMigrationTask::dryRunFinished); + disconnect(&m_copyFutureWatcher, &QFutureWatcher::canceled, this, &DataMigrationTask::dryRunAborted); + +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + if (!m_copyFuture.isValid() || !m_copyFuture.result()) { +#else + if (!m_copyFuture.result()) { +#endif + emitFailed(tr("Failed to scan source path.")); + return; + } + + // 2. Copy + // Actually copy all files now. + m_toCopy = m_copy.totalCopied(); + connect(&m_copy, &FS::copy::fileCopied, [&, this](const QString& relativeName) { + QString shortenedName = relativeName; + // shorten the filename to hopefully fit into one line + if (shortenedName.length() > 50) + shortenedName = relativeName.left(20) + "…" + relativeName.right(29); + setProgress(m_copy.totalCopied(), m_toCopy); + setStatus(tr("Copying %1…").arg(shortenedName)); + }); + m_copyFuture = QtConcurrent::run(QThreadPool::globalInstance(), [&] { + return m_copy(false); // actually copy now + }); + connect(&m_copyFutureWatcher, &QFutureWatcher::finished, this, &DataMigrationTask::copyFinished); + connect(&m_copyFutureWatcher, &QFutureWatcher::canceled, this, &DataMigrationTask::copyAborted); + m_copyFutureWatcher.setFuture(m_copyFuture); +} + +void DataMigrationTask::dryRunAborted() +{ + emitFailed(tr("Aborted")); +} + +void DataMigrationTask::copyFinished() +{ + disconnect(&m_copyFutureWatcher, &QFutureWatcher::finished, this, &DataMigrationTask::copyFinished); + disconnect(&m_copyFutureWatcher, &QFutureWatcher::canceled, this, &DataMigrationTask::copyAborted); + +#if (QT_VERSION >= QT_VERSION_CHECK(6, 0, 0)) + if (!m_copyFuture.isValid() || !m_copyFuture.result()) { +#else + if (!m_copyFuture.result()) { +#endif + emitFailed(tr("Some paths could not be copied!")); + return; + } + + emitSucceeded(); +} + +void DataMigrationTask::copyAborted() +{ + emitFailed(tr("Aborted")); +} diff --git a/launcher/DataMigrationTask.h b/launcher/DataMigrationTask.h new file mode 100644 index 00000000..6cc23b1a --- /dev/null +++ b/launcher/DataMigrationTask.h @@ -0,0 +1,42 @@ +// SPDX-FileCopyrightText: 2022 Sefa Eyeoglu +// +// SPDX-License-Identifier: GPL-3.0-only + +#pragma once + +#include "FileSystem.h" +#include "pathmatcher/IPathMatcher.h" +#include "tasks/Task.h" + +#include +#include + +/* + * Migrate existing data from other MMC-like launchers. + */ + +class DataMigrationTask : public Task { + Q_OBJECT + public: + explicit DataMigrationTask(QObject* parent, const QString& sourcePath, const QString& targetPath, const IPathMatcher::Ptr pathmatcher); + ~DataMigrationTask() override = default; + + protected: + virtual void executeTask() override; + + protected slots: + void dryRunFinished(); + void dryRunAborted(); + void copyFinished(); + void copyAborted(); + + private: + const QString& m_sourcePath; + const QString& m_targetPath; + const IPathMatcher::Ptr m_pathMatcher; + + FS::copy m_copy; + int m_toCopy = 0; + QFuture m_copyFuture; + QFutureWatcher m_copyFutureWatcher; +}; diff --git a/launcher/FileSystem.cpp b/launcher/FileSystem.cpp index 4a8f4bd3..0c6527b1 100644 --- a/launcher/FileSystem.cpp +++ b/launcher/FileSystem.cpp @@ -152,9 +152,10 @@ bool ensureFolderPathExists(QString foldernamepath) /// @brief Copies a directory and it's contents from src to dest /// @param offset subdirectory form src to copy to dest /// @return if there was an error during the filecopy -bool copy::operator()(const QString& offset) +bool copy::operator()(const QString& offset, bool dryRun) { using copy_opts = fs::copy_options; + m_copied = 0; // reset counter // NOTE always deep copy on windows. the alternatives are too messy. #if defined Q_OS_WIN32 @@ -174,13 +175,14 @@ bool copy::operator()(const QString& offset) // Function that'll do the actual copying auto copy_file = [&](QString src_path, QString relative_dst_path) { - if (m_blacklist && m_blacklist->matches(relative_dst_path)) + if (m_matcher && (m_matcher->matches(relative_dst_path) != m_whitelist)) return; auto dst_path = PathCombine(dst, relative_dst_path); - ensureFilePathExists(dst_path); - - fs::copy(StringUtils::toStdString(src_path), StringUtils::toStdString(dst_path), opt, err); + if (!dryRun) { + ensureFilePathExists(dst_path); + fs::copy(StringUtils::toStdString(src_path), StringUtils::toStdString(dst_path), opt, err); + } if (err) { qWarning() << "Failed to copy files:" << QString::fromStdString(err.message()); qDebug() << "Source file:" << src_path; diff --git a/launcher/FileSystem.h b/launcher/FileSystem.h index b7e175fd..a9a81123 100644 --- a/launcher/FileSystem.h +++ b/launcher/FileSystem.h @@ -40,6 +40,7 @@ #include #include +#include namespace FS { @@ -76,9 +77,10 @@ bool ensureFilePathExists(QString filenamepath); bool ensureFolderPathExists(QString filenamepath); /// @brief Copies a directory and it's contents from src to dest -class copy { +class copy : public QObject { + Q_OBJECT public: - copy(const QString& src, const QString& dst) + copy(const QString& src, const QString& dst, QObject* parent = nullptr) : QObject(parent) { m_src.setPath(src); m_dst.setPath(dst); @@ -88,21 +90,35 @@ class copy { m_followSymlinks = follow; return *this; } - copy& blacklist(const IPathMatcher* filter) + copy& matcher(const IPathMatcher* filter) { - m_blacklist = filter; + m_matcher = filter; return *this; } - bool operator()() { return operator()(QString()); } + copy& whitelist(bool whitelist) + { + m_whitelist = whitelist; + return *this; + } + + bool operator()(bool dryRun = false) { return operator()(QString(), dryRun); } + + int totalCopied() { return m_copied; } + + signals: + void fileCopied(const QString& relativeName); + // TODO: maybe add a "shouldCopy" signal in the future? private: - bool operator()(const QString& offset); + bool operator()(const QString& offset, bool dryRun = false); private: bool m_followSymlinks = true; - const IPathMatcher* m_blacklist = nullptr; + const IPathMatcher* m_matcher = nullptr; + bool m_whitelist = false; QDir m_src; QDir m_dst; + int m_copied; }; /** diff --git a/launcher/InstanceCopyTask.cpp b/launcher/InstanceCopyTask.cpp index a4ea947d..0a83ed9c 100644 --- a/launcher/InstanceCopyTask.cpp +++ b/launcher/InstanceCopyTask.cpp @@ -26,9 +26,11 @@ void InstanceCopyTask::executeTask() setStatus(tr("Copying instance %1").arg(m_origInstance->name())); FS::copy folderCopy(m_origInstance->instanceRoot(), m_stagingPath); - folderCopy.followSymlinks(false).blacklist(m_matcher.get()); + folderCopy.followSymlinks(false).matcher(m_matcher.get()); - m_copyFuture = QtConcurrent::run(QThreadPool::globalInstance(), folderCopy); + m_copyFuture = QtConcurrent::run(QThreadPool::globalInstance(), [&folderCopy]{ + return folderCopy(); + }); connect(&m_copyFutureWatcher, &QFutureWatcher::finished, this, &InstanceCopyTask::copyFinished); connect(&m_copyFutureWatcher, &QFutureWatcher::canceled, this, &InstanceCopyTask::copyAborted); m_copyFutureWatcher.setFuture(m_copyFuture); diff --git a/launcher/main.cpp b/launcher/main.cpp index df596449..b63f8bfd 100644 --- a/launcher/main.cpp +++ b/launcher/main.cpp @@ -81,6 +81,8 @@ int main(int argc, char *argv[]) Q_INIT_RESOURCE(pe_light); Q_INIT_RESOURCE(pe_blue); Q_INIT_RESOURCE(pe_colored); + Q_INIT_RESOURCE(breeze_dark); + Q_INIT_RESOURCE(breeze_light); Q_INIT_RESOURCE(OSX); Q_INIT_RESOURCE(iOS); Q_INIT_RESOURCE(flat); diff --git a/launcher/minecraft/MinecraftInstance.cpp b/launcher/minecraft/MinecraftInstance.cpp index de22b365..70d0b949 100644 --- a/launcher/minecraft/MinecraftInstance.cpp +++ b/launcher/minecraft/MinecraftInstance.cpp @@ -1,8 +1,9 @@ // SPDX-License-Identifier: GPL-3.0-only /* - * PolyMC - Minecraft Launcher + * Prism Launcher - Minecraft Launcher * Copyright (C) 2022 Sefa Eyeoglu * Copyright (C) 2022 Jamie Mansfield + * Copyright (C) 2022 TheKodeToad * * 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 @@ -436,6 +437,17 @@ QStringList MinecraftInstance::javaArguments() return args; } +QString MinecraftInstance::getLauncher() +{ + auto profile = m_components->getProfile(); + + // use legacy launcher if the traits are set + if (profile->getTraits().contains("legacyLaunch") || profile->getTraits().contains("alphaLaunch")) + return "legacy"; + + return "standard"; +} + QMap MinecraftInstance::getVariables() { QMap out; @@ -627,26 +639,13 @@ QString MinecraftInstance::createLaunchScript(AuthSessionPtr session, MinecraftS launchScript += "sessionId " + session->session + "\n"; } - // libraries and class path. - { - QStringList jars, nativeJars; - profile->getLibraryFiles(runtimeContext(), jars, nativeJars, getLocalLibraryPath(), binRoot()); - for(auto file: jars) - { - launchScript += "cp " + file + "\n"; - } - for(auto file: nativeJars) - { - launchScript += "ext " + file + "\n"; - } - launchScript += "natives " + getNativePath() + "\n"; - } - for (auto trait : profile->getTraits()) { launchScript += "traits " + trait + "\n"; } - launchScript += "launcher onesix\n"; + + launchScript += "launcher " + getLauncher() + "\n"; + // qDebug() << "Generated launch script:" << launchScript; return launchScript; } @@ -782,6 +781,8 @@ QStringList MinecraftInstance::verboseDescription(AuthSessionPtr session, Minecr out << "Window size: " + QString::number(width) + " x " + QString::number(height); } out << ""; + out << "Launcher: " + getLauncher(); + out << ""; return out; } diff --git a/launcher/minecraft/MinecraftInstance.h b/launcher/minecraft/MinecraftInstance.h index 1895d187..1bbd7b83 100644 --- a/launcher/minecraft/MinecraftInstance.h +++ b/launcher/minecraft/MinecraftInstance.h @@ -1,7 +1,8 @@ // SPDX-License-Identifier: GPL-3.0-only /* - * PolyMC - Minecraft Launcher + * Prism Launcher - Minecraft Launcher * Copyright (C) 2022 Sefa Eyeoglu + * Copyright (C) 2022 TheKodeToad * * 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 @@ -130,6 +131,7 @@ public: QString createLaunchScript(AuthSessionPtr session, MinecraftServerTargetPtr serverToJoin); /// get arguments passed to java QStringList javaArguments(); + QString getLauncher(); /// get variables for launch command variable substitution/environment QMap getVariables() override; diff --git a/launcher/pathmatcher/SimplePrefixMatcher.h b/launcher/pathmatcher/SimplePrefixMatcher.h new file mode 100644 index 00000000..fc1f5ced --- /dev/null +++ b/launcher/pathmatcher/SimplePrefixMatcher.h @@ -0,0 +1,25 @@ +// SPDX-FileCopyrightText: 2022 Sefa Eyeoglu +// +// SPDX-License-Identifier: GPL-3.0-only + +#include +#include "IPathMatcher.h" + +class SimplePrefixMatcher : public IPathMatcher { + public: + virtual ~SimplePrefixMatcher(){}; + SimplePrefixMatcher(const QString& prefix) + { + m_prefix = prefix; + m_isPrefix = prefix.endsWith('/'); + } + + virtual bool matches(const QString& string) const override + { + if (m_isPrefix) + return string.startsWith(m_prefix); + return string == m_prefix; + } + QString m_prefix; + bool m_isPrefix = false; +}; diff --git a/launcher/resources/breeze_dark/breeze_dark.qrc b/launcher/resources/breeze_dark/breeze_dark.qrc new file mode 100644 index 00000000..4d7a69b2 --- /dev/null +++ b/launcher/resources/breeze_dark/breeze_dark.qrc @@ -0,0 +1,43 @@ + + + index.theme + scalable/about.svg + scalable/accounts.svg + scalable/bug.svg + scalable/centralmods.svg + scalable/checkupdate.svg + scalable/copy.svg + scalable/coremods.svg + scalable/custom-commands.svg + scalable/discord.svg + scalable/externaltools.svg + scalable/help.svg + scalable/instance-settings.svg + scalable/jarmods.svg + scalable/java.svg + scalable/language.svg + scalable/loadermods.svg + scalable/log.svg + scalable/minecraft.svg + scalable/new.svg + scalable/news.svg + scalable/notes.svg + scalable/proxy.svg + scalable/reddit-alien.svg + scalable/refresh.svg + scalable/resourcepacks.svg + scalable/shaderpacks.svg + scalable/screenshots.svg + scalable/settings.svg + scalable/status-bad.svg + scalable/status-good.svg + scalable/status-yellow.svg + scalable/viewfolder.svg + scalable/worlds.svg + scalable/delete.svg + scalable/tag.svg + scalable/export.svg + scalable/rename.svg + scalable/launch.svg + + diff --git a/launcher/resources/breeze_dark/index.theme b/launcher/resources/breeze_dark/index.theme new file mode 100644 index 00000000..f9f6f4dc --- /dev/null +++ b/launcher/resources/breeze_dark/index.theme @@ -0,0 +1,11 @@ +[Icon Theme] +Name=Breeze Dark +Comment=Breeze Dark Icons +Inherits=multimc +Directories=scalable + +[scalable] +Size=48 +Type=Scalable +MinSize=16 +MaxSize=256 diff --git a/launcher/resources/breeze_dark/scalable/about.svg b/launcher/resources/breeze_dark/scalable/about.svg new file mode 100644 index 00000000..856d1b2b --- /dev/null +++ b/launcher/resources/breeze_dark/scalable/about.svg @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/launcher/resources/breeze_dark/scalable/accounts.svg b/launcher/resources/breeze_dark/scalable/accounts.svg new file mode 100644 index 00000000..fbb51959 --- /dev/null +++ b/launcher/resources/breeze_dark/scalable/accounts.svg @@ -0,0 +1,17 @@ + + + + + + diff --git a/launcher/resources/breeze_dark/scalable/bug.svg b/launcher/resources/breeze_dark/scalable/bug.svg new file mode 100644 index 00000000..6ddf482f --- /dev/null +++ b/launcher/resources/breeze_dark/scalable/bug.svg @@ -0,0 +1,13 @@ + + + + + + diff --git a/launcher/resources/breeze_dark/scalable/centralmods.svg b/launcher/resources/breeze_dark/scalable/centralmods.svg new file mode 100644 index 00000000..4035e51c --- /dev/null +++ b/launcher/resources/breeze_dark/scalable/centralmods.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/launcher/resources/breeze_dark/scalable/checkupdate.svg b/launcher/resources/breeze_dark/scalable/checkupdate.svg new file mode 100644 index 00000000..cc5dfc16 --- /dev/null +++ b/launcher/resources/breeze_dark/scalable/checkupdate.svg @@ -0,0 +1,14 @@ + + + + + + diff --git a/launcher/resources/breeze_dark/scalable/copy.svg b/launcher/resources/breeze_dark/scalable/copy.svg new file mode 100644 index 00000000..fe4a36ac --- /dev/null +++ b/launcher/resources/breeze_dark/scalable/copy.svg @@ -0,0 +1,11 @@ + + + + + + + diff --git a/launcher/resources/breeze_dark/scalable/coremods.svg b/launcher/resources/breeze_dark/scalable/coremods.svg new file mode 100644 index 00000000..ec4ecea8 --- /dev/null +++ b/launcher/resources/breeze_dark/scalable/coremods.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/launcher/resources/breeze_dark/scalable/custom-commands.svg b/launcher/resources/breeze_dark/scalable/custom-commands.svg new file mode 100644 index 00000000..44efd39e --- /dev/null +++ b/launcher/resources/breeze_dark/scalable/custom-commands.svg @@ -0,0 +1,13 @@ + + + + + + diff --git a/launcher/resources/breeze_dark/scalable/delete.svg b/launcher/resources/breeze_dark/scalable/delete.svg new file mode 100644 index 00000000..c7074585 --- /dev/null +++ b/launcher/resources/breeze_dark/scalable/delete.svg @@ -0,0 +1,13 @@ + + + + + + diff --git a/launcher/resources/breeze_dark/scalable/discord.svg b/launcher/resources/breeze_dark/scalable/discord.svg new file mode 100644 index 00000000..22ee27ba --- /dev/null +++ b/launcher/resources/breeze_dark/scalable/discord.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/launcher/resources/breeze_dark/scalable/export.svg b/launcher/resources/breeze_dark/scalable/export.svg new file mode 100644 index 00000000..b1fe39d1 --- /dev/null +++ b/launcher/resources/breeze_dark/scalable/export.svg @@ -0,0 +1,11 @@ + + + + + + + diff --git a/launcher/resources/breeze_dark/scalable/externaltools.svg b/launcher/resources/breeze_dark/scalable/externaltools.svg new file mode 100644 index 00000000..dd19fb90 --- /dev/null +++ b/launcher/resources/breeze_dark/scalable/externaltools.svg @@ -0,0 +1,13 @@ + + + + + + diff --git a/launcher/resources/breeze_dark/scalable/help.svg b/launcher/resources/breeze_dark/scalable/help.svg new file mode 100644 index 00000000..b273a8bc --- /dev/null +++ b/launcher/resources/breeze_dark/scalable/help.svg @@ -0,0 +1,13 @@ + + + + + + diff --git a/launcher/resources/breeze_dark/scalable/instance-settings.svg b/launcher/resources/breeze_dark/scalable/instance-settings.svg new file mode 100644 index 00000000..c5f0504b --- /dev/null +++ b/launcher/resources/breeze_dark/scalable/instance-settings.svg @@ -0,0 +1,13 @@ + + + + + + diff --git a/launcher/resources/breeze_dark/scalable/jarmods.svg b/launcher/resources/breeze_dark/scalable/jarmods.svg new file mode 100644 index 00000000..49a45d36 --- /dev/null +++ b/launcher/resources/breeze_dark/scalable/jarmods.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/launcher/resources/breeze_dark/scalable/java.svg b/launcher/resources/breeze_dark/scalable/java.svg new file mode 100644 index 00000000..7149981c --- /dev/null +++ b/launcher/resources/breeze_dark/scalable/java.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/launcher/resources/breeze_dark/scalable/language.svg b/launcher/resources/breeze_dark/scalable/language.svg new file mode 100644 index 00000000..239cdf94 --- /dev/null +++ b/launcher/resources/breeze_dark/scalable/language.svg @@ -0,0 +1,13 @@ + + + + + + diff --git a/launcher/resources/breeze_dark/scalable/launch.svg b/launcher/resources/breeze_dark/scalable/launch.svg new file mode 100644 index 00000000..25c5fabc --- /dev/null +++ b/launcher/resources/breeze_dark/scalable/launch.svg @@ -0,0 +1,8 @@ + + + + diff --git a/launcher/resources/breeze_dark/scalable/launcher.svg b/launcher/resources/breeze_dark/scalable/launcher.svg new file mode 100644 index 00000000..aeee8433 --- /dev/null +++ b/launcher/resources/breeze_dark/scalable/launcher.svg @@ -0,0 +1,57 @@ + + + + Prism Launcher Logo + + + + + + + + + + + + + + + + + + + + + + + Prism Launcher Logo + 19/10/2022 + + + Prism Launcher + + + + + AutiOne, Boba, ely, Fulmine, gon sawa, Pankakes, tobimori, Zeke + + + https://github.com/PrismLauncher/PrismLauncher + + + Prism Launcher + + + + + + + + + + + + + + + diff --git a/launcher/resources/breeze_dark/scalable/loadermods.svg b/launcher/resources/breeze_dark/scalable/loadermods.svg new file mode 100644 index 00000000..7bd87188 --- /dev/null +++ b/launcher/resources/breeze_dark/scalable/loadermods.svg @@ -0,0 +1,13 @@ + + + + + + diff --git a/launcher/resources/breeze_dark/scalable/log.svg b/launcher/resources/breeze_dark/scalable/log.svg new file mode 100644 index 00000000..fcd83c4d --- /dev/null +++ b/launcher/resources/breeze_dark/scalable/log.svg @@ -0,0 +1,13 @@ + + + + + + diff --git a/launcher/resources/breeze_dark/scalable/matrix.svg b/launcher/resources/breeze_dark/scalable/matrix.svg new file mode 100644 index 00000000..214f5708 --- /dev/null +++ b/launcher/resources/breeze_dark/scalable/matrix.svg @@ -0,0 +1,9 @@ + + + Matrix (protocol) logo + + + + + + \ No newline at end of file diff --git a/launcher/resources/breeze_dark/scalable/minecraft.svg b/launcher/resources/breeze_dark/scalable/minecraft.svg new file mode 100644 index 00000000..1d8d0167 --- /dev/null +++ b/launcher/resources/breeze_dark/scalable/minecraft.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/launcher/resources/breeze_dark/scalable/new.svg b/launcher/resources/breeze_dark/scalable/new.svg new file mode 100644 index 00000000..9ee910e7 --- /dev/null +++ b/launcher/resources/breeze_dark/scalable/new.svg @@ -0,0 +1,18 @@ + + + + + + diff --git a/launcher/resources/breeze_dark/scalable/news.svg b/launcher/resources/breeze_dark/scalable/news.svg new file mode 100644 index 00000000..a2ff0c8d --- /dev/null +++ b/launcher/resources/breeze_dark/scalable/news.svg @@ -0,0 +1,13 @@ + + + + + + diff --git a/launcher/resources/breeze_dark/scalable/notes.svg b/launcher/resources/breeze_dark/scalable/notes.svg new file mode 100644 index 00000000..6452d3c8 --- /dev/null +++ b/launcher/resources/breeze_dark/scalable/notes.svg @@ -0,0 +1,13 @@ + + + + + + diff --git a/launcher/resources/breeze_dark/scalable/patreon.svg b/launcher/resources/breeze_dark/scalable/patreon.svg new file mode 100644 index 00000000..7f98dd13 --- /dev/null +++ b/launcher/resources/breeze_dark/scalable/patreon.svg @@ -0,0 +1,3 @@ + + + diff --git a/launcher/resources/breeze_dark/scalable/proxy.svg b/launcher/resources/breeze_dark/scalable/proxy.svg new file mode 100644 index 00000000..c6efb171 --- /dev/null +++ b/launcher/resources/breeze_dark/scalable/proxy.svg @@ -0,0 +1,14 @@ + + + + + + diff --git a/launcher/resources/breeze_dark/scalable/reddit-alien.svg b/launcher/resources/breeze_dark/scalable/reddit-alien.svg new file mode 100644 index 00000000..00f82bb3 --- /dev/null +++ b/launcher/resources/breeze_dark/scalable/reddit-alien.svg @@ -0,0 +1,3 @@ + + + diff --git a/launcher/resources/breeze_dark/scalable/refresh.svg b/launcher/resources/breeze_dark/scalable/refresh.svg new file mode 100644 index 00000000..7b486463 --- /dev/null +++ b/launcher/resources/breeze_dark/scalable/refresh.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/launcher/resources/breeze_dark/scalable/rename.svg b/launcher/resources/breeze_dark/scalable/rename.svg new file mode 100644 index 00000000..6a844965 --- /dev/null +++ b/launcher/resources/breeze_dark/scalable/rename.svg @@ -0,0 +1,13 @@ + + + + + + diff --git a/launcher/resources/breeze_dark/scalable/resourcepacks.svg b/launcher/resources/breeze_dark/scalable/resourcepacks.svg new file mode 100644 index 00000000..0986c216 --- /dev/null +++ b/launcher/resources/breeze_dark/scalable/resourcepacks.svg @@ -0,0 +1,11 @@ + + + + + + + diff --git a/launcher/resources/breeze_dark/scalable/screenshots.svg b/launcher/resources/breeze_dark/scalable/screenshots.svg new file mode 100644 index 00000000..a10ed713 --- /dev/null +++ b/launcher/resources/breeze_dark/scalable/screenshots.svg @@ -0,0 +1,13 @@ + + + + + + diff --git a/launcher/resources/breeze_dark/scalable/settings.svg b/launcher/resources/breeze_dark/scalable/settings.svg new file mode 100644 index 00000000..009d8154 --- /dev/null +++ b/launcher/resources/breeze_dark/scalable/settings.svg @@ -0,0 +1,17 @@ + + + + + + diff --git a/launcher/resources/breeze_dark/scalable/shaderpacks.svg b/launcher/resources/breeze_dark/scalable/shaderpacks.svg new file mode 100644 index 00000000..b2887947 --- /dev/null +++ b/launcher/resources/breeze_dark/scalable/shaderpacks.svg @@ -0,0 +1,13 @@ + + + + + + diff --git a/launcher/resources/breeze_dark/scalable/status-bad.svg b/launcher/resources/breeze_dark/scalable/status-bad.svg new file mode 100644 index 00000000..6fc3137e --- /dev/null +++ b/launcher/resources/breeze_dark/scalable/status-bad.svg @@ -0,0 +1,9 @@ + + + + + diff --git a/launcher/resources/breeze_dark/scalable/status-good.svg b/launcher/resources/breeze_dark/scalable/status-good.svg new file mode 100644 index 00000000..eb8bc03b --- /dev/null +++ b/launcher/resources/breeze_dark/scalable/status-good.svg @@ -0,0 +1,10 @@ + + + + + diff --git a/launcher/resources/breeze_dark/scalable/status-yellow.svg b/launcher/resources/breeze_dark/scalable/status-yellow.svg new file mode 100644 index 00000000..1dc4d0f5 --- /dev/null +++ b/launcher/resources/breeze_dark/scalable/status-yellow.svg @@ -0,0 +1,9 @@ + + + + + diff --git a/launcher/resources/breeze_dark/scalable/tag.svg b/launcher/resources/breeze_dark/scalable/tag.svg new file mode 100644 index 00000000..b54b515f --- /dev/null +++ b/launcher/resources/breeze_dark/scalable/tag.svg @@ -0,0 +1,17 @@ + + + + + + diff --git a/launcher/resources/breeze_dark/scalable/viewfolder.svg b/launcher/resources/breeze_dark/scalable/viewfolder.svg new file mode 100644 index 00000000..0189b954 --- /dev/null +++ b/launcher/resources/breeze_dark/scalable/viewfolder.svg @@ -0,0 +1,13 @@ + + + + + + diff --git a/launcher/resources/breeze_dark/scalable/worlds.svg b/launcher/resources/breeze_dark/scalable/worlds.svg new file mode 100644 index 00000000..0cff8266 --- /dev/null +++ b/launcher/resources/breeze_dark/scalable/worlds.svg @@ -0,0 +1,16 @@ + + + + + + + + diff --git a/launcher/resources/breeze_light/breeze_light.qrc b/launcher/resources/breeze_light/breeze_light.qrc new file mode 100644 index 00000000..7d9d99f5 --- /dev/null +++ b/launcher/resources/breeze_light/breeze_light.qrc @@ -0,0 +1,43 @@ + + + index.theme + scalable/about.svg + scalable/accounts.svg + scalable/bug.svg + scalable/centralmods.svg + scalable/checkupdate.svg + scalable/copy.svg + scalable/coremods.svg + scalable/custom-commands.svg + scalable/discord.svg + scalable/externaltools.svg + scalable/help.svg + scalable/instance-settings.svg + scalable/jarmods.svg + scalable/java.svg + scalable/language.svg + scalable/loadermods.svg + scalable/log.svg + scalable/minecraft.svg + scalable/new.svg + scalable/news.svg + scalable/notes.svg + scalable/proxy.svg + scalable/reddit-alien.svg + scalable/refresh.svg + scalable/resourcepacks.svg + scalable/shaderpacks.svg + scalable/screenshots.svg + scalable/settings.svg + scalable/status-bad.svg + scalable/status-good.svg + scalable/status-yellow.svg + scalable/viewfolder.svg + scalable/worlds.svg + scalable/delete.svg + scalable/tag.svg + scalable/export.svg + scalable/rename.svg + scalable/launch.svg + + diff --git a/launcher/resources/breeze_light/index.theme b/launcher/resources/breeze_light/index.theme new file mode 100644 index 00000000..126d42d7 --- /dev/null +++ b/launcher/resources/breeze_light/index.theme @@ -0,0 +1,11 @@ +[Icon Theme] +Name=Breeze Light +Comment=Breeze Light Icons +Inherits=multimc +Directories=scalable + +[scalable] +Size=48 +Type=Scalable +MinSize=16 +MaxSize=256 diff --git a/launcher/resources/breeze_light/scalable/about.svg b/launcher/resources/breeze_light/scalable/about.svg new file mode 100644 index 00000000..ea1dc02c --- /dev/null +++ b/launcher/resources/breeze_light/scalable/about.svg @@ -0,0 +1,12 @@ + + + + + + + + diff --git a/launcher/resources/breeze_light/scalable/accounts.svg b/launcher/resources/breeze_light/scalable/accounts.svg new file mode 100644 index 00000000..8a542f36 --- /dev/null +++ b/launcher/resources/breeze_light/scalable/accounts.svg @@ -0,0 +1,17 @@ + + + + + + diff --git a/launcher/resources/breeze_light/scalable/bug.svg b/launcher/resources/breeze_light/scalable/bug.svg new file mode 100644 index 00000000..4f41ad6b --- /dev/null +++ b/launcher/resources/breeze_light/scalable/bug.svg @@ -0,0 +1,13 @@ + + + + + + diff --git a/launcher/resources/breeze_light/scalable/centralmods.svg b/launcher/resources/breeze_light/scalable/centralmods.svg new file mode 100644 index 00000000..4035e51c --- /dev/null +++ b/launcher/resources/breeze_light/scalable/centralmods.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/launcher/resources/breeze_light/scalable/checkupdate.svg b/launcher/resources/breeze_light/scalable/checkupdate.svg new file mode 100644 index 00000000..06b31827 --- /dev/null +++ b/launcher/resources/breeze_light/scalable/checkupdate.svg @@ -0,0 +1,14 @@ + + + + + + diff --git a/launcher/resources/breeze_light/scalable/copy.svg b/launcher/resources/breeze_light/scalable/copy.svg new file mode 100644 index 00000000..2557953b --- /dev/null +++ b/launcher/resources/breeze_light/scalable/copy.svg @@ -0,0 +1,11 @@ + + + + + + + diff --git a/launcher/resources/breeze_light/scalable/coremods.svg b/launcher/resources/breeze_light/scalable/coremods.svg new file mode 100644 index 00000000..ec4ecea8 --- /dev/null +++ b/launcher/resources/breeze_light/scalable/coremods.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/launcher/resources/breeze_light/scalable/custom-commands.svg b/launcher/resources/breeze_light/scalable/custom-commands.svg new file mode 100644 index 00000000..b2ac78c5 --- /dev/null +++ b/launcher/resources/breeze_light/scalable/custom-commands.svg @@ -0,0 +1,13 @@ + + + + + + diff --git a/launcher/resources/breeze_light/scalable/delete.svg b/launcher/resources/breeze_light/scalable/delete.svg new file mode 100644 index 00000000..f2aea6e8 --- /dev/null +++ b/launcher/resources/breeze_light/scalable/delete.svg @@ -0,0 +1,13 @@ + + + + + + diff --git a/launcher/resources/breeze_light/scalable/discord.svg b/launcher/resources/breeze_light/scalable/discord.svg new file mode 100644 index 00000000..22ee27ba --- /dev/null +++ b/launcher/resources/breeze_light/scalable/discord.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/launcher/resources/breeze_light/scalable/export.svg b/launcher/resources/breeze_light/scalable/export.svg new file mode 100644 index 00000000..d6314bd7 --- /dev/null +++ b/launcher/resources/breeze_light/scalable/export.svg @@ -0,0 +1,11 @@ + + + + + + + diff --git a/launcher/resources/breeze_light/scalable/externaltools.svg b/launcher/resources/breeze_light/scalable/externaltools.svg new file mode 100644 index 00000000..c965b6c3 --- /dev/null +++ b/launcher/resources/breeze_light/scalable/externaltools.svg @@ -0,0 +1,13 @@ + + + + + + diff --git a/launcher/resources/breeze_light/scalable/help.svg b/launcher/resources/breeze_light/scalable/help.svg new file mode 100644 index 00000000..bcd14e05 --- /dev/null +++ b/launcher/resources/breeze_light/scalable/help.svg @@ -0,0 +1,13 @@ + + + + + + diff --git a/launcher/resources/breeze_light/scalable/instance-settings.svg b/launcher/resources/breeze_light/scalable/instance-settings.svg new file mode 100644 index 00000000..69854d73 --- /dev/null +++ b/launcher/resources/breeze_light/scalable/instance-settings.svg @@ -0,0 +1,13 @@ + + + + + + diff --git a/launcher/resources/breeze_light/scalable/jarmods.svg b/launcher/resources/breeze_light/scalable/jarmods.svg new file mode 100644 index 00000000..49a45d36 --- /dev/null +++ b/launcher/resources/breeze_light/scalable/jarmods.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/launcher/resources/breeze_light/scalable/java.svg b/launcher/resources/breeze_light/scalable/java.svg new file mode 100644 index 00000000..ff86c9cc --- /dev/null +++ b/launcher/resources/breeze_light/scalable/java.svg @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/launcher/resources/breeze_light/scalable/language.svg b/launcher/resources/breeze_light/scalable/language.svg new file mode 100644 index 00000000..3d56d33e --- /dev/null +++ b/launcher/resources/breeze_light/scalable/language.svg @@ -0,0 +1,13 @@ + + + + + + diff --git a/launcher/resources/breeze_light/scalable/launch.svg b/launcher/resources/breeze_light/scalable/launch.svg new file mode 100644 index 00000000..678fd098 --- /dev/null +++ b/launcher/resources/breeze_light/scalable/launch.svg @@ -0,0 +1,8 @@ + + + + diff --git a/launcher/resources/breeze_light/scalable/loadermods.svg b/launcher/resources/breeze_light/scalable/loadermods.svg new file mode 100644 index 00000000..4fb0f96d --- /dev/null +++ b/launcher/resources/breeze_light/scalable/loadermods.svg @@ -0,0 +1,13 @@ + + + + + + diff --git a/launcher/resources/breeze_light/scalable/log.svg b/launcher/resources/breeze_light/scalable/log.svg new file mode 100644 index 00000000..cf9c9b22 --- /dev/null +++ b/launcher/resources/breeze_light/scalable/log.svg @@ -0,0 +1,13 @@ + + + + + + diff --git a/launcher/resources/breeze_light/scalable/matrix.svg b/launcher/resources/breeze_light/scalable/matrix.svg new file mode 100644 index 00000000..4745efc1 --- /dev/null +++ b/launcher/resources/breeze_light/scalable/matrix.svg @@ -0,0 +1,9 @@ + + + Matrix (protocol) logo + + + + + + \ No newline at end of file diff --git a/launcher/resources/breeze_light/scalable/minecraft.svg b/launcher/resources/breeze_light/scalable/minecraft.svg new file mode 100644 index 00000000..1ffb4565 --- /dev/null +++ b/launcher/resources/breeze_light/scalable/minecraft.svg @@ -0,0 +1,13 @@ + + + + + + + + + + + diff --git a/launcher/resources/breeze_light/scalable/new.svg b/launcher/resources/breeze_light/scalable/new.svg new file mode 100644 index 00000000..51babd76 --- /dev/null +++ b/launcher/resources/breeze_light/scalable/new.svg @@ -0,0 +1,18 @@ + + + + + + diff --git a/launcher/resources/breeze_light/scalable/news.svg b/launcher/resources/breeze_light/scalable/news.svg new file mode 100644 index 00000000..3e3ebe95 --- /dev/null +++ b/launcher/resources/breeze_light/scalable/news.svg @@ -0,0 +1,13 @@ + + + + + + diff --git a/launcher/resources/breeze_light/scalable/notes.svg b/launcher/resources/breeze_light/scalable/notes.svg new file mode 100644 index 00000000..a8eaf279 --- /dev/null +++ b/launcher/resources/breeze_light/scalable/notes.svg @@ -0,0 +1,13 @@ + + + + + + diff --git a/launcher/resources/breeze_light/scalable/patreon.svg b/launcher/resources/breeze_light/scalable/patreon.svg new file mode 100644 index 00000000..e12f1f8d --- /dev/null +++ b/launcher/resources/breeze_light/scalable/patreon.svg @@ -0,0 +1,3 @@ + + + diff --git a/launcher/resources/breeze_light/scalable/proxy.svg b/launcher/resources/breeze_light/scalable/proxy.svg new file mode 100644 index 00000000..2e67ff6c --- /dev/null +++ b/launcher/resources/breeze_light/scalable/proxy.svg @@ -0,0 +1,14 @@ + + + + + + diff --git a/launcher/resources/breeze_light/scalable/reddit-alien.svg b/launcher/resources/breeze_light/scalable/reddit-alien.svg new file mode 100644 index 00000000..93b8eedc --- /dev/null +++ b/launcher/resources/breeze_light/scalable/reddit-alien.svg @@ -0,0 +1,3 @@ + + + diff --git a/launcher/resources/breeze_light/scalable/refresh.svg b/launcher/resources/breeze_light/scalable/refresh.svg new file mode 100644 index 00000000..ecd2b394 --- /dev/null +++ b/launcher/resources/breeze_light/scalable/refresh.svg @@ -0,0 +1,8 @@ + + + + + + diff --git a/launcher/resources/breeze_light/scalable/rename.svg b/launcher/resources/breeze_light/scalable/rename.svg new file mode 100644 index 00000000..18ccc58a --- /dev/null +++ b/launcher/resources/breeze_light/scalable/rename.svg @@ -0,0 +1,13 @@ + + + + + + diff --git a/launcher/resources/breeze_light/scalable/resourcepacks.svg b/launcher/resources/breeze_light/scalable/resourcepacks.svg new file mode 100644 index 00000000..913d3c1f --- /dev/null +++ b/launcher/resources/breeze_light/scalable/resourcepacks.svg @@ -0,0 +1,11 @@ + + + + + + + diff --git a/launcher/resources/breeze_light/scalable/screenshots.svg b/launcher/resources/breeze_light/scalable/screenshots.svg new file mode 100644 index 00000000..d984b330 --- /dev/null +++ b/launcher/resources/breeze_light/scalable/screenshots.svg @@ -0,0 +1,13 @@ + + + + + + diff --git a/launcher/resources/breeze_light/scalable/settings.svg b/launcher/resources/breeze_light/scalable/settings.svg new file mode 100644 index 00000000..19e86e26 --- /dev/null +++ b/launcher/resources/breeze_light/scalable/settings.svg @@ -0,0 +1,17 @@ + + + + + + diff --git a/launcher/resources/breeze_light/scalable/shaderpacks.svg b/launcher/resources/breeze_light/scalable/shaderpacks.svg new file mode 100644 index 00000000..591c6af5 --- /dev/null +++ b/launcher/resources/breeze_light/scalable/shaderpacks.svg @@ -0,0 +1,13 @@ + + + + + + diff --git a/launcher/resources/breeze_light/scalable/status-bad.svg b/launcher/resources/breeze_light/scalable/status-bad.svg new file mode 100644 index 00000000..6fc3137e --- /dev/null +++ b/launcher/resources/breeze_light/scalable/status-bad.svg @@ -0,0 +1,9 @@ + + + + + diff --git a/launcher/resources/breeze_light/scalable/status-good.svg b/launcher/resources/breeze_light/scalable/status-good.svg new file mode 100644 index 00000000..eb8bc03b --- /dev/null +++ b/launcher/resources/breeze_light/scalable/status-good.svg @@ -0,0 +1,10 @@ + + + + + diff --git a/launcher/resources/breeze_light/scalable/status-yellow.svg b/launcher/resources/breeze_light/scalable/status-yellow.svg new file mode 100644 index 00000000..1dc4d0f5 --- /dev/null +++ b/launcher/resources/breeze_light/scalable/status-yellow.svg @@ -0,0 +1,9 @@ + + + + + diff --git a/launcher/resources/breeze_light/scalable/tag.svg b/launcher/resources/breeze_light/scalable/tag.svg new file mode 100644 index 00000000..4887d126 --- /dev/null +++ b/launcher/resources/breeze_light/scalable/tag.svg @@ -0,0 +1,17 @@ + + + + + + diff --git a/launcher/resources/breeze_light/scalable/viewfolder.svg b/launcher/resources/breeze_light/scalable/viewfolder.svg new file mode 100644 index 00000000..4a8498ce --- /dev/null +++ b/launcher/resources/breeze_light/scalable/viewfolder.svg @@ -0,0 +1,13 @@ + + + + + + diff --git a/launcher/resources/breeze_light/scalable/worlds.svg b/launcher/resources/breeze_light/scalable/worlds.svg new file mode 100644 index 00000000..543cc55e --- /dev/null +++ b/launcher/resources/breeze_light/scalable/worlds.svg @@ -0,0 +1,16 @@ + + + + + + + + diff --git a/launcher/translations/TranslationsModel.cpp b/launcher/translations/TranslationsModel.cpp index 84778d32..38f48296 100644 --- a/launcher/translations/TranslationsModel.cpp +++ b/launcher/translations/TranslationsModel.cpp @@ -83,6 +83,9 @@ struct Language else if(key == "es_UY") { result = u8"español de Latinoamérica"; } + else if(key == "en_NZ") { + result = u8"New Zealand English"; // No idea why qt translates this to just english and not to New Zealand English + } else if(key == "en@pirate") { result = u8"Tongue of the High Seas"; } diff --git a/launcher/ui/dialogs/ProgressDialog.cpp b/launcher/ui/dialogs/ProgressDialog.cpp index 05269f62..da73a449 100644 --- a/launcher/ui/dialogs/ProgressDialog.cpp +++ b/launcher/ui/dialogs/ProgressDialog.cpp @@ -44,7 +44,8 @@ void ProgressDialog::setSkipButton(bool present, QString label) void ProgressDialog::on_skipButton_clicked(bool checked) { Q_UNUSED(checked); - task->abort(); + if (ui->skipButton->isEnabled()) // prevent other triggers from aborting + task->abort(); } ProgressDialog::~ProgressDialog() diff --git a/launcher/ui/pages/global/LauncherPage.cpp b/launcher/ui/pages/global/LauncherPage.cpp index 6661bf0f..cae0635f 100644 --- a/launcher/ui/pages/global/LauncherPage.cpp +++ b/launcher/ui/pages/global/LauncherPage.cpp @@ -303,21 +303,27 @@ void LauncherPage::applySettings() s->set("IconTheme", "pe_blue"); break; case 4: - s->set("IconTheme", "OSX"); + s->set("IconTheme", "breeze_light"); break; case 5: - s->set("IconTheme", "iOS"); + s->set("IconTheme", "breeze_dark"); break; case 6: - s->set("IconTheme", "flat"); + s->set("IconTheme", "OSX"); break; case 7: - s->set("IconTheme", "flat_white"); + s->set("IconTheme", "iOS"); break; case 8: - s->set("IconTheme", "multimc"); + s->set("IconTheme", "flat"); break; case 9: + s->set("IconTheme", "flat_white"); + break; + case 10: + s->set("IconTheme", "multimc"); + break; + case 11: s->set("IconTheme", "custom"); break; } @@ -397,7 +403,18 @@ void LauncherPage::loadSettings() m_currentUpdateChannel = s->get("UpdateChannel").toString(); //FIXME: make generic auto theme = s->get("IconTheme").toString(); - QStringList iconThemeOptions{"pe_colored", "pe_light", "pe_dark", "pe_blue", "OSX", "iOS", "flat", "flat_white", "multimc", "custom"}; + QStringList iconThemeOptions{"pe_colored", + "pe_light", + "pe_dark", + "pe_blue", + "breeze_light", + "breeze_dark", + "OSX", + "iOS", + "flat", + "flat_white", + "multimc", + "custom"}; ui->themeComboBox->setCurrentIndex(iconThemeOptions.indexOf(theme)); auto cat = s->get("BackgroundCat").toString(); diff --git a/launcher/ui/pages/global/LauncherPage.ui b/launcher/ui/pages/global/LauncherPage.ui index 6de644ee..c44718a1 100644 --- a/launcher/ui/pages/global/LauncherPage.ui +++ b/launcher/ui/pages/global/LauncherPage.ui @@ -285,6 +285,16 @@ Simple (Blue Icons) + + + Breeze Light + + + + + Breeze Dark + + OSX diff --git a/libraries/README.md b/libraries/README.md index dc38477b..ac5a3618 100644 --- a/libraries/README.md +++ b/libraries/README.md @@ -42,19 +42,20 @@ MIT licensed. Java launcher part for Minecraft. -It: +It does the following: -- Starts a process -- Waits for a launch script on stdin -- Consumes the launch script you feed it -- Proceeds with launch when it gets the `launcher` command +- Waits for a launch script on stdin. +- Consumes the launch script you feed it. +- Proceeds with launch when it gets the `launcher` command. + +If "abort" is sent, the process will exit. This means the process is essentially idle until the final command is sent. You can, for example, attach a profiler before you send it. -A `legacy` and `onesix` launchers are available. +The `standard` and `legacy` launchers are available. +- `standard` can handle launching any Minecraft version, at the cost of some extra features `legacy` enables (custom window icon and title). - `legacy` is intended for use with Minecraft versions < 1.6 and is deprecated. -- `onesix` can handle launching any Minecraft version, at the cost of some extra features `legacy` enables (custom window icon and title). Example (some parts have been censored): @@ -64,7 +65,7 @@ mainClass net.minecraft.launchwrapper.Launch param --username param CENSORED param --version -param MultiMC5 +param Prism Launcher param --gameDir param /home/peterix/minecraft/FTB/17ForgeTest/minecraft param --assetsDir @@ -81,58 +82,11 @@ param --userType param mojang param --tweakClass param cpw.mods.fml.common.launcher.FMLTweaker -windowTitle MultiMC: 172ForgeTest +windowTitle Prism Launcher: 172ForgeTest windowParams 854x480 userName CENSORED sessionId token:CENSORED:CENSORED -cp /home/peterix/minecraft/FTB/libraries/com/mojang/realms/1.3.5/realms-1.3.5.jar -cp /home/peterix/minecraft/FTB/libraries/org/apache/commons/commons-compress/1.8.1/commons-compress-1.8.1.jar -cp /home/peterix/minecraft/FTB/libraries/org/apache/httpcomponents/httpclient/4.3.3/httpclient-4.3.3.jar -cp /home/peterix/minecraft/FTB/libraries/commons-logging/commons-logging/1.1.3/commons-logging-1.1.3.jar -cp /home/peterix/minecraft/FTB/libraries/org/apache/httpcomponents/httpcore/4.3.2/httpcore-4.3.2.jar -cp /home/peterix/minecraft/FTB/libraries/java3d/vecmath/1.3.1/vecmath-1.3.1.jar -cp /home/peterix/minecraft/FTB/libraries/net/sf/trove4j/trove4j/3.0.3/trove4j-3.0.3.jar -cp /home/peterix/minecraft/FTB/libraries/com/ibm/icu/icu4j-core-mojang/51.2/icu4j-core-mojang-51.2.jar -cp /home/peterix/minecraft/FTB/libraries/net/sf/jopt-simple/jopt-simple/4.5/jopt-simple-4.5.jar -cp /home/peterix/minecraft/FTB/libraries/com/paulscode/codecjorbis/20101023/codecjorbis-20101023.jar -cp /home/peterix/minecraft/FTB/libraries/com/paulscode/codecwav/20101023/codecwav-20101023.jar -cp /home/peterix/minecraft/FTB/libraries/com/paulscode/libraryjavasound/20101123/libraryjavasound-20101123.jar -cp /home/peterix/minecraft/FTB/libraries/com/paulscode/librarylwjglopenal/20100824/librarylwjglopenal-20100824.jar -cp /home/peterix/minecraft/FTB/libraries/com/paulscode/soundsystem/20120107/soundsystem-20120107.jar -cp /home/peterix/minecraft/FTB/libraries/io/netty/netty-all/4.0.10.Final/netty-all-4.0.10.Final.jar -cp /home/peterix/minecraft/FTB/libraries/com/google/guava/guava/16.0/guava-16.0.jar -cp /home/peterix/minecraft/FTB/libraries/org/apache/commons/commons-lang3/3.2.1/commons-lang3-3.2.1.jar -cp /home/peterix/minecraft/FTB/libraries/commons-io/commons-io/2.4/commons-io-2.4.jar -cp /home/peterix/minecraft/FTB/libraries/commons-codec/commons-codec/1.9/commons-codec-1.9.jar -cp /home/peterix/minecraft/FTB/libraries/net/java/jinput/jinput/2.0.5/jinput-2.0.5.jar -cp /home/peterix/minecraft/FTB/libraries/net/java/jutils/jutils/1.0.0/jutils-1.0.0.jar -cp /home/peterix/minecraft/FTB/libraries/com/google/code/gson/gson/2.2.4/gson-2.2.4.jar -cp /home/peterix/minecraft/FTB/libraries/com/mojang/authlib/1.5.16/authlib-1.5.16.jar -cp /home/peterix/minecraft/FTB/libraries/org/apache/logging/log4j/log4j-api/2.0-beta9/log4j-api-2.0-beta9.jar -cp /home/peterix/minecraft/FTB/libraries/org/apache/logging/log4j/log4j-core/2.0-beta9/log4j-core-2.0-beta9.jar -cp /home/peterix/minecraft/FTB/libraries/org/lwjgl/lwjgl/lwjgl/2.9.1/lwjgl-2.9.1.jar -cp /home/peterix/minecraft/FTB/libraries/org/lwjgl/lwjgl/lwjgl_util/2.9.1/lwjgl_util-2.9.1.jar -cp /home/peterix/minecraft/FTB/libraries/tv/twitch/twitch/5.16/twitch-5.16.jar -cp /home/peterix/minecraft/FTB/libraries/net/minecraftforge/forge/1.7.10-10.13.0.1178/forge-1.7.10-10.13.0.1178.jar -cp /home/peterix/minecraft/FTB/libraries/net/minecraft/launchwrapper/1.9/launchwrapper-1.9.jar -cp /home/peterix/minecraft/FTB/libraries/org/ow2/asm/asm-all/4.1/asm-all-4.1.jar -cp /home/peterix/minecraft/FTB/libraries/com/typesafe/akka/akka-actor_2.11/2.3.3/akka-actor_2.11-2.3.3.jar -cp /home/peterix/minecraft/FTB/libraries/com/typesafe/config/1.2.1/config-1.2.1.jar -cp /home/peterix/minecraft/FTB/libraries/org/scala-lang/scala-actors-migration_2.11/1.1.0/scala-actors-migration_2.11-1.1.0.jar -cp /home/peterix/minecraft/FTB/libraries/org/scala-lang/scala-compiler/2.11.1/scala-compiler-2.11.1.jar -cp /home/peterix/minecraft/FTB/libraries/org/scala-lang/plugins/scala-continuations-library_2.11/1.0.2/scala-continuations-library_2.11-1.0.2.jar -cp /home/peterix/minecraft/FTB/libraries/org/scala-lang/plugins/scala-continuations-plugin_2.11.1/1.0.2/scala-continuations-plugin_2.11.1-1.0.2.jar -cp /home/peterix/minecraft/FTB/libraries/org/scala-lang/scala-library/2.11.1/scala-library-2.11.1.jar -cp /home/peterix/minecraft/FTB/libraries/org/scala-lang/scala-parser-combinators_2.11/1.0.1/scala-parser-combinators_2.11-1.0.1.jar -cp /home/peterix/minecraft/FTB/libraries/org/scala-lang/scala-reflect/2.11.1/scala-reflect-2.11.1.jar -cp /home/peterix/minecraft/FTB/libraries/org/scala-lang/scala-swing_2.11/1.0.1/scala-swing_2.11-1.0.1.jar -cp /home/peterix/minecraft/FTB/libraries/org/scala-lang/scala-xml_2.11/1.0.2/scala-xml_2.11-1.0.2.jar -cp /home/peterix/minecraft/FTB/libraries/lzma/lzma/0.0.1/lzma-0.0.1.jar -ext /home/peterix/minecraft/FTB/libraries/org/lwjgl/lwjgl/lwjgl-platform/2.9.1/lwjgl-platform-2.9.1-natives-linux.jar -ext /home/peterix/minecraft/FTB/libraries/net/java/jinput/jinput-platform/2.0.5/jinput-platform-2.0.5-natives-linux.jar -natives /home/peterix/minecraft/FTB/17ForgeTest/natives -cp /home/peterix/minecraft/FTB/versions/1.7.10/1.7.10.jar -launcher onesix +launcher standard ``` Available under `GPL-3.0-only` (with classpath exception), sublicensed from its original `Apache-2.0` codebase diff --git a/libraries/launcher/.gitignore b/libraries/launcher/.gitignore index cc1c52bf..dda456e3 100644 --- a/libraries/launcher/.gitignore +++ b/libraries/launcher/.gitignore @@ -4,3 +4,4 @@ out .classpath .idea .project +bin/ diff --git a/libraries/launcher/CMakeLists.txt b/libraries/launcher/CMakeLists.txt index df25414f..55ed5875 100644 --- a/libraries/launcher/CMakeLists.txt +++ b/libraries/launcher/CMakeLists.txt @@ -4,18 +4,21 @@ find_package(Java 1.7 REQUIRED COMPONENTS Development) include(UseJava) set(CMAKE_JAVA_JAR_ENTRY_POINT org.prismlauncher.EntryPoint) -set(CMAKE_JAVA_COMPILE_FLAGS -target 7 -source 7 -Xlint:deprecation -Xlint:unchecked) +set(CMAKE_JAVA_COMPILE_FLAGS -target 7 -source 7) set(SRC org/prismlauncher/EntryPoint.java - org/prismlauncher/Launcher.java - org/prismlauncher/LauncherFactory.java - org/prismlauncher/impl/OneSixLauncher.java - org/prismlauncher/applet/LegacyFrame.java + org/prismlauncher/launcher/Launcher.java + org/prismlauncher/launcher/impl/AbstractLauncher.java + org/prismlauncher/launcher/impl/StandardLauncher.java + org/prismlauncher/launcher/impl/legacy/LegacyLauncher.java + org/prismlauncher/launcher/impl/legacy/LegacyFrame.java org/prismlauncher/exception/ParameterNotFoundException.java org/prismlauncher/exception/ParseException.java org/prismlauncher/utils/Parameters.java - org/prismlauncher/utils/Utils.java + org/prismlauncher/utils/ReflectionUtils.java + org/prismlauncher/utils/logging/Level.java + org/prismlauncher/utils/logging/Log.java net/minecraft/Launcher.java ) add_jar(NewLaunch ${SRC}) diff --git a/libraries/launcher/net/minecraft/Launcher.java b/libraries/launcher/net/minecraft/Launcher.java index 6bf671be..646e2e3e 100644 --- a/libraries/launcher/net/minecraft/Launcher.java +++ b/libraries/launcher/net/minecraft/Launcher.java @@ -1,41 +1,83 @@ +// SPDX-License-Identifier: GPL-3.0-only /* - * Copyright 2012-2021 MultiMC Contributors + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 icelimetea + * Copyright (C) 2022 TheKodeToad + * Copyright (C) 2022 solonovamax * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * 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. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Linking this library statically or dynamically with other modules is + * making a combined work based on this library. Thus, the terms and + * conditions of the GNU General Public License cover the whole + * combination. + * + * As a special exception, the copyright holders of this library give + * you permission to link this library with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. An independent module is a module which is + * not derived from or based on this library. If you modify this + * library, you may extend this exception to your version of the + * library, but you are not obliged to do so. If you do not wish to do + * so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package net.minecraft; import java.applet.Applet; import java.applet.AppletStub; -import java.awt.*; +import java.awt.BorderLayout; +import java.awt.Dimension; +import java.awt.Graphics; import java.net.MalformedURLException; import java.net.URL; +import java.util.HashMap; import java.util.Map; -import java.util.TreeMap; -/* +/** * WARNING: This class is reflectively accessed by legacy Forge versions. - * Changing field and method declarations without further testing is not recommended. + *

+ * Changing field and method declarations without further testing is not + * recommended. */ public final class Launcher extends Applet implements AppletStub { - private final Map params = new TreeMap<>(); + private static final long serialVersionUID = 1L; + + private final Map params = new HashMap<>(); private Applet wrappedApplet; - - private URL documentBase; - + private final URL documentBase; private boolean active = false; public Launcher(Applet applet) { @@ -43,35 +85,36 @@ public final class Launcher extends Applet implements AppletStub { } public Launcher(Applet applet, URL documentBase) { - this.setLayout(new BorderLayout()); + setLayout(new BorderLayout()); - this.add(applet, "Center"); + add(applet, "Center"); - this.wrappedApplet = applet; + wrappedApplet = applet; try { - if (documentBase != null) { - this.documentBase = documentBase; - } else if (applet.getClass().getPackage().getName().startsWith("com.mojang")) { - // Special case only for Classic versions - - this.documentBase = new URL("http", "www.minecraft.net", 80, "/game/"); - } else { - this.documentBase = new URL("http://www.minecraft.net/game/"); + if (documentBase == null) { + if (applet.getClass().getPackage().getName().startsWith("com.mojang.")) { + // Special case only for Classic versions + documentBase = new URL("http://www.minecraft.net:80/game/"); + } else { + documentBase = new URL("http://www.minecraft.net/game/"); + } } } catch (MalformedURLException e) { - throw new RuntimeException(e); + throw new AssertionError(e); } + + this.documentBase = documentBase; } public void replace(Applet applet) { - this.wrappedApplet = applet; + wrappedApplet = applet; applet.setStub(this); applet.setSize(getWidth(), getHeight()); - this.setLayout(new BorderLayout()); - this.add(applet, "Center"); + setLayout(new BorderLayout()); + add(applet, "Center"); applet.init(); @@ -82,32 +125,38 @@ public final class Launcher extends Applet implements AppletStub { validate(); } - public void setParameter(String name, String value) { - params.put(name, value); - } - - @Override - public String getParameter(String name) { - String param = params.get(name); - - if (param != null) - return param; - - try { - return super.getParameter(name); - } catch (Exception ignored) {} - - return null; - } - @Override public boolean isActive() { return active; } @Override - public void appletResize(int width, int height) { - wrappedApplet.resize(width, height); + public URL getDocumentBase() { + return documentBase; + } + + @Override + public URL getCodeBase() { + try { + return new URL("http://www.minecraft.net/game/"); + } catch (MalformedURLException e) { + throw new AssertionError(e); + } + } + + @Override + public String getParameter(String key) { + String param = params.get(key); + + if (param != null) + return param; + + try { + return super.getParameter(key); + } catch (Throwable ignored) { + } + + return null; } @Override @@ -116,8 +165,8 @@ public final class Launcher extends Applet implements AppletStub { } @Override - public void resize(Dimension d) { - wrappedApplet.resize(d); + public void resize(Dimension size) { + wrappedApplet.resize(size); } @Override @@ -140,33 +189,37 @@ public final class Launcher extends Applet implements AppletStub { active = false; } + @Override public void destroy() { wrappedApplet.destroy(); } @Override - public URL getCodeBase() { - try { - return new URL("http://www.minecraft.net/game/"); - } catch (MalformedURLException e) { - throw new RuntimeException(e); - } + public void appletResize(int width, int height) { + wrappedApplet.resize(width, height); } @Override - public URL getDocumentBase() { - return documentBase; + public void setVisible(boolean visible) { + super.setVisible(visible); + + wrappedApplet.setVisible(visible); } @Override - public void setVisible(boolean b) { - super.setVisible(b); - - wrappedApplet.setVisible(b); + public void paint(Graphics graphics) { } - public void update(Graphics paramGraphics) {} + @Override + public void update(Graphics graphics) { + } - public void paint(Graphics paramGraphics) {} + public void setParameter(String key, String value) { + params.put(key, value); + } + + public void setParameter(String key, boolean value) { + setParameter(key, value ? "true" : "false"); + } } diff --git a/libraries/launcher/org/prismlauncher/EntryPoint.java b/libraries/launcher/org/prismlauncher/EntryPoint.java index 9144e1f1..78804b3e 100644 --- a/libraries/launcher/org/prismlauncher/EntryPoint.java +++ b/libraries/launcher/org/prismlauncher/EntryPoint.java @@ -1,7 +1,9 @@ // SPDX-License-Identifier: GPL-3.0-only /* - * PolyMC - Minecraft Launcher - * Copyright (C) 2022 icelimetea, + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 icelimetea + * Copyright (C) 2022 TheKodeToad + * Copyright (C) 2022 solonovamax * * 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 @@ -52,113 +54,125 @@ package org.prismlauncher; -import org.prismlauncher.exception.ParseException; -import org.prismlauncher.utils.Parameters; - import java.io.BufferedReader; -import java.io.IOException; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; -import java.util.logging.Level; -import java.util.logging.Logger; + +import org.prismlauncher.exception.ParseException; +import org.prismlauncher.launcher.Launcher; +import org.prismlauncher.launcher.impl.StandardLauncher; +import org.prismlauncher.launcher.impl.legacy.LegacyLauncher; +import org.prismlauncher.utils.Parameters; +import org.prismlauncher.utils.logging.Log; public final class EntryPoint { - private static final Logger LOGGER = Logger.getLogger("EntryPoint"); - - private final Parameters params = new Parameters(); - public static void main(String[] args) { - EntryPoint listener = new EntryPoint(); + ExitCode code = listen(); - int retCode = listener.listen(); + if (code != ExitCode.NORMAL) { + Log.fatal("Exiting with " + code); - if (retCode != 0) { - LOGGER.info("Exiting with " + retCode); - - System.exit(retCode); + System.exit(code.numeric); } } - private Action parseLine(String inData) throws ParseException { - String[] tokens = inData.split("\\s+", 2); + private static ExitCode listen() { + Parameters params = new Parameters(); + PreLaunchAction action = PreLaunchAction.PROCEED; - if (tokens.length == 0) - throw new ParseException("Unexpected empty string!"); - - switch (tokens[0]) { - case "launch": { - return Action.Launch; - } - - case "abort": { - return Action.Abort; - } - - default: { - if (tokens.length != 2) - throw new ParseException("Error while parsing:" + inData); - - params.add(tokens[0], tokens[1]); - - return Action.Proceed; - } - } - } - - public int listen() { - Action action = Action.Proceed; - - try (BufferedReader reader = new BufferedReader(new InputStreamReader( - System.in, - StandardCharsets.UTF_8 - ))) { + try (BufferedReader reader = new BufferedReader(new InputStreamReader(System.in, StandardCharsets.UTF_8))) { String line; - while (action == Action.Proceed) { - if ((line = reader.readLine()) != null) { - action = parseLine(line); - } else { - action = Action.Abort; - } + while (action == PreLaunchAction.PROCEED) { + if ((line = reader.readLine()) != null) + action = parseLine(line, params); + else + action = PreLaunchAction.ABORT; } - } catch (IOException | ParseException e) { - LOGGER.log(Level.SEVERE, "Launcher ABORT due to exception:", e); + } catch (IllegalArgumentException e) { + Log.fatal("Aborting due to wrong argument", e); - return 1; + return ExitCode.ILLEGAL_ARGUMENT; + } catch (Throwable e) { + Log.fatal("Aborting due to exception", e); + + return ExitCode.ABORT; } - // Main loop - if (action == Action.Abort) { - LOGGER.info("Launch aborted by the launcher."); + if (action == PreLaunchAction.ABORT) { + Log.fatal("Launch aborted by the launcher"); - return 1; + return ExitCode.ABORT; } try { - Launcher launcher = - LauncherFactory - .getInstance() - .createLauncher(params); + Launcher launcher; + String type = params.getString("launcher"); + + switch (type) { + case "standard": + launcher = new StandardLauncher(params); + break; + + case "legacy": + launcher = new LegacyLauncher(params); + break; + + default: + throw new IllegalArgumentException("Invalid launcher type: " + type); + } launcher.launch(); - return 0; + return ExitCode.NORMAL; } catch (IllegalArgumentException e) { - LOGGER.log(Level.SEVERE, "Wrong argument.", e); + Log.fatal("Illegal argument", e); - return 1; - } catch (Exception e) { - LOGGER.log(Level.SEVERE, "Exception caught from launcher.", e); + return ExitCode.ILLEGAL_ARGUMENT; + } catch (Throwable e) { + Log.fatal("Exception caught from launcher", e); - return 1; + return ExitCode.ERROR; } } - private enum Action { - Proceed, - Launch, - Abort + private static PreLaunchAction parseLine(String input, Parameters params) throws ParseException { + switch (input) { + case "": + break; + + case "launch": + return PreLaunchAction.LAUNCH; + + case "abort": + return PreLaunchAction.ABORT; + + default: + String[] pair = input.split(" ", 2); + + if (pair.length != 2) + throw new ParseException(input, "[key] [value]"); + + params.add(pair[0], pair[1]); + } + + return PreLaunchAction.PROCEED; + } + + private enum PreLaunchAction { + PROCEED, LAUNCH, ABORT + } + + private enum ExitCode { + NORMAL(0), ABORT(1), ERROR(2), ILLEGAL_ARGUMENT(65); + + private final int numeric; + + ExitCode(int numeric) { + this.numeric = numeric; + } + } } diff --git a/libraries/launcher/org/prismlauncher/Launcher.java b/libraries/launcher/org/prismlauncher/Launcher.java deleted file mode 100644 index 7f25717b..00000000 --- a/libraries/launcher/org/prismlauncher/Launcher.java +++ /dev/null @@ -1,23 +0,0 @@ -/* - * Copyright 2012-2021 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.prismlauncher; - -public interface Launcher { - - void launch() throws Exception; - -} diff --git a/libraries/launcher/org/prismlauncher/applet/LegacyFrame.java b/libraries/launcher/org/prismlauncher/applet/LegacyFrame.java deleted file mode 100644 index 4413efa8..00000000 --- a/libraries/launcher/org/prismlauncher/applet/LegacyFrame.java +++ /dev/null @@ -1,163 +0,0 @@ -/* - * Copyright 2012-2021 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.prismlauncher.applet; - -import net.minecraft.Launcher; - -import javax.imageio.ImageIO; -import java.applet.Applet; -import java.awt.*; -import java.awt.event.WindowAdapter; -import java.awt.event.WindowEvent; -import java.io.File; -import java.io.IOException; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.nio.file.StandardCopyOption; -import java.util.List; -import java.util.logging.Level; -import java.util.logging.Logger; - -public final class LegacyFrame extends Frame { - - private static final Logger LOGGER = Logger.getLogger("LegacyFrame"); - - private final Launcher appletWrap; - - public LegacyFrame(String title, Applet mcApplet) { - super(title); - - appletWrap = new Launcher(mcApplet); - - mcApplet.setStub(appletWrap); - - try { - setIconImage(ImageIO.read(new File("icon.png"))); - } catch (IOException e) { - LOGGER.log(Level.WARNING, "Unable to read Minecraft icon!", e); - } - - addWindowListener(new ForceExitHandler()); - } - - public void start ( - String user, - String session, - int winSizeW, - int winSizeH, - boolean maximize, - String serverAddress, - String serverPort, - boolean isDemo - ) { - // Implements support for launching in to multiplayer on classic servers using a mpticket - // file generated by an external program and stored in the instance's root folder. - - Path mpticketFile = - Paths.get(System.getProperty("user.dir"), "..", "mpticket"); - - Path mpticketFileCorrupt = - Paths.get(System.getProperty("user.dir"), "..", "mpticket.corrupt"); - - if (Files.exists(mpticketFile)) { - try { - List lines = Files.readAllLines(mpticketFile, StandardCharsets.UTF_8); - - if (lines.size() < 3) { - Files.move( - mpticketFile, - mpticketFileCorrupt, - StandardCopyOption.REPLACE_EXISTING - ); - - LOGGER.warning("Mpticket file is corrupted!"); - } else { - // Assumes parameters are valid and in the correct order - appletWrap.setParameter("server", lines.get(0)); - appletWrap.setParameter("port", lines.get(1)); - appletWrap.setParameter("mppass", lines.get(2)); - } - } catch (IOException e) { - LOGGER.log(Level.WARNING, "Unable to read mpticket file!", e); - } - } - - if (serverAddress != null) { - appletWrap.setParameter("server", serverAddress); - appletWrap.setParameter("port", serverPort); - } - - appletWrap.setParameter("username", user); - appletWrap.setParameter("sessionid", session); - appletWrap.setParameter("stand-alone", "true"); // Show the quit button. - appletWrap.setParameter("haspaid", "true"); // Some old versions need this for world saves to work. - appletWrap.setParameter("demo", isDemo ? "true" : "false"); - appletWrap.setParameter("fullscreen", "false"); - - add(appletWrap); - - appletWrap.setPreferredSize(new Dimension(winSizeW, winSizeH)); - - pack(); - - setLocationRelativeTo(null); - setResizable(true); - - if (maximize) - this.setExtendedState(MAXIMIZED_BOTH); - - validate(); - - appletWrap.init(); - appletWrap.start(); - - setVisible(true); - } - - private final class ForceExitHandler extends WindowAdapter { - - @Override - public void windowClosing(WindowEvent e) { - new Thread(new Runnable() { - @Override - public void run() { - try { - Thread.sleep(30000L); - } catch (InterruptedException localInterruptedException) { - localInterruptedException.printStackTrace(); - } - - LOGGER.info("Forcing exit!"); - - System.exit(0); - } - }).start(); - - if (appletWrap != null) { - appletWrap.stop(); - appletWrap.destroy(); - } - - // old minecraft versions can hang without this >_< - System.exit(0); - } - - } - -} diff --git a/libraries/launcher/org/prismlauncher/exception/ParameterNotFoundException.java b/libraries/launcher/org/prismlauncher/exception/ParameterNotFoundException.java index 641e0c99..524076ff 100644 --- a/libraries/launcher/org/prismlauncher/exception/ParameterNotFoundException.java +++ b/libraries/launcher/org/prismlauncher/exception/ParameterNotFoundException.java @@ -1,25 +1,48 @@ +// SPDX-License-Identifier: GPL-3.0-only /* - * Copyright 2012-2021 MultiMC Contributors + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 icelimetea + * Copyright (C) 2022 solonovamax + * Copyright (C) 2022 TheKodeToad * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * 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. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Linking this library statically or dynamically with other modules is + * making a combined work based on this library. Thus, the terms and + * conditions of the GNU General Public License cover the whole + * combination. + * + * As a special exception, the copyright holders of this library give + * you permission to link this library with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. An independent module is a module which is + * not derived from or based on this library. If you modify this + * library, you may extend this exception to your version of the + * library, but you are not obliged to do so. If you do not wish to do + * so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ package org.prismlauncher.exception; public final class ParameterNotFoundException extends IllegalArgumentException { + private static final long serialVersionUID = 1L; + public ParameterNotFoundException(String key) { - super("Unknown parameter name: " + key); + super(String.format("Required parameter '%s' was not found", key)); } } diff --git a/libraries/launcher/org/prismlauncher/exception/ParseException.java b/libraries/launcher/org/prismlauncher/exception/ParseException.java index 51d25a62..4608fdd1 100644 --- a/libraries/launcher/org/prismlauncher/exception/ParseException.java +++ b/libraries/launcher/org/prismlauncher/exception/ParseException.java @@ -1,25 +1,48 @@ +// SPDX-License-Identifier: GPL-3.0-only /* - * Copyright 2012-2021 MultiMC Contributors + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 icelimetea + * Copyright (C) 2022 solonovamax + * Copyright (C) 2022 TheKodeToad * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * 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. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Linking this library statically or dynamically with other modules is + * making a combined work based on this library. Thus, the terms and + * conditions of the GNU General Public License cover the whole + * combination. + * + * As a special exception, the copyright holders of this library give + * you permission to link this library with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. An independent module is a module which is + * not derived from or based on this library. If you modify this + * library, you may extend this exception to your version of the + * library, but you are not obliged to do so. If you do not wish to do + * so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . */ package org.prismlauncher.exception; public final class ParseException extends IllegalArgumentException { - public ParseException(String message) { - super(message); + private static final long serialVersionUID = 1L; + + public ParseException(String input, String format) { + super(String.format("For input '%s' - should match '%s'", input, format)); } } diff --git a/libraries/launcher/org/prismlauncher/impl/OneSixLauncher.java b/libraries/launcher/org/prismlauncher/impl/OneSixLauncher.java deleted file mode 100644 index d6443826..00000000 --- a/libraries/launcher/org/prismlauncher/impl/OneSixLauncher.java +++ /dev/null @@ -1,190 +0,0 @@ -/* Copyright 2012-2021 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.prismlauncher.impl; - -import org.prismlauncher.Launcher; -import org.prismlauncher.applet.LegacyFrame; -import org.prismlauncher.utils.Parameters; -import org.prismlauncher.utils.Utils; - -import java.applet.Applet; -import java.io.File; -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.util.List; -import java.util.ArrayList; -import java.util.logging.Level; -import java.util.logging.Logger; - -public final class OneSixLauncher implements Launcher { - - private static final int DEFAULT_WINDOW_WIDTH = 854; - private static final int DEFAULT_WINDOW_HEIGHT = 480; - - private static final Logger LOGGER = Logger.getLogger("OneSixLauncher"); - - // parameters, separated from ParamBucket - private final List mcParams; - private final List traits; - private final String appletClass; - private final String mainClass; - private final String userName, sessionId; - private final String windowTitle; - - // secondary parameters - private final int winSizeW; - private final int winSizeH; - private final boolean maximize; - private final String cwd; - - private final String serverAddress; - private final String serverPort; - - private final ClassLoader classLoader; - - public OneSixLauncher(Parameters params) { - classLoader = ClassLoader.getSystemClassLoader(); - - mcParams = params.allSafe("param", new ArrayList()); - mainClass = params.firstSafe("mainClass", "net.minecraft.client.Minecraft"); - appletClass = params.firstSafe("appletClass", "net.minecraft.client.MinecraftApplet"); - traits = params.allSafe("traits", new ArrayList()); - - userName = params.first("userName"); - sessionId = params.first("sessionId"); - windowTitle = params.firstSafe("windowTitle", "Minecraft"); - - serverAddress = params.firstSafe("serverAddress", null); - serverPort = params.firstSafe("serverPort", null); - - cwd = System.getProperty("user.dir"); - - String windowParams = params.firstSafe("windowParams", null); - - if (windowParams != null) { - String[] dimStrings = windowParams.split("x"); - - if (windowParams.equalsIgnoreCase("max")) { - maximize = true; - - winSizeW = DEFAULT_WINDOW_WIDTH; - winSizeH = DEFAULT_WINDOW_HEIGHT; - } else if (dimStrings.length == 2) { - maximize = false; - - winSizeW = Integer.parseInt(dimStrings[0]); - winSizeH = Integer.parseInt(dimStrings[1]); - } else { - throw new IllegalArgumentException("Unexpected window size parameter value: " + windowParams); - } - } else { - maximize = false; - - winSizeW = DEFAULT_WINDOW_WIDTH; - winSizeH = DEFAULT_WINDOW_HEIGHT; - } - } - - private void invokeMain(Class mainClass) throws Exception { - Method method = mainClass.getMethod("main", String[].class); - - method.invoke(null, (Object) mcParams.toArray(new String[0])); - } - - private void legacyLaunch() throws Exception { - // Get the Minecraft Class and set the base folder - Class minecraftClass = classLoader.loadClass(mainClass); - - Field baseDirField = Utils.getMinecraftBaseDirField(minecraftClass); - - if (baseDirField == null) { - LOGGER.warning("Could not find Minecraft path field."); - } else { - baseDirField.setAccessible(true); - - baseDirField.set(null, new File(cwd)); - } - - System.setProperty("minecraft.applet.TargetDirectory", cwd); - - if (!traits.contains("noapplet")) { - LOGGER.info("Launching with applet wrapper..."); - - try { - Class mcAppletClass = classLoader.loadClass(appletClass); - - Applet mcApplet = (Applet) mcAppletClass.getConstructor().newInstance(); - - LegacyFrame mcWindow = new LegacyFrame(windowTitle, mcApplet); - - mcWindow.start( - userName, - sessionId, - winSizeW, - winSizeH, - maximize, - serverAddress, - serverPort, - mcParams.contains("--demo") - ); - - return; - } catch (Exception e) { - LOGGER.log(Level.SEVERE, "Applet wrapper failed: ", e); - - LOGGER.warning("Falling back to using main class."); - } - } - - invokeMain(minecraftClass); - } - - private void launchWithMainClass() throws Exception { - // window size, title and state, onesix - - // FIXME: there is no good way to maximize the minecraft window in onesix. - // the following often breaks linux screen setups - // mcparams.add("--fullscreen"); - - if (!maximize) { - mcParams.add("--width"); - mcParams.add(Integer.toString(winSizeW)); - mcParams.add("--height"); - mcParams.add(Integer.toString(winSizeH)); - } - - if (serverAddress != null) { - mcParams.add("--server"); - mcParams.add(serverAddress); - mcParams.add("--port"); - mcParams.add(serverPort); - } - - invokeMain(classLoader.loadClass(mainClass)); - } - - @Override - public void launch() throws Exception { - if (traits.contains("legacyLaunch") || traits.contains("alphaLaunch")) { - // legacy launch uses the applet wrapper - legacyLaunch(); - } else { - // normal launch just calls main() - launchWithMainClass(); - } - } - -} diff --git a/libraries/launcher/org/prismlauncher/launcher/Launcher.java b/libraries/launcher/org/prismlauncher/launcher/Launcher.java new file mode 100644 index 00000000..049a83d8 --- /dev/null +++ b/libraries/launcher/org/prismlauncher/launcher/Launcher.java @@ -0,0 +1,44 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 icelimetea + * Copyright (C) 2022 TheKodeToad + * Copyright (C) 2022 solonovamax + * + * 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. + * + * Linking this library statically or dynamically with other modules is + * making a combined work based on this library. Thus, the terms and + * conditions of the GNU General Public License cover the whole + * combination. + * + * As a special exception, the copyright holders of this library give + * you permission to link this library with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. An independent module is a module which is + * not derived from or based on this library. If you modify this + * library, you may extend this exception to your version of the + * library, but you are not obliged to do so. If you do not wish to do + * so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.prismlauncher.launcher; + +public interface Launcher { + + void launch() throws Throwable; + +} diff --git a/libraries/launcher/org/prismlauncher/launcher/impl/AbstractLauncher.java b/libraries/launcher/org/prismlauncher/launcher/impl/AbstractLauncher.java new file mode 100644 index 00000000..0c2153a9 --- /dev/null +++ b/libraries/launcher/org/prismlauncher/launcher/impl/AbstractLauncher.java @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 icelimetea + * Copyright (C) 2022 TheKodeToad + * Copyright (C) 2022 solonovamax + * + * 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. + * + * Linking this library statically or dynamically with other modules is + * making a combined work based on this library. Thus, the terms and + * conditions of the GNU General Public License cover the whole + * combination. + * + * As a special exception, the copyright holders of this library give + * you permission to link this library with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. An independent module is a module which is + * not derived from or based on this library. If you modify this + * library, you may extend this exception to your version of the + * library, but you are not obliged to do so. If you do not wish to do + * so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.prismlauncher.launcher.impl; + +import java.util.ArrayList; +import java.util.List; + +import org.prismlauncher.exception.ParseException; +import org.prismlauncher.launcher.Launcher; +import org.prismlauncher.utils.Parameters; + +public abstract class AbstractLauncher implements Launcher { + + private static final int DEFAULT_WINDOW_WIDTH = 854, DEFAULT_WINDOW_HEIGHT = 480; + + // parameters, separated from ParamBucket + protected final List gameArgs; + + // secondary parameters + protected final int width, height; + protected final boolean maximize; + protected final String serverAddress, serverPort; + + protected final String mainClassName; + + protected AbstractLauncher(Parameters params) { + gameArgs = params.getList("param", new ArrayList()); + mainClassName = params.getString("mainClass", "net.minecraft.client.Minecraft"); + + serverAddress = params.getString("serverAddress", null); + serverPort = params.getString("serverPort", null); + + String windowParams = params.getString("windowParams", null); + + if ("max".equals(windowParams) || windowParams == null) { + maximize = windowParams != null; + + width = DEFAULT_WINDOW_WIDTH; + height = DEFAULT_WINDOW_HEIGHT; + } else { + maximize = false; + + String[] sizePair = windowParams.split("x", 2); + + if (sizePair.length == 2) { + try { + width = Integer.parseInt(sizePair[0]); + height = Integer.parseInt(sizePair[1]); + return; + } catch (NumberFormatException ignored) { + } + } + + throw new ParseException(windowParams, "[width]x[height]"); + } + } + +} diff --git a/libraries/launcher/org/prismlauncher/launcher/impl/StandardLauncher.java b/libraries/launcher/org/prismlauncher/launcher/impl/StandardLauncher.java new file mode 100644 index 00000000..9436ff15 --- /dev/null +++ b/libraries/launcher/org/prismlauncher/launcher/impl/StandardLauncher.java @@ -0,0 +1,91 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 icelimetea + * Copyright (C) 2022 TheKodeToad + * Copyright (C) 2022 solonovamax + * + * 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. + * + * Linking this library statically or dynamically with other modules is + * making a combined work based on this library. Thus, the terms and + * conditions of the GNU General Public License cover the whole + * combination. + * + * As a special exception, the copyright holders of this library give + * you permission to link this library with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. An independent module is a module which is + * not derived from or based on this library. If you modify this + * library, you may extend this exception to your version of the + * library, but you are not obliged to do so. If you do not wish to do + * so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.prismlauncher.launcher.impl; + +import java.lang.invoke.MethodHandle; + +import org.prismlauncher.utils.Parameters; +import org.prismlauncher.utils.ReflectionUtils; + +public final class StandardLauncher extends AbstractLauncher { + + public StandardLauncher(Parameters params) { + super(params); + } + + @Override + public void launch() throws Throwable { + // window size, title and state + // FIXME doesn't support maximisation + if (!maximize) { + gameArgs.add("--width"); + gameArgs.add(Integer.toString(width)); + gameArgs.add("--height"); + gameArgs.add(Integer.toString(height)); + } + + if (serverAddress != null) { + gameArgs.add("--server"); + gameArgs.add(serverAddress); + gameArgs.add("--port"); + gameArgs.add(serverPort); + } + + // find and invoke the main method + MethodHandle method = ReflectionUtils.findMainMethod(mainClassName); + method.invokeExact(gameArgs.toArray(new String[0])); + } + +} diff --git a/libraries/launcher/org/prismlauncher/launcher/impl/legacy/LegacyFrame.java b/libraries/launcher/org/prismlauncher/launcher/impl/legacy/LegacyFrame.java new file mode 100644 index 00000000..c215e7fe --- /dev/null +++ b/libraries/launcher/org/prismlauncher/launcher/impl/legacy/LegacyFrame.java @@ -0,0 +1,190 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 icelimetea + * Copyright (C) 2022 flow + * Copyright (C) 2022 TheKodeToad + * + * 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. + * + * Linking this library statically or dynamically with other modules is + * making a combined work based on this library. Thus, the terms and + * conditions of the GNU General Public License cover the whole + * combination. + * + * As a special exception, the copyright holders of this library give + * you permission to link this library with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. An independent module is a module which is + * not derived from or based on this library. If you modify this + * library, you may extend this exception to your version of the + * library, but you are not obliged to do so. If you do not wish to do + * so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.prismlauncher.launcher.impl.legacy; + +import java.applet.Applet; +import java.awt.Dimension; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.io.File; +import java.io.IOException; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; +import java.util.List; + +import javax.imageio.ImageIO; +import javax.swing.JFrame; + +import org.prismlauncher.utils.logging.Log; + +import net.minecraft.Launcher; + +public final class LegacyFrame extends JFrame { + + private static final long serialVersionUID = 1L; + + private final Launcher launcher; + + public LegacyFrame(String title, Applet applet) { + super(title); + + launcher = new Launcher(applet); + + applet.setStub(launcher); + + try { + setIconImage(ImageIO.read(new File("icon.png"))); + } catch (IOException e) { + Log.error("Failed to read window icon", e); + } + + addWindowListener(new ForceExitHandler()); + } + + public void start(String user, String session, int width, int height, boolean maximize, String serverAddress, + String serverPort, boolean demo) { + // Implements support for launching in to multiplayer on classic servers using a + // mpticket file generated by an external program and stored in the instance's + // root folder. + Path instanceFolder = Paths.get(".."); + Path mpticket = instanceFolder.resolve("mpticket"); + Path mpticketCorrupt = instanceFolder.resolve("mpticket.corrupt"); + + if (Files.exists(mpticket)) { + try { + List lines = Files.readAllLines(mpticket, StandardCharsets.UTF_8); + + if (lines.size() < 3) { + Files.move(mpticket, mpticketCorrupt, StandardCopyOption.REPLACE_EXISTING); + + Log.warning("mpticket file is corrupted"); + } else { + // Assumes parameters are valid and in the correct order + launcher.setParameter("server", lines.get(0)); + launcher.setParameter("port", lines.get(1)); + launcher.setParameter("mppass", lines.get(2)); + } + } catch (IOException e) { + Log.error("Failed to read mpticket file", e); + } + } + + if (serverAddress != null) { + launcher.setParameter("server", serverAddress); + launcher.setParameter("port", serverPort); + } + + launcher.setParameter("username", user); + launcher.setParameter("sessionid", session); + launcher.setParameter("stand-alone", true); // Show the quit button. TODO: why won't this work? + launcher.setParameter("haspaid", true); // Some old versions need this for world saves to work. + launcher.setParameter("demo", demo); + launcher.setParameter("fullscreen", false); + + add(launcher); + + launcher.setPreferredSize(new Dimension(width, height)); + + pack(); + + setLocationRelativeTo(null); + setResizable(true); + + if (maximize) + setExtendedState(MAXIMIZED_BOTH); + + validate(); + + launcher.init(); + launcher.start(); + + setVisible(true); + } + + private final class ForceExitHandler extends WindowAdapter { + + @Override + public void windowClosing(WindowEvent event) { + // FIXME better solution + + new Thread(new Runnable() { + @Override + public void run() { + try { + Thread.sleep(30000L); + } catch (InterruptedException e) { + Log.error("Thread interrupted", e); + } + + Log.warning("Forcing exit"); + System.exit(0); + } + }).start(); + + if (launcher != null) { + launcher.stop(); + launcher.destroy(); + } + + // old minecraft versions can hang without this >_< + System.exit(0); + } + + } + +} diff --git a/libraries/launcher/org/prismlauncher/launcher/impl/legacy/LegacyLauncher.java b/libraries/launcher/org/prismlauncher/launcher/impl/legacy/LegacyLauncher.java new file mode 100644 index 00000000..d349177b --- /dev/null +++ b/libraries/launcher/org/prismlauncher/launcher/impl/legacy/LegacyLauncher.java @@ -0,0 +1,126 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 icelimetea + * Copyright (C) 2022 flow + * Copyright (C) 2022 TheKodeToad + * Copyright (C) 2022 solonovamax + * + * 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. + * + * Linking this library statically or dynamically with other modules is + * making a combined work based on this library. Thus, the terms and + * conditions of the GNU General Public License cover the whole + * combination. + * + * As a special exception, the copyright holders of this library give + * you permission to link this library with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. An independent module is a module which is + * not derived from or based on this library. If you modify this + * library, you may extend this exception to your version of the + * library, but you are not obliged to do so. If you do not wish to do + * so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.prismlauncher.launcher.impl.legacy; + +import java.io.File; +import java.lang.invoke.MethodHandle; +import java.lang.reflect.Field; +import java.util.Collections; +import java.util.List; + +import org.prismlauncher.launcher.impl.AbstractLauncher; +import org.prismlauncher.utils.Parameters; +import org.prismlauncher.utils.ReflectionUtils; +import org.prismlauncher.utils.logging.Log; + +/** + * Used to launch old versions that support applets. + */ +public final class LegacyLauncher extends AbstractLauncher { + + private final String user, session; + private final String title; + private final String appletClass; + private final boolean useApplet; + private final String gameDir; + + public LegacyLauncher(Parameters params) { + super(params); + + user = params.getString("userName"); + session = params.getString("sessionId"); + title = params.getString("windowTitle", "Minecraft"); + appletClass = params.getString("appletClass", "net.minecraft.client.MinecraftApplet"); + + List traits = params.getList("traits", Collections.emptyList()); + useApplet = !traits.contains("noapplet"); + + gameDir = System.getProperty("user.dir"); + } + + @Override + public void launch() throws Throwable { + Class main = ClassLoader.getSystemClassLoader().loadClass(mainClassName); + Field gameDirField = ReflectionUtils.findMinecraftGameDirField(main); + + if (gameDirField == null) + Log.warning("Could not find Minecraft folder field"); + else { + gameDirField.setAccessible(true); + gameDirField.set(null, new File(gameDir)); + } + + if (useApplet) { + System.setProperty("minecraft.applet.TargetDirectory", gameDir); + + try { + LegacyFrame window = new LegacyFrame(title, ReflectionUtils.createAppletClass(appletClass)); + + window.start(user, session, width, height, maximize, serverAddress, serverPort, + gameArgs.contains("--demo")); + return; + } catch (Throwable e) { + Log.error("Running applet wrapper failed with exception; falling back to main class", e); + } + } + + // find and invoke the main method, this time without size parameters + // in all versions that support applets, these are ignored + MethodHandle method = ReflectionUtils.findMainMethod(main); + method.invokeExact(gameArgs.toArray(new String[0])); + } + +} diff --git a/libraries/launcher/org/prismlauncher/utils/Parameters.java b/libraries/launcher/org/prismlauncher/utils/Parameters.java index 98a40c28..6365753e 100644 --- a/libraries/launcher/org/prismlauncher/utils/Parameters.java +++ b/libraries/launcher/org/prismlauncher/utils/Parameters.java @@ -1,46 +1,84 @@ +// SPDX-License-Identifier: GPL-3.0-only /* - * Copyright 2012-2021 MultiMC Contributors + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 icelimetea + * Copyright (C) 2022 TheKodeToad + * Copyright (C) 2022 solonovamax * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at + * 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. * - * http://www.apache.org/licenses/LICENSE-2.0 + * 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. * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. + * Linking this library statically or dynamically with other modules is + * making a combined work based on this library. Thus, the terms and + * conditions of the GNU General Public License cover the whole + * combination. + * + * As a special exception, the copyright holders of this library give + * you permission to link this library with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. An independent module is a module which is + * not derived from or based on this library. If you modify this + * library, you may extend this exception to your version of the + * library, but you are not obliged to do so. If you do not wish to do + * so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. */ package org.prismlauncher.utils; -import org.prismlauncher.exception.ParameterNotFoundException; - import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; +import org.prismlauncher.exception.ParameterNotFoundException; + public final class Parameters { - private final Map> paramsMap = new HashMap<>(); + private final Map> map = new HashMap<>(); public void add(String key, String value) { - List params = paramsMap.get(key); + List params = map.get(key); if (params == null) { params = new ArrayList<>(); - paramsMap.put(key, params); + map.put(key, params); } params.add(value); } - public List all(String key) throws ParameterNotFoundException { - List params = paramsMap.get(key); + public List getList(String key) throws ParameterNotFoundException { + List params = map.get(key); if (params == null) throw new ParameterNotFoundException(key); @@ -48,8 +86,8 @@ public final class Parameters { return params; } - public List allSafe(String key, List def) { - List params = paramsMap.get(key); + public List getList(String key, List def) { + List params = map.get(key); if (params == null || params.isEmpty()) return def; @@ -57,8 +95,8 @@ public final class Parameters { return params; } - public String first(String key) throws ParameterNotFoundException { - List list = all(key); + public String getString(String key) throws ParameterNotFoundException { + List list = getList(key); if (list.isEmpty()) throw new ParameterNotFoundException(key); @@ -66,8 +104,8 @@ public final class Parameters { return list.get(0); } - public String firstSafe(String key, String def) { - List params = paramsMap.get(key); + public String getString(String key, String def) { + List params = map.get(key); if (params == null || params.isEmpty()) return def; diff --git a/libraries/launcher/org/prismlauncher/utils/ReflectionUtils.java b/libraries/launcher/org/prismlauncher/utils/ReflectionUtils.java new file mode 100644 index 00000000..dd212ef9 --- /dev/null +++ b/libraries/launcher/org/prismlauncher/utils/ReflectionUtils.java @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 icelimetea + * Copyright (C) 2022 solonovamax + * Copyright (C) 2022 TheKodeToad + * + * 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. + * + * Linking this library statically or dynamically with other modules is + * making a combined work based on this library. Thus, the terms and + * conditions of the GNU General Public License cover the whole + * combination. + * + * As a special exception, the copyright holders of this library give + * you permission to link this library with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. An independent module is a module which is + * not derived from or based on this library. If you modify this + * library, you may extend this exception to your version of the + * library, but you are not obliged to do so. If you do not wish to do + * so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * This file incorporates work covered by the following copyright and + * permission notice: + * + * Copyright 2013-2021 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.prismlauncher.utils; + +import java.applet.Applet; +import java.io.File; +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodHandles; +import java.lang.invoke.MethodType; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; + +import org.prismlauncher.utils.logging.Log; + +public final class ReflectionUtils { + + private static final MethodHandles.Lookup LOOKUP = MethodHandles.lookup(); + private static final ClassLoader LOADER = ClassLoader.getSystemClassLoader(); + + /** + * Construct a Java applet by its class name. + * + * @param clazz The class name + * @return The applet instance + * @throws Throwable + */ + public static Applet createAppletClass(String clazz) throws Throwable { + Class appletClass = LOADER.loadClass(clazz); + + MethodHandle appletConstructor = LOOKUP.findConstructor(appletClass, MethodType.methodType(void.class)); + return (Applet) appletConstructor.invoke(); + } + + /** + * Best guess of the game directory field within net.minecraft.client.Minecraft. + * Designed for legacy versions - newer versions do not use a static field. + * + * @param clazz The class + * @return The first field matching criteria + */ + public static Field findMinecraftGameDirField(Class clazz) { + Log.debug("Resolving minecraft game directory field"); + + // search for private static File + for (Field field : clazz.getDeclaredFields()) { + if (field.getType() != File.class) { + continue; + } + + int fieldModifiers = field.getModifiers(); + + if (!Modifier.isStatic(fieldModifiers)) { + Log.debug("Rejecting field " + field.getName() + " because it is not static"); + continue; + } + + if (!Modifier.isPrivate(fieldModifiers)) { + Log.debug("Rejecting field " + field.getName() + " because it is not private"); + continue; + } + + if (Modifier.isFinal(fieldModifiers)) { + Log.debug("Rejecting field " + field.getName() + " because it is final"); + continue; + } + + Log.debug("Identified field " + field.getName() + " to match conditions for game directory field"); + + return field; + } + + return null; + } + + /** + * Gets the main method within a class. + * + * @param clazz The class + * @return A method matching the descriptor of a main method + * @throws ClassNotFoundException + * @throws NoSuchMethodException + * @throws IllegalAccessException + */ + public static MethodHandle findMainMethod(Class clazz) throws NoSuchMethodException, IllegalAccessException { + return LOOKUP.findStatic(clazz, "main", MethodType.methodType(void.class, String[].class)); + } + + /** + * Gets the main method within a class by its name. + * + * @param clazz The class name + * @return A method matching the descriptor of a main method + * @throws ClassNotFoundException + * @throws NoSuchMethodException + * @throws IllegalAccessException + */ + public static MethodHandle findMainMethod(String clazz) + throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException { + return findMainMethod(LOADER.loadClass(clazz)); + } + +} diff --git a/libraries/launcher/org/prismlauncher/utils/Utils.java b/libraries/launcher/org/prismlauncher/utils/Utils.java deleted file mode 100644 index ae9a4de2..00000000 --- a/libraries/launcher/org/prismlauncher/utils/Utils.java +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2012-2021 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.prismlauncher.utils; - -import java.io.File; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; - -public final class Utils { - - private Utils() {} - - /** - * Finds a field that looks like a Minecraft base folder in a supplied class - * - * @param clazz the class to scan - */ - public static Field getMinecraftBaseDirField(Class clazz) { - for (Field f : clazz.getDeclaredFields()) { - // Has to be File - if (f.getType() != File.class) - continue; - - // And Private Static. - if (!Modifier.isStatic(f.getModifiers()) || !Modifier.isPrivate(f.getModifiers())) - continue; - - return f; - } - - return null; - } - -} - diff --git a/libraries/launcher/org/prismlauncher/LauncherFactory.java b/libraries/launcher/org/prismlauncher/utils/logging/Level.java similarity index 56% rename from libraries/launcher/org/prismlauncher/LauncherFactory.java rename to libraries/launcher/org/prismlauncher/utils/logging/Level.java index 98f2bbba..552b0b55 100644 --- a/libraries/launcher/org/prismlauncher/LauncherFactory.java +++ b/libraries/launcher/org/prismlauncher/utils/logging/Level.java @@ -1,7 +1,7 @@ // SPDX-License-Identifier: GPL-3.0-only /* - * PolyMC - Minecraft Launcher - * Copyright (C) 2022 icelimetea, + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 TheKodeToad * * 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 @@ -33,48 +33,27 @@ * along with this program. If not, see . */ -package org.prismlauncher; +package org.prismlauncher.utils.logging; -import org.prismlauncher.impl.OneSixLauncher; -import org.prismlauncher.utils.Parameters; +public enum Level { + LAUNCHER("Launcher"), + DEBUG("Debug"), + INFO("Info"), + MESSAGE("Message"), + WARNING("Warning"), + ERROR("Error", true), + FATAL("Fatal", true); -import java.util.HashMap; -import java.util.Map; + String name; + boolean stderr; -public final class LauncherFactory { - - private static final LauncherFactory INSTANCE = new LauncherFactory(); - - private final Map launcherRegistry = new HashMap<>(); - - private LauncherFactory() { - launcherRegistry.put("onesix", new LauncherProvider() { - @Override - public Launcher provide(Parameters parameters) { - return new OneSixLauncher(parameters); - } - }); + Level(String name) { + this(name, false); } - public Launcher createLauncher(Parameters parameters) { - String name = parameters.first("launcher"); - - LauncherProvider launcherProvider = launcherRegistry.get(name); - - if (launcherProvider == null) - throw new IllegalArgumentException("Invalid launcher type: " + name); - - return launcherProvider.provide(parameters); - } - - public static LauncherFactory getInstance() { - return INSTANCE; - } - - public interface LauncherProvider { - - Launcher provide(Parameters parameters); - + Level(String name, boolean stderr) { + this.name = name; + this.stderr = stderr; } } diff --git a/libraries/launcher/org/prismlauncher/utils/logging/Log.java b/libraries/launcher/org/prismlauncher/utils/logging/Log.java new file mode 100644 index 00000000..e3aa538b --- /dev/null +++ b/libraries/launcher/org/prismlauncher/utils/logging/Log.java @@ -0,0 +1,104 @@ +// SPDX-License-Identifier: GPL-3.0-only +/* + * Prism Launcher - Minecraft Launcher + * Copyright (C) 2022 TheKodeToad + * + * 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. + * + * Linking this library statically or dynamically with other modules is + * making a combined work based on this library. Thus, the terms and + * conditions of the GNU General Public License cover the whole + * combination. + * + * As a special exception, the copyright holders of this library give + * you permission to link this library with independent modules to + * produce an executable, regardless of the license terms of these + * independent modules, and to copy and distribute the resulting + * executable under terms of your choice, provided that you also meet, + * for each linked independent module, the terms and conditions of the + * license of that module. An independent module is a module which is + * not derived from or based on this library. If you modify this + * library, you may extend this exception to your version of the + * library, but you are not obliged to do so. If you do not wish to do + * so, delete this exception statement from your version. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +package org.prismlauncher.utils.logging; + +import java.io.PrintStream; + +/** + * Used to print messages with different levels used to colourise the output. + * Used instead of a logging framework, as the launcher knows how to parse these + * messages. + */ +public final class Log { + + // original before possibly overridden by MC + private static final PrintStream OUT = new PrintStream(System.out), ERR = new PrintStream(System.err); + private static final boolean DEBUG = Boolean.getBoolean("org.prismlauncher.debug"); + + public static void launcher(String message) { + log(message, Level.LAUNCHER); + } + + public static void error(String message) { + log(message, Level.ERROR); + } + + public static void debug(String message) { + log(message, Level.DEBUG); + } + + public static void warning(String message) { + log(message, Level.WARNING); + } + + public static void error(String message, Throwable e) { + error(message); + e.printStackTrace(ERR); + } + + public static void fatal(String message) { + log(message, Level.FATAL); + } + + public static void fatal(String message, Throwable e) { + fatal(message); + e.printStackTrace(ERR); + } + + /** + * Logs a message with the prefix !![LEVEL]!. This is picked up by + * the log viewer to give it nice colours. + * + * @param message The message + * @param level The level + */ + public static void log(String message, Level level) { + if (!DEBUG && level == Level.DEBUG) + return; + + String prefix = "!![" + level.name + "]!"; + // prefix first line + message = prefix + message; + // prefix subsequent lines + message = message.replace("\n", "\n" + prefix); + + if (level.stderr) + ERR.println(message); + else + OUT.println(message); + } + +} diff --git a/tests/FileSystem_test.cpp b/tests/FileSystem_test.cpp index 21270f6f..3a5c38d0 100644 --- a/tests/FileSystem_test.cpp +++ b/tests/FileSystem_test.cpp @@ -126,7 +126,7 @@ slots: qDebug() << tempDir.path(); qDebug() << target_dir.path(); FS::copy c(folder, target_dir.path()); - c.blacklist(new RegexpMatcher("[.]?mcmeta")); + c.matcher(new RegexpMatcher("[.]?mcmeta")); c(); for(auto entry: target_dir.entryList()) @@ -147,6 +147,41 @@ slots: f(); } + void test_copy_with_whitelist() + { + QString folder = QFINDTESTDATA("testdata/FileSystem/test_folder"); + auto f = [&folder]() + { + QTemporaryDir tempDir; + tempDir.setAutoRemove(true); + qDebug() << "From:" << folder << "To:" << tempDir.path(); + + QDir target_dir(FS::PathCombine(tempDir.path(), "test_folder")); + qDebug() << tempDir.path(); + qDebug() << target_dir.path(); + FS::copy c(folder, target_dir.path()); + c.matcher(new RegexpMatcher("[.]?mcmeta")); + c.whitelist(true); + c(); + + for(auto entry: target_dir.entryList()) + { + qDebug() << entry; + } + QVERIFY(target_dir.entryList().contains("pack.mcmeta")); + QVERIFY(!target_dir.entryList().contains("assets")); + }; + + // first try variant without trailing / + QVERIFY(!folder.endsWith('/')); + f(); + + // then variant with trailing / + folder.append('/'); + QVERIFY(folder.endsWith('/')); + f(); + } + void test_copy_with_dot_hidden() { QString folder = QFINDTESTDATA("testdata/FileSystem/test_folder");