diff options
58 files changed, 2630 insertions, 31 deletions
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 00000000..d7eeaf1d --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,107 @@ +name: build_portable + +on: + [push, pull_request, workflow_dispatch] + +jobs: + build: + strategy: + fail-fast: false + matrix: + include: + + - os: ubuntu-20.04 + qt_version: 5.12.8 + qt_host: linux + + - os: windows-2022 + qt_version: 5.15.2 + qt_host: windows + qt_arch: win64_mingw81 + + - os: macos-11 + qt_version: 5.12.12 + qt_host: mac + macosx_deployment_target: 10.12 + + runs-on: ${{ matrix.os }} + + env: + MACOSX_DEPLOYMENT_TARGET: ${{matrix.macosx_deployment_target}} + + steps: + + - name: Checkout + uses: actions/checkout@v2 + with: + submodules: 'true' + + - name: Install OpenJDK + uses: AdoptOpenJDK/install-jdk@v1 + with: + version: '17' + + - name: Cache Qt + id: cache-qt + uses: actions/cache@v2 + with: + path: "${{ github.workspace }}/Qt/" + key: ${{ runner.os }}-${{ matrix.qt_version }}-qt_cache + + - name: Install Qt + uses: jurplel/install-qt-action@v2 + with: + version: ${{ matrix.qt_version }} + host: ${{ matrix.qt_host }} + arch: ${{ matrix.qt_arch }} + cached: ${{ steps.cache-qt.outputs.cache-hit }} + dir: "${{ github.workspace }}/Qt/" + + - name: Install Ninja + uses: urkle/action-get-ninja@v1 + + - name: Configure CMake + run: | + cmake -S . -B build -DCMAKE_INSTALL_PREFIX=install -DCMAKE_BUILD_TYPE=Debug -G Ninja + + - name: Build + run: | + cmake --build build + + - name: Install + run: | + cmake --install build + + - name: Install OpenSSL libs + if: runner.os == 'Windows' + run: | + python -m pip install --upgrade pip + python -m pip install aqtinstall==2.0.5 + python -m aqt install-tool -O "${{ github.workspace }}\Qt\" windows desktop tools_openssl_x64 + copy "${{ github.workspace }}\Qt\Tools\OpenSSL\Win_x64\bin\libssl-1_1-x64.dll" "${{ github.workspace }}\install\" + copy "${{ github.workspace }}\Qt\Tools\OpenSSL\Win_x64\bin\libcrypto-1_1-x64.dll" "${{ github.workspace }}\install\" + + - name: chmod binary on macOS + if: runner.os == 'macOS' + run: | + chmod +x "${{ github.workspace }}/install/PolyMC.app/Contents/MacOS/polymc" + + - name: tar bundle on macOS + if: runner.os == 'macOS' + run: | + cd install + tar -czf ../polymc.tar.gz * + + - name: Upload package for Linux and Windows + if: runner.os != 'macOS' + uses: actions/upload-artifact@v2 + with: + name: polymc-${{ matrix.os }}-portable + path: install/** + + - name: Upload package for macOS + if: runner.os == 'macOS' + uses: actions/upload-artifact@v2 + with: + name: polymc-${{ matrix.os }}-portable + path: polymc.tar.gz @@ -25,7 +25,6 @@ The rest of the documentation assumes you have already cloned the repository. Getting the project to build and run on Linux is easy if you use any modern and up-to-date linux distribution. ## Build dependencies - - A C++ compiler capable of building C++11 code. - Qt Development tools 5.6 or newer (`qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5core5a libqt5network5 libqt5gui5` on Debian-based system) - cmake 3.1 or newer (`cmake` on Debian-based system) @@ -116,7 +115,7 @@ The path to the rpm packages will be printed when the build is complete. ### Building a flatpak -You only need to clone the flatpak sources +You only need to clone the flatpak sources `flatpak` and `flatpak-builder` need to be installed on your system ```sh @@ -26,6 +26,7 @@ This is a **fork** of the MultiMC Launcher and not endorsed by MultiMC. The Poly ### <img src="https://www.vectorlogo.zone/logos/archlinux/archlinux-icon.svg" height="20"/> Arch Linux There are several AUR packages available: + [](https://aur.archlinux.org/packages/polymc/) [](https://aur.archlinux.org/packages/polymc-bin/) [](https://aur.archlinux.org/packages/polymc-git/) @@ -68,7 +69,7 @@ A Gentoo ebuild is available in the [swirl](https://git.swurl.xyz/swirl/ebuilds) ```sh # as root: emerge --oneshot eselect-repository -eselect-repository enable swirl +eselect repository enable swirl emaint sync -r swirl emerge polymc # to use latest git version: @@ -125,7 +126,6 @@ If you want to contribute to PolyMC you might find it useful to join our Discord If you want to build PolyMC yourself, check [BUILD.md](BUILD.md) for build instructions. ## Code formatting - Just follow the existing formatting. In general, in order of importance: diff --git a/launcher/Application.cpp b/launcher/Application.cpp index b605e54b..7050e5dc 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -717,6 +717,8 @@ Application::Application(int &argc, char **argv) : QApplication(argc, argv) // pastebin URL m_settings->registerSetting("PastebinURL", "https://0x0.st"); + m_settings->registerSetting("CloseAfterLaunch", false); + // Init page provider { m_globalSettingsProvider = std::make_shared<GenericPageProvider>(tr("Settings")); diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index c704563b..f4c3a9bc 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -37,6 +37,10 @@ set(CORE_SOURCES InstanceImportTask.h InstanceImportTask.cpp + # Mod downloading task + ModDownloadTask.h + ModDownloadTask.cpp + # Use tracking separate from memory management Usable.h @@ -212,7 +216,11 @@ set(MINECRAFT_SOURCES minecraft/auth/flows/Mojang.h minecraft/auth/flows/MSA.cpp minecraft/auth/flows/MSA.h + minecraft/auth/flows/Offline.cpp + minecraft/auth/flows/Offline.h + minecraft/auth/steps/OfflineStep.cpp + minecraft/auth/steps/OfflineStep.h minecraft/auth/steps/EntitlementsStep.cpp minecraft/auth/steps/EntitlementsStep.h minecraft/auth/steps/GetSkinStep.cpp @@ -497,12 +505,19 @@ set(FLAME_SOURCES # Flame modplatform/flame/FlamePackIndex.cpp modplatform/flame/FlamePackIndex.h + modplatform/flame/FlameModIndex.cpp + modplatform/flame/FlameModIndex.h modplatform/flame/PackManifest.h modplatform/flame/PackManifest.cpp modplatform/flame/FileResolvingTask.h modplatform/flame/FileResolvingTask.cpp ) +set(MODRINTH_SOURCES + modplatform/modrinth/ModrinthPackIndex.cpp + modplatform/modrinth/ModrinthPackIndex.h +) + set(MODPACKSCH_SOURCES modplatform/modpacksch/FTBPackInstallTask.h modplatform/modpacksch/FTBPackInstallTask.cpp @@ -557,6 +572,7 @@ set(LOGIC_SOURCES ${ICONS_SOURCES} ${FTB_SOURCES} ${FLAME_SOURCES} + ${MODRINTH_SOURCES} ${MODPACKSCH_SOURCES} ${TECHNIC_SOURCES} ${ATLAUNCHER_SOURCES} @@ -730,6 +746,10 @@ SET(LAUNCHER_SOURCES ui/pages/modplatform/flame/FlameModel.h ui/pages/modplatform/flame/FlamePage.cpp ui/pages/modplatform/flame/FlamePage.h + ui/pages/modplatform/flame/FlameModModel.cpp + ui/pages/modplatform/flame/FlameModModel.h + ui/pages/modplatform/flame/FlameModPage.cpp + ui/pages/modplatform/flame/FlameModPage.h ui/pages/modplatform/technic/TechnicModel.cpp ui/pages/modplatform/technic/TechnicModel.h @@ -739,6 +759,11 @@ SET(LAUNCHER_SOURCES ui/pages/modplatform/ImportPage.cpp ui/pages/modplatform/ImportPage.h + ui/pages/modplatform/modrinth/ModrinthModel.cpp + ui/pages/modplatform/modrinth/ModrinthModel.h + ui/pages/modplatform/modrinth/ModrinthPage.cpp + ui/pages/modplatform/modrinth/ModrinthPage.h + # GUI - dialogs ui/dialogs/AboutDialog.cpp ui/dialogs/AboutDialog.h @@ -760,6 +785,8 @@ SET(LAUNCHER_SOURCES ui/dialogs/LoginDialog.h ui/dialogs/MSALoginDialog.cpp ui/dialogs/MSALoginDialog.h + ui/dialogs/OfflineLoginDialog.cpp + ui/dialogs/OfflineLoginDialog.h ui/dialogs/NewComponentDialog.cpp ui/dialogs/NewComponentDialog.h ui/dialogs/NewInstanceDialog.cpp @@ -776,6 +803,8 @@ SET(LAUNCHER_SOURCES ui/dialogs/VersionSelectDialog.h ui/dialogs/SkinUploadDialog.cpp ui/dialogs/SkinUploadDialog.h + ui/dialogs/ModDownloadDialog.cpp + ui/dialogs/ModDownloadDialog.h # GUI - widgets @@ -852,10 +881,12 @@ qt5_wrap_ui(LAUNCHER_UI ui/pages/modplatform/atlauncher/AtlPage.ui ui/pages/modplatform/VanillaPage.ui ui/pages/modplatform/flame/FlamePage.ui + ui/pages/modplatform/flame/FlameModPage.ui ui/pages/modplatform/legacy_ftb/Page.ui ui/pages/modplatform/ImportPage.ui ui/pages/modplatform/ftb/FtbPage.ui ui/pages/modplatform/technic/TechnicPage.ui + ui/pages/modplatform/modrinth/ModrinthPage.ui ui/widgets/InstanceCardWidget.ui ui/widgets/CustomCommands.ui ui/widgets/MCModInfoFrame.ui @@ -871,6 +902,7 @@ qt5_wrap_ui(LAUNCHER_UI ui/dialogs/ExportInstanceDialog.ui ui/dialogs/IconPickerDialog.ui ui/dialogs/MSALoginDialog.ui + ui/dialogs/OfflineLoginDialog.ui ui/dialogs/AboutDialog.ui ui/dialogs/LoginDialog.ui ui/dialogs/EditAccountDialog.ui diff --git a/launcher/LaunchController.cpp b/launcher/LaunchController.cpp index 7750be1a..32fc99cb 100644 --- a/launcher/LaunchController.cpp +++ b/launcher/LaunchController.cpp @@ -116,6 +116,12 @@ void LaunchController::login() { m_session->wants_online = m_online; m_accountToUse->fillSession(m_session); + // Launch immediately in true offline mode + if(m_accountToUse->isOffline()) { + launchInstance(); + return; + } + switch(m_accountToUse->accountState()) { case AccountState::Offline: { m_session->wants_online = false; diff --git a/launcher/ModDownloadTask.cpp b/launcher/ModDownloadTask.cpp new file mode 100644 index 00000000..08a02d29 --- /dev/null +++ b/launcher/ModDownloadTask.cpp @@ -0,0 +1,39 @@ +#include "ModDownloadTask.h" +#include "Application.h" + +ModDownloadTask::ModDownloadTask(const QUrl sourceUrl,const QString filename, const std::shared_ptr<ModFolderModel> mods) +: m_sourceUrl(sourceUrl), mods(mods), filename(filename) { +} + +void ModDownloadTask::executeTask() { + setStatus(tr("Downloading mod:\n%1").arg(m_sourceUrl.toString())); + + m_filesNetJob.reset(new NetJob(tr("Mod download"), APPLICATION->network())); + m_filesNetJob->addNetAction(Net::Download::makeFile(m_sourceUrl, mods->dir().absoluteFilePath(filename))); + connect(m_filesNetJob.get(), &NetJob::succeeded, this, &ModDownloadTask::downloadSucceeded); + connect(m_filesNetJob.get(), &NetJob::progress, this, &ModDownloadTask::downloadProgressChanged); + connect(m_filesNetJob.get(), &NetJob::failed, this, &ModDownloadTask::downloadFailed); + m_filesNetJob->start(); +} + +void ModDownloadTask::downloadSucceeded() +{ + emitSucceeded(); + m_filesNetJob.reset(); +} + +void ModDownloadTask::downloadFailed(QString reason) +{ + emitFailed(reason); + m_filesNetJob.reset(); +} + +void ModDownloadTask::downloadProgressChanged(qint64 current, qint64 total) +{ + emit progress(current, total); +} + +bool ModDownloadTask::abort() { + return m_filesNetJob->abort(); +} + diff --git a/launcher/ModDownloadTask.h b/launcher/ModDownloadTask.h new file mode 100644 index 00000000..7e4f1b7d --- /dev/null +++ b/launcher/ModDownloadTask.h @@ -0,0 +1,34 @@ +#pragma once +#include "QObjectPtr.h" +#include "tasks/Task.h" +#include "minecraft/mod/ModFolderModel.h" +#include "net/NetJob.h" +#include <QUrl> + + +class ModDownloadTask : public Task { + Q_OBJECT +public: + explicit ModDownloadTask(const QUrl sourceUrl, const QString filename, const std::shared_ptr<ModFolderModel> mods); + +public slots: + bool abort() override; +protected: + //! Entry point for tasks. + void executeTask() override; + +private: + QUrl m_sourceUrl; + NetJob::Ptr m_filesNetJob; + const std::shared_ptr<ModFolderModel> mods; + const QString filename; + + void downloadProgressChanged(qint64 current, qint64 total); + + void downloadFailed(QString reason); + + void downloadSucceeded(); +}; + + + diff --git a/launcher/minecraft/auth/AccountData.cpp b/launcher/minecraft/auth/AccountData.cpp index 7526c951..9b84fe1a 100644 --- a/launcher/minecraft/auth/AccountData.cpp +++ b/launcher/minecraft/auth/AccountData.cpp @@ -314,6 +314,8 @@ bool AccountData::resumeStateFromV3(QJsonObject data) { type = AccountType::MSA; } else if (typeS == "Mojang") { type = AccountType::Mojang; + } else if (typeS == "Offline") { + type = AccountType::Offline; } else { qWarning() << "Failed to parse account data: type is not recognized."; return false; @@ -363,6 +365,9 @@ QJsonObject AccountData::saveState() const { tokenToJSONV3(output, xboxApiToken, "xrp-main"); tokenToJSONV3(output, mojangservicesToken, "xrp-mc"); } + else if (type == AccountType::Offline) { + output["type"] = "Offline"; + } tokenToJSONV3(output, yggdrasilToken, "ygg"); profileToJSONV3(output, minecraftProfile, "profile"); @@ -371,7 +376,7 @@ QJsonObject AccountData::saveState() const { } QString AccountData::userName() const { - if(type != AccountType::Mojang) { + if(type == AccountType::MSA) { return QString(); } return yggdrasilToken.extra["userName"].toString(); @@ -427,6 +432,9 @@ QString AccountData::accountDisplayString() const { case AccountType::Mojang: { return userName(); } + case AccountType::Offline: { + return userName(); + } case AccountType::MSA: { if(xboxApiToken.extra.contains("gtg")) { return xboxApiToken.extra["gtg"].toString(); diff --git a/launcher/minecraft/auth/AccountData.h b/launcher/minecraft/auth/AccountData.h index abf84e43..606c1ad1 100644 --- a/launcher/minecraft/auth/AccountData.h +++ b/launcher/minecraft/auth/AccountData.h @@ -38,7 +38,8 @@ struct MinecraftProfile { enum class AccountType { MSA, - Mojang + Mojang, + Offline }; enum class AccountState { diff --git a/launcher/minecraft/auth/AccountList.cpp b/launcher/minecraft/auth/AccountList.cpp index ef8b435d..04470e1c 100644 --- a/launcher/minecraft/auth/AccountList.cpp +++ b/launcher/minecraft/auth/AccountList.cpp @@ -302,7 +302,7 @@ QVariant AccountList::data(const QModelIndex &index, int role) const } case MigrationColumn: { - if(account->isMSA()) { + if(account->isMSA() || account->isOffline()) { return tr("N/A", "Can Migrate?"); } if (account->canMigrate()) { diff --git a/launcher/minecraft/auth/MinecraftAccount.cpp b/launcher/minecraft/auth/MinecraftAccount.cpp index ed9e945e..ffc81ed8 100644 --- a/launcher/minecraft/auth/MinecraftAccount.cpp +++ b/launcher/minecraft/auth/MinecraftAccount.cpp @@ -30,6 +30,7 @@ #include "flows/MSA.h" #include "flows/Mojang.h" +#include "flows/Offline.h" MinecraftAccount::MinecraftAccount(QObject* parent) : QObject(parent) { data.internalId = QUuid::createUuid().toString().remove(QRegExp("[{}-]")); @@ -68,6 +69,23 @@ MinecraftAccountPtr MinecraftAccount::createBlankMSA() return account; } +MinecraftAccountPtr MinecraftAccount::createOffline(const QString &username) +{ + MinecraftAccountPtr account = new MinecraftAccount(); + account->data.type = AccountType::Offline; + account->data.yggdrasilToken.token = "offline"; + account->data.yggdrasilToken.validity = Katabasis::Validity::Certain; + account->data.yggdrasilToken.issueInstant = QDateTime::currentDateTimeUtc(); + account->data.yggdrasilToken.extra["userName"] = username; + account->data.yggdrasilToken.extra["clientToken"] = QUuid::createUuid().toString().remove(QRegExp("[{}-]")); + account->data.minecraftEntitlement.ownsMinecraft = true; + account->data.minecraftEntitlement.canPlayMinecraft = true; + account->data.minecraftProfile.id = QUuid::createUuid().toString().remove(QRegExp("[{}-]")); + account->data.minecraftProfile.name = username; + account->data.minecraftProfile.validity = Katabasis::Validity::Certain; + return account; +} + QJsonObject MinecraftAccount::saveToJson() const { @@ -111,6 +129,16 @@ shared_qobject_ptr<AccountTask> MinecraftAccount::loginMSA() { return m_currentTask; } +shared_qobject_ptr<AccountTask> MinecraftAccount::loginOffline() { + Q_ASSERT(m_currentTask.get() == nullptr); + + m_currentTask.reset(new OfflineLogin(&data)); + connect(m_currentTask.get(), SIGNAL(succeeded()), SLOT(authSucceeded())); + connect(m_currentTask.get(), SIGNAL(failed(QString)), SLOT(authFailed(QString))); + emit activityChanged(true); + return m_currentTask; +} + shared_qobject_ptr<AccountTask> MinecraftAccount::refresh() { if(m_currentTask) { return m_currentTask; @@ -119,6 +147,9 @@ shared_qobject_ptr<AccountTask> MinecraftAccount::refresh() { if(data.type == AccountType::MSA) { m_currentTask.reset(new MSASilent(&data)); } + else if(data.type == AccountType::Offline) { + m_currentTask.reset(new OfflineRefresh(&data)); + } else { m_currentTask.reset(new MojangRefresh(&data)); } diff --git a/launcher/minecraft/au |
