diff --git a/.envrc b/.envrc index 190b5b2b3..1d11c5354 100644 --- a/.envrc +++ b/.envrc @@ -1,2 +1,2 @@ -use flake +use nix watch_file nix/*.nix diff --git a/.github/actions/get-merge-commit/action.yml b/.github/actions/get-merge-commit/action.yml new file mode 100644 index 000000000..8c67fdfc9 --- /dev/null +++ b/.github/actions/get-merge-commit/action.yml @@ -0,0 +1,103 @@ +# This file incorporates work covered by the following copyright and +# permission notice +# +# Copyright (c) 2003-2025 Eelco Dolstra and the Nixpkgs/NixOS contributors +# +# Permission is hereby granted, free of charge, to any person obtaining +# a copy of this software and associated documentation files (the +# "Software"), to deal in the Software without restriction, including +# without limitation the rights to use, copy, modify, merge, publish, +# distribute, sublicense, and/or sell copies of the Software, and to +# permit persons to whom the Software is furnished to do so, subject to +# the following conditions: +# +# The above copyright notice and this permission notice shall be +# included in all copies or substantial portions of the Software. +# +# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 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. + +name: Get merge commit +description: Get a merge commit of a given pull request + +inputs: + repository: + description: Repository containing the pull request + required: false + pull-request-id: + description: ID of a pull request + required: true + +outputs: + merge-commit-sha: + description: Git SHA of a merge commit + value: ${{ steps.query.outputs.merge-commit-sha }} + +runs: + using: composite + + steps: + - name: Wait for GitHub to report merge commit + id: query + shell: bash + env: + GITHUB_REPO: ${{ inputs.repository || github.repository }} + PR_ID: ${{ inputs.pull-request-id }} + # https://github.com/NixOS/nixpkgs/blob/8f77f3600f1ee775b85dc2c72fd842768e486ec9/ci/get-merge-commit.sh + run: | + set -euo pipefail + + log() { + echo "$@" >&2 + } + + # Retry the API query this many times + retryCount=5 + # Start with 5 seconds, but double every retry + retryInterval=5 + + while true; do + log "Checking whether the pull request can be merged" + prInfo=$(gh api \ + -H "Accept: application/vnd.github+json" \ + -H "X-GitHub-Api-Version: 2022-11-28" \ + "/repos/$GITHUB_REPO/pulls/$PR_ID") + + # Non-open PRs won't have their mergeability computed no matter what + state=$(jq -r .state <<<"$prInfo") + if [[ "$state" != open ]]; then + log "PR is not open anymore" + exit 1 + fi + + mergeable=$(jq -r .mergeable <<<"$prInfo") + if [[ "$mergeable" == "null" ]]; then + if ((retryCount == 0)); then + log "Not retrying anymore. It's likely that GitHub is having internal issues: check https://www.githubstatus.com/" + exit 3 + else + ((retryCount -= 1)) || true + + # null indicates that GitHub is still computing whether it's mergeable + # Wait a couple seconds before trying again + log "GitHub is still computing whether this PR can be merged, waiting $retryInterval seconds before trying again ($retryCount retries left)" + sleep "$retryInterval" + + ((retryInterval *= 2)) || true + fi + else + break + fi + done + + if [[ "$mergeable" == "true" ]]; then + echo "merge-commit-sha=$(jq -r .merge_commit_sha <<<"$prInfo")" >> "$GITHUB_OUTPUT" + else + echo "# 🚨 The PR has a merge conflict!" >>> "$GITHUB_STEP_SUMMARY" + exit 2 + fi diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 11ef262ea..5d5cbc893 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -52,13 +52,6 @@ jobs: fail-fast: false matrix: include: - - os: ubuntu-22.04 - qt_ver: 5 - qt_host: linux - qt_arch: "" - qt_version: "5.15.2" - qt_modules: "qtnetworkauth" - - os: ubuntu-22.04 qt_ver: 6 qt_host: linux @@ -254,7 +247,7 @@ jobs: arch: ${{ matrix.vcvars_arch }} - name: Prepare AppImage (Linux) - if: runner.os == 'Linux' && matrix.qt_ver != 5 + if: runner.os == 'Linux' env: APPIMAGEUPDATE_HASH: ${{ matrix.appimageupdate_hash }} LINUXDEPLOY_HASH: ${{ matrix.linuxdeploy_hash }} @@ -287,7 +280,7 @@ jobs: ## - name: Configure CMake (macOS) - if: runner.os == 'macOS' && matrix.qt_ver == 6 + if: runner.os == 'macOS' run: | cmake -S . -B ${{ env.BUILD_DIR }} -DCMAKE_INSTALL_PREFIX=${{ env.INSTALL_DIR }} -DCMAKE_BUILD_TYPE=${{ inputs.build_type }} -DENABLE_LTO=ON -DLauncher_ENABLE_JAVA_DOWNLOADER=ON -DLauncher_BUILD_PLATFORM=official -DCMAKE_C_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DCMAKE_CXX_COMPILER_LAUNCHER=${{ env.CCACHE_VAR }} -DLauncher_QT_VERSION_MAJOR=${{ matrix.qt_ver }} -DCMAKE_OSX_ARCHITECTURES="x86_64;arm64" -G Ninja @@ -502,7 +495,7 @@ jobs: } - name: Package AppImage (Linux) - if: runner.os == 'Linux' && matrix.qt_ver != 5 + if: runner.os == 'Linux' shell: bash env: GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} @@ -598,29 +591,22 @@ jobs: name: PrismLauncher-${{ matrix.name }}-Setup-${{ env.VERSION }}-${{ inputs.build_type }} path: PrismLauncher-Setup.exe - - name: Upload binary tarball (Linux, portable, Qt 5) - if: runner.os == 'Linux' && matrix.qt_ver != 6 - uses: actions/upload-artifact@v4 - with: - name: PrismLauncher-${{ runner.os }}-Qt5-Portable-${{ env.VERSION }}-${{ inputs.build_type }} - path: PrismLauncher-portable.tar.gz - - - name: Upload binary tarball (Linux, portable, Qt 6) - if: runner.os == 'Linux' && matrix.qt_ver != 5 + - name: Upload binary tarball (Linux, portable) + if: runner.os == 'Linux' uses: actions/upload-artifact@v4 with: name: PrismLauncher-${{ runner.os }}-Qt6-Portable-${{ env.VERSION }}-${{ inputs.build_type }} path: PrismLauncher-portable.tar.gz - name: Upload AppImage (Linux) - if: runner.os == 'Linux' && matrix.qt_ver != 5 + if: runner.os == 'Linux' uses: actions/upload-artifact@v4 with: name: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage path: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage - name: Upload AppImage Zsync (Linux) - if: runner.os == 'Linux' && matrix.qt_ver != 5 + if: runner.os == 'Linux' uses: actions/upload-artifact@v4 with: name: PrismLauncher-${{ runner.os }}-${{ env.VERSION }}-${{ inputs.build_type }}-x86_64.AppImage.zsync diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index d1d810374..a5ac537f1 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -1,16 +1,49 @@ name: "CodeQL Code Scanning" -on: [ push, pull_request, workflow_dispatch ] +on: + push: + # NOTE: `!` doesn't work with `paths-ignore` :( + # So we a catch-all glob instead + # https://github.com/orgs/community/discussions/25369#discussioncomment-3247674 + paths: + - "**" + - "!.github/**" + - ".github/workflows/codeql.yml" + - "!flatpak/" + - "!nix/" + - "!scripts/" + + - "!.git*" + - "!.envrc" + - "!**.md" + - "COPYING.md" + - "!renovate.json" + pull_request: + # See above + paths: + - "**" + - "!.github/**" + - ".github/workflows/codeql.yml" + - "!flatpak/" + - "!nix/" + - "!scripts/" + + - "!.git*" + - "!.envrc" + - "!**.md" + - "COPYING.md" + - "!renovate.json" + workflow_dispatch: jobs: CodeQL: runs-on: ubuntu-latest - + steps: - name: Checkout repository uses: actions/checkout@v4 with: - submodules: 'true' + submodules: "true" - name: Initialize CodeQL uses: github/codeql-action/init@v3 @@ -20,14 +53,25 @@ jobs: languages: cpp, java - name: Install Dependencies - run: - sudo apt-get -y update + run: sudo apt-get -y update - sudo apt-get -y install ninja-build extra-cmake-modules scdoc qtbase5-dev qtchooser qt5-qmake qtbase5-dev-tools libqt5core5a libqt5network5 libqt5gui5 libqt5networkauth5 libqt5networkauth5-dev libqt5opengl5 libqt5opengl5-dev + sudo apt-get -y install ninja-build extra-cmake-modules scdoc + + - name: Install Qt + uses: jurplel/install-qt-action@v3 + with: + aqtversion: "==3.1.*" + py7zrversion: ">=0.20.2" + version: "6.8.1" + host: "linux" + target: "desktop" + arch: "" + modules: "qt5compat qtimageformats qtnetworkauth" + tools: "" - name: Configure and Build run: | - cmake -S . -B build -DCMAKE_INSTALL_PREFIX=/usr -DLauncher_QT_VERSION_MAJOR=5 -G Ninja + cmake -S . -B build -DCMAKE_INSTALL_PREFIX=/usr -G Ninja cmake --build build diff --git a/.github/workflows/flatpak.yml b/.github/workflows/flatpak.yml index 41cc2a51d..8caba46fa 100644 --- a/.github/workflows/flatpak.yml +++ b/.github/workflows/flatpak.yml @@ -2,22 +2,38 @@ name: Flatpak on: push: - paths-ignore: - - "**.md" - - "**/LICENSE" - - ".github/ISSUE_TEMPLATE/**" - - ".markdownlint**" - - "nix/**" # We don't do anything with these artifacts on releases. They go to Flathub tags-ignore: - "*" + # NOTE: `!` doesn't work with `paths-ignore` :( + # So we a catch-all glob instead + # https://github.com/orgs/community/discussions/25369#discussioncomment-3247674 + paths: + - "**" + - "!.github/**" + - ".github/workflows/flatpak.yml" + - "!nix/" + - "!scripts/" + + - "!.git*" + - "!.envrc" + - "!**.md" + - "COPYING.md" + - "!renovate.json" pull_request: - paths-ignore: - - "**.md" - - "**/LICENSE" - - ".github/ISSUE_TEMPLATE/**" - - ".markdownlint**" - - "nix/**" + # See above + paths: + - "**" + - "!.github/**" + - ".github/workflows/flatpak.yml" + - "!nix/" + - "!scripts/" + + - "!.git*" + - "!.envrc" + - "!**.md" + - "COPYING.md" + - "!renovate.json" workflow_dispatch: permissions: diff --git a/.github/workflows/merge-blocking-pr.yml b/.github/workflows/merge-blocking-pr.yml index d6410f997..d37c33761 100644 --- a/.github/workflows/merge-blocking-pr.yml +++ b/.github/workflows/merge-blocking-pr.yml @@ -1,9 +1,15 @@ name: Merged Blocking Pull Request Automation on: - pull_request: + pull_request_target: types: - closed + workflow_dispatch: + inputs: + pr_id: + description: Local Pull Request number to work on + required: true + type: number jobs: update-blocked-status: @@ -12,7 +18,7 @@ jobs: # a pr that was a `blocking:` label was merged. # find the open pr's it was blocked by and trigger a refresh of their state - if: github.event.pull_request.merged == true && contains( join( github.event.pull_request.labels.*.name, ',' ), 'blocking' ) + if: ${{ github.event_name == 'workflow_dispatch' || github.event.pull_request.merged == true && contains(github.event.pull_request.labels.*.name, 'blocking') }} steps: - name: Generate token @@ -26,11 +32,11 @@ jobs: id: gather_deps env: GH_TOKEN: ${{ steps.generate-token.outputs.token }} - PR_NUMBER: ${{ github.event.pull_request.number }} + PR_NUMBER: ${{ inputs.pr_id || github.event.pull_request.number }} run: | blocked_prs=$( gh -R ${{ github.repository }} pr list --label 'blocked' --json 'number,body' \ - | jq -c --argjson pr "${{ github.event.pull_request.number }}" ' + | jq -c --argjson pr "$PR_NUMBER" ' reduce ( .[] | select( .body | scan("(?:blocked (?:by|on)|stacked on):? #([0-9]+)") | diff --git a/.github/workflows/nix.yml b/.github/workflows/nix.yml index fea0df6ce..a11389e6c 100644 --- a/.github/workflows/nix.yml +++ b/.github/workflows/nix.yml @@ -4,28 +4,34 @@ on: push: tags: - "*" - paths-ignore: - - ".github/**" - - "!.github/workflows/nix.yml" - - "flatpak/" - - "scripts/" + # NOTE: `!` doesn't work with `paths-ignore` :( + # So we a catch-all glob instead + # https://github.com/orgs/community/discussions/25369#discussioncomment-3247674 + paths: + - "**" + - "!.github/**" + - ".github/workflows/nix.yml" + - "!flatpak/" + - "!scripts/" - - ".git*" - - ".envrc" - - "**.md" - - "!COPYING.md" - - "renovate.json" + - "!.git*" + - "!.envrc" + - "!**.md" + - "COPYING.md" + - "!renovate.json" pull_request_target: - paths-ignore: - - ".github/**" - - "flatpak/" - - "scripts/" + paths: + - "**" + - "!.github/**" + - ".github/workflows/nix.yml" + - "!flatpak/" + - "!scripts/" - - ".git*" - - ".envrc" - - "**.md" - - "!COPYING.md" - - "renovate.json" + - "!.git*" + - "!.envrc" + - "!**.md" + - "COPYING.md" + - "!renovate.json" workflow_dispatch: permissions: @@ -61,11 +67,20 @@ jobs: id-token: write steps: + - name: Get merge commit + if: ${{ github.event_name == 'pull_request_target' }} + id: merge-commit + uses: PrismLauncher/PrismLauncher/.github/actions/get-merge-commit@develop + with: + pull-request-id: ${{ github.event.pull_request.id }} + - name: Checkout repository uses: actions/checkout@v4 + with: + ref: ${{ steps.merge-commit.outputs.merge-commit-sha || github.sha }} - name: Install Nix - uses: DeterminateSystems/nix-installer-action@v16 + uses: DeterminateSystems/nix-installer-action@v17 with: determinate: ${{ env.USE_DETERMINATE }} diff --git a/.github/workflows/trigger_builds.yml b/.github/workflows/trigger_builds.yml index 9efafc8cc..e4c90ef0b 100644 --- a/.github/workflows/trigger_builds.yml +++ b/.github/workflows/trigger_builds.yml @@ -4,21 +4,39 @@ on: push: branches-ignore: - "renovate/**" - paths-ignore: - - "**.md" - - "**/LICENSE" - - "flake.lock" - - "packages/**" - - ".github/ISSUE_TEMPLATE/**" - - ".markdownlint**" + # NOTE: `!` doesn't work with `paths-ignore` :( + # So we a catch-all glob instead + # https://github.com/orgs/community/discussions/25369#discussioncomment-3247674 + paths: + - "**" + - "!.github/**" + - ".github/workflows/build.yml" + - ".github/workflows/trigger_builds.yml" + - "!flatpak/" + - "!nix/" + - "!scripts/" + + - "!.git*" + - "!.envrc" + - "!**.md" + - "COPYING.md" + - "!renovate.json" pull_request: - paths-ignore: - - "**.md" - - "**/LICENSE" - - "flake.lock" - - "packages/**" - - ".github/ISSUE_TEMPLATE/**" - - ".markdownlint**" + # See above + paths: + - "**" + - "!.github/**" + - ".github/workflows/build.yml" + - ".github/workflows/trigger_builds.yml" + - "!flatpak/" + - "!nix/" + - "!scripts/" + + - "!.git*" + - "!.envrc" + - "!**.md" + - "COPYING.md" + - "!renovate.json" workflow_dispatch: jobs: diff --git a/.github/workflows/trigger_release.yml b/.github/workflows/trigger_release.yml index 411a5bbeb..96f616a43 100644 --- a/.github/workflows/trigger_release.yml +++ b/.github/workflows/trigger_release.yml @@ -46,7 +46,6 @@ jobs: run: | mv ${{ github.workspace }}/PrismLauncher-source PrismLauncher-${{ env.VERSION }} mv PrismLauncher-Linux-Qt6-Portable*/PrismLauncher-portable.tar.gz PrismLauncher-Linux-Qt6-Portable-${{ env.VERSION }}.tar.gz - mv PrismLauncher-Linux-Qt5-Portable*/PrismLauncher-portable.tar.gz PrismLauncher-Linux-Qt5-Portable-${{ env.VERSION }}.tar.gz mv PrismLauncher-*.AppImage/PrismLauncher-*.AppImage PrismLauncher-Linux-x86_64.AppImage mv PrismLauncher-*.AppImage.zsync/PrismLauncher-*.AppImage.zsync PrismLauncher-Linux-x86_64.AppImage.zsync mv PrismLauncher-macOS*/PrismLauncher.zip PrismLauncher-macOS-${{ env.VERSION }}.zip @@ -89,7 +88,6 @@ jobs: draft: true prerelease: false files: | - PrismLauncher-Linux-Qt5-Portable-${{ env.VERSION }}.tar.gz PrismLauncher-Linux-x86_64.AppImage PrismLauncher-Linux-x86_64.AppImage.zsync PrismLauncher-Linux-Qt6-Portable-${{ env.VERSION }}.tar.gz diff --git a/.github/workflows/update-flake.yml b/.github/workflows/update-flake.yml index cdd360589..f4b1c4f5d 100644 --- a/.github/workflows/update-flake.yml +++ b/.github/workflows/update-flake.yml @@ -17,7 +17,7 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: cachix/install-nix-action@d1ca217b388ee87b2507a9a93bf01368bde7cec2 # v31 + - uses: cachix/install-nix-action@754537aaedb35f72ab11a60cc162c49ef3016495 # v31 - uses: DeterminateSystems/update-flake-lock@v24 with: diff --git a/CMakeLists.txt b/CMakeLists.txt index 91e10daf7..68d900c27 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -88,10 +88,8 @@ else() endif() endif() -# Fix build with Qt 5.13 -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_NO_DEPRECATED_WARNINGS=Y") - -set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_DISABLE_DEPRECATED_BEFORE=0x050C00") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_WARN_DEPRECATED_UP_TO=0x060200") +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DQT_DISABLE_DEPRECATED_UP_TO=0x060000") # Fix aarch64 build for toml++ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DTOML_ENABLE_FLOAT16=0") @@ -310,23 +308,7 @@ endif() # Find the required Qt parts include(QtVersionlessBackport) -if(Launcher_QT_VERSION_MAJOR EQUAL 5) - set(QT_VERSION_MAJOR 5) - find_package(Qt5 REQUIRED COMPONENTS Core Widgets Concurrent Network Test Xml NetworkAuth OpenGL) - find_package(Qt5 COMPONENTS DBus) - list(APPEND Launcher_QT_DBUS Qt5::DBus) - - if(NOT Launcher_FORCE_BUNDLED_LIBS) - find_package(QuaZip-Qt5 1.3 QUIET) - endif() - if (NOT QuaZip-Qt5_FOUND) - set(QUAZIP_QT_MAJOR_VERSION ${QT_VERSION_MAJOR} CACHE STRING "Qt version to use (4, 5 or 6), defaults to ${QT_VERSION_MAJOR}" FORCE) - set(FORCE_BUNDLED_QUAZIP 1) - endif() - - # Qt 6 sets these by default. Notably causes Windows APIs to use UNICODE strings. - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUNICODE -D_UNICODE") -elseif(Launcher_QT_VERSION_MAJOR EQUAL 6) +if(Launcher_QT_VERSION_MAJOR EQUAL 6) set(QT_VERSION_MAJOR 6) find_package(Qt6 REQUIRED COMPONENTS Core CoreTools Widgets Concurrent Network Test Xml Core5Compat NetworkAuth OpenGL) find_package(Qt6 COMPONENTS DBus) @@ -344,22 +326,12 @@ else() message(FATAL_ERROR "Qt version ${Launcher_QT_VERSION_MAJOR} is not supported") endif() -if(Launcher_QT_VERSION_MAJOR EQUAL 5) - include(ECMQueryQt) - ecm_query_qt(QT_PLUGINS_DIR QT_INSTALL_PLUGINS) - ecm_query_qt(QT_LIBS_DIR QT_INSTALL_LIBS) - ecm_query_qt(QT_LIBEXECS_DIR QT_INSTALL_LIBEXECS) -else() +if(Launcher_QT_VERSION_MAJOR EQUAL 6) set(QT_PLUGINS_DIR ${QT${QT_VERSION_MAJOR}_INSTALL_PREFIX}/${QT${QT_VERSION_MAJOR}_INSTALL_PLUGINS}) set(QT_LIBS_DIR ${QT${QT_VERSION_MAJOR}_INSTALL_PREFIX}/${QT${QT_VERSION_MAJOR}_INSTALL_LIBS}) set(QT_LIBEXECS_DIR ${QT${QT_VERSION_MAJOR}_INSTALL_PREFIX}/${QT${QT_VERSION_MAJOR}_INSTALL_LIBEXECS}) endif() -# NOTE: Qt 6 already sets this by default -if (Qt5_POSITION_INDEPENDENT_CODE) - SET(CMAKE_POSITION_INDEPENDENT_CODE ON) -endif() - if(NOT Launcher_FORCE_BUNDLED_LIBS) # Find toml++ find_package(tomlplusplus 3.2.0 QUIET) diff --git a/COPYING.md b/COPYING.md index f742c0132..1ebde116f 100644 --- a/COPYING.md +++ b/COPYING.md @@ -108,7 +108,7 @@ Information on third party licenses used in MinGW-w64 can be found in its COPYING.MinGW-w64-runtime.txt. -## Qt 5/6 +## Qt 6 Copyright (C) 2022 The Qt Company Ltd and other contributors. Contact: https://www.qt.io/licensing diff --git a/flake.lock b/flake.lock index 070d069e5..07fa5117a 100644 --- a/flake.lock +++ b/flake.lock @@ -3,11 +3,11 @@ "libnbtplusplus": { "flake": false, "locked": { - "lastModified": 1699286814, - "narHash": "sha256-yy0q+bky80LtK1GWzz7qpM+aAGrOqLuewbid8WT1ilk=", + "lastModified": 1744811532, + "narHash": "sha256-qhmjaRkt+O7A+gu6HjUkl7QzOEb4r8y8vWZMG2R/C6o=", "owner": "PrismLauncher", "repo": "libnbtplusplus", - "rev": "23b955121b8217c1c348a9ed2483167a6f3ff4ad", + "rev": "531449ba1c930c98e0bcf5d332b237a8566f9d78", "type": "github" }, "original": { @@ -18,11 +18,11 @@ }, "nixpkgs": { "locked": { - "lastModified": 1744463964, - "narHash": "sha256-LWqduOgLHCFxiTNYi3Uj5Lgz0SR+Xhw3kr/3Xd0GPTM=", + "lastModified": 1744932701, + "narHash": "sha256-fusHbZCyv126cyArUwwKrLdCkgVAIaa/fQJYFlCEqiU=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "2631b0b7abcea6e640ce31cd78ea58910d31e650", + "rev": "b024ced1aac25639f8ca8fdfc2f8c4fbd66c48ef", "type": "github" }, "original": { @@ -35,11 +35,11 @@ "qt-qrcodegenerator": { "flake": false, "locked": { - "lastModified": 1731907326, - "narHash": "sha256-5+iYwsbX8wjKZPCy7ENj5HCYgOqzeSNLs/YrX2Vc7CQ=", + "lastModified": 1737616857, + "narHash": "sha256-6SugPt0lp1Gz7nV23FLmsmpfzgFItkSw7jpGftsDPWc=", "owner": "nayuki", "repo": "QR-Code-generator", - "rev": "f40366c40d8d1956081f7ec643d240c02a81df52", + "rev": "2c9044de6b049ca25cb3cd1649ed7e27aa055138", "type": "github" }, "original": { diff --git a/flake.nix b/flake.nix index 2c7c69b3d..69abd78dd 100644 --- a/flake.nix +++ b/flake.nix @@ -138,6 +138,8 @@ { default = pkgs.mkShell { + name = "prism-launcher"; + inputsFrom = [ packages'.prismlauncher-unwrapped ]; packages = with pkgs; [ diff --git a/launcher/Application.cpp b/launcher/Application.cpp index d773d9a1c..cfe028279 100644 --- a/launcher/Application.cpp +++ b/launcher/Application.cpp @@ -125,6 +125,7 @@ #include #include +#include #include #include #include "SysInfo.h" @@ -153,11 +154,16 @@ #endif #if defined Q_OS_WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif #include #include -#include "WindowsConsole.h" +#include "console/WindowsConsole.h" #endif +#include "console/Console.h" + #define STRINGIFY(x) #x #define TOSTRING(x) STRINGIFY(x) @@ -165,6 +171,63 @@ static const QLatin1String liveCheckFile("live.check"); PixmapCache* PixmapCache::s_instance = nullptr; +static bool isANSIColorConsole; + +static QString defaultLogFormat = QStringLiteral( + "%{time process}" + " " + "%{if-debug}Debug:%{endif}" + "%{if-info}Info:%{endif}" + "%{if-warning}Warning:%{endif}" + "%{if-critical}Critical:%{endif}" + "%{if-fatal}Fatal:%{endif}" + " " + "%{if-category}[%{category}] %{endif}" + "%{message}" + " " + "(%{function}:%{line})"); + +#define ansi_reset "\x1b[0m" +#define ansi_bold "\x1b[1m" +#define ansi_reset_bold "\x1b[22m" +#define ansi_faint "\x1b[2m" +#define ansi_italic "\x1b[3m" +#define ansi_red_fg "\x1b[31m" +#define ansi_green_fg "\x1b[32m" +#define ansi_yellow_fg "\x1b[33m" +#define ansi_blue_fg "\x1b[34m" +#define ansi_purple_fg "\x1b[35m" +#define ansi_inverse "\x1b[7m" + +// clang-format off +static QString ansiLogFormat = QStringLiteral( + ansi_faint "%{time process}" ansi_reset + " " + "%{if-debug}" ansi_bold ansi_green_fg "D:" ansi_reset "%{endif}" + "%{if-info}" ansi_bold ansi_blue_fg "I:" ansi_reset "%{endif}" + "%{if-warning}" ansi_bold ansi_yellow_fg "W:" ansi_reset_bold "%{endif}" + "%{if-critical}" ansi_bold ansi_red_fg "C:" ansi_reset_bold "%{endif}" + "%{if-fatal}" ansi_bold ansi_inverse ansi_red_fg "F:" ansi_reset_bold "%{endif}" + " " + "%{if-category}" ansi_bold "[%{category}]" ansi_reset_bold " %{endif}" + "%{message}" + " " + ansi_reset ansi_faint "(%{function}:%{line})" ansi_reset +); +// clang-format on + +#undef ansi_inverse +#undef ansi_purple_fg +#undef ansi_blue_fg +#undef ansi_yellow_fg +#undef ansi_green_fg +#undef ansi_red_fg +#undef ansi_italic +#undef ansi_faint +#undef ansi_bold +#undef ansi_reset_bold +#undef ansi_reset + namespace { /** This is used so that we can output to the log file in addition to the CLI. */ @@ -173,11 +236,24 @@ void appDebugOutput(QtMsgType type, const QMessageLogContext& context, const QSt static std::mutex loggerMutex; const std::lock_guard lock(loggerMutex); // synchronized, QFile logFile is not thread-safe + if (isANSIColorConsole) { + // ensure default is set for log file + qSetMessagePattern(defaultLogFormat); + } + QString out = qFormatLogMessage(type, context, msg); out += QChar::LineFeed; APPLICATION->logFile->write(out.toUtf8()); APPLICATION->logFile->flush(); + + if (isANSIColorConsole) { + // format ansi for console; + qSetMessagePattern(ansiLogFormat); + out = qFormatLogMessage(type, context, msg); + out += QChar::LineFeed; + } + QTextStream(stderr) << out.toLocal8Bit(); fflush(stderr); } @@ -218,8 +294,18 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv) // attach the parent console if stdout not already captured if (AttachWindowsConsole()) { consoleAttached = true; + if (auto err = EnableAnsiSupport(); !err) { + isANSIColorConsole = true; + } else { + std::cout << "Error setting up ansi console" << err.message() << std::endl; + } + } +#else + if (console::isConsole()) { + isANSIColorConsole = true; } #endif + setOrganizationName(BuildConfig.LAUNCHER_NAME); setOrganizationDomain(BuildConfig.LAUNCHER_DOMAIN); setApplicationName(BuildConfig.LAUNCHER_NAME); @@ -448,27 +534,14 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv) return; } qInstallMessageHandler(appDebugOutput); - - qSetMessagePattern( - "%{time process}" - " " - "%{if-debug}D%{endif}" - "%{if-info}I%{endif}" - "%{if-warning}W%{endif}" - "%{if-critical}C%{endif}" - "%{if-fatal}F%{endif}" - " " - "|" - " " - "%{if-category}[%{category}]: %{endif}" - "%{message}"); + qSetMessagePattern(defaultLogFormat); bool foundLoggingRules = false; auto logRulesFile = QStringLiteral("qtlogging.ini"); auto logRulesPath = FS::PathCombine(dataPath, logRulesFile); - qDebug() << "Testing" << logRulesPath << "..."; + qInfo() << "Testing" << logRulesPath << "..."; foundLoggingRules = QFile::exists(logRulesPath); // search the dataPath() @@ -476,7 +549,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv) if (!foundLoggingRules && !isPortable() && dirParam.isEmpty() && dataDirEnv.isEmpty()) { logRulesPath = QStandardPaths::locate(QStandardPaths::AppDataLocation, FS::PathCombine("..", logRulesFile)); if (!logRulesPath.isEmpty()) { - qDebug() << "Found" << logRulesPath << "..."; + qInfo() << "Found" << logRulesPath << "..."; foundLoggingRules = true; } } @@ -487,28 +560,28 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv) #else logRulesPath = FS::PathCombine(m_rootPath, logRulesFile); #endif - qDebug() << "Testing" << logRulesPath << "..."; + qInfo() << "Testing" << logRulesPath << "..."; foundLoggingRules = QFile::exists(logRulesPath); } if (foundLoggingRules) { // load and set logging rules - qDebug() << "Loading logging rules from:" << logRulesPath; + qInfo() << "Loading logging rules from:" << logRulesPath; QSettings loggingRules(logRulesPath, QSettings::IniFormat); loggingRules.beginGroup("Rules"); QStringList rule_names = loggingRules.childKeys(); QStringList rules; - qDebug() << "Setting log rules:"; + qInfo() << "Setting log rules:"; for (auto rule_name : rule_names) { auto rule = QString("%1=%2").arg(rule_name).arg(loggingRules.value(rule_name).toString()); rules.append(rule); - qDebug() << " " << rule; + qInfo() << " " << rule; } auto rules_str = rules.join("\n"); QLoggingCategory::setFilterRules(rules_str); } - qDebug() << "<> Log initialized."; + qInfo() << "<> Log initialized."; } { @@ -525,33 +598,33 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv) } { - qDebug() << qPrintable(BuildConfig.LAUNCHER_DISPLAYNAME + ", " + QString(BuildConfig.LAUNCHER_COPYRIGHT).replace("\n", ", ")); - qDebug() << "Version : " << BuildConfig.printableVersionString(); - qDebug() << "Platform : " << BuildConfig.BUILD_PLATFORM; - qDebug() << "Git commit : " << BuildConfig.GIT_COMMIT; - qDebug() << "Git refspec : " << BuildConfig.GIT_REFSPEC; - qDebug() << "Compiled for : " << BuildConfig.systemID(); - qDebug() << "Compiled by : " << BuildConfig.compilerID(); - qDebug() << "Build Artifact : " << BuildConfig.BUILD_ARTIFACT; - qDebug() << "Updates Enabled : " << (updaterEnabled() ? "Yes" : "No"); + qInfo() << qPrintable(BuildConfig.LAUNCHER_DISPLAYNAME + ", " + QString(BuildConfig.LAUNCHER_COPYRIGHT).replace("\n", ", ")); + qInfo() << "Version : " << BuildConfig.printableVersionString(); + qInfo() << "Platform : " << BuildConfig.BUILD_PLATFORM; + qInfo() << "Git commit : " << BuildConfig.GIT_COMMIT; + qInfo() << "Git refspec : " << BuildConfig.GIT_REFSPEC; + qInfo() << "Compiled for : " << BuildConfig.systemID(); + qInfo() << "Compiled by : " << BuildConfig.compilerID(); + qInfo() << "Build Artifact : " << BuildConfig.BUILD_ARTIFACT; + qInfo() << "Updates Enabled : " << (updaterEnabled() ? "Yes" : "No"); if (adjustedBy.size()) { - qDebug() << "Work dir before adjustment : " << origcwdPath; - qDebug() << "Work dir after adjustment : " << QDir::currentPath(); - qDebug() << "Adjusted by : " << adjustedBy; + qInfo() << "Work dir before adjustment : " << origcwdPath; + qInfo() << "Work dir after adjustment : " << QDir::currentPath(); + qInfo() << "Adjusted by : " << adjustedBy; } else { - qDebug() << "Work dir : " << QDir::currentPath(); + qInfo() << "Work dir : " << QDir::currentPath(); } - qDebug() << "Binary path : " << binPath; - qDebug() << "Application root path : " << m_rootPath; + qInfo() << "Binary path : " << binPath; + qInfo() << "Application root path : " << m_rootPath; if (!m_instanceIdToLaunch.isEmpty()) { - qDebug() << "ID of instance to launch : " << m_instanceIdToLaunch; + qInfo() << "ID of instance to launch : " << m_instanceIdToLaunch; } if (!m_serverToJoin.isEmpty()) { - qDebug() << "Address of server to join :" << m_serverToJoin; + qInfo() << "Address of server to join :" << m_serverToJoin; } else if (!m_worldToJoin.isEmpty()) { - qDebug() << "Name of the world to join :" << m_worldToJoin; + qInfo() << "Name of the world to join :" << m_worldToJoin; } - qDebug() << "<> Paths set."; + qInfo() << "<> Paths set."; } if (m_liveCheck) { @@ -818,7 +891,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv) PixmapCache::setInstance(new PixmapCache(this)); - qDebug() << "<> Settings loaded."; + qInfo() << "<> Settings loaded."; } #ifndef QT_NO_ACCESSIBILITY @@ -834,7 +907,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv) QString user = settings()->get("ProxyUser").toString(); QString pass = settings()->get("ProxyPass").toString(); updateProxySettings(proxyTypeStr, addr, port, user, pass); - qDebug() << "<> Network done."; + qInfo() << "<> Network done."; } // load translations @@ -842,8 +915,8 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv) m_translations.reset(new TranslationsModel("translations")); auto bcp47Name = m_settings->get("Language").toString(); m_translations->selectLanguage(bcp47Name); - qDebug() << "Your language is" << bcp47Name; - qDebug() << "<> Translations loaded."; + qInfo() << "Your language is" << bcp47Name; + qInfo() << "<> Translations loaded."; } // Instance icons @@ -854,7 +927,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv) m_icons.reset(new IconList(instFolders, setting->get().toString())); connect(setting.get(), &Setting::SettingChanged, [this](const Setting&, QVariant value) { m_icons->directoryChanged(value.toString()); }); - qDebug() << "<> Instance icons initialized."; + qInfo() << "<> Instance icons initialized."; } // Themes @@ -866,25 +939,25 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv) // instance path: check for problems with '!' in instance path and warn the user in the log // and remember that we have to show him a dialog when the gui starts (if it does so) QString instDir = InstDirSetting->get().toString(); - qDebug() << "Instance path : " << instDir; + qInfo() << "Instance path : " << instDir; if (FS::checkProblemticPathJava(QDir(instDir))) { qWarning() << "Your instance path contains \'!\' and this is known to cause java problems!"; } m_instances.reset(new InstanceList(m_settings, instDir, this)); connect(InstDirSetting.get(), &Setting::SettingChanged, m_instances.get(), &InstanceList::on_InstFolderChanged); - qDebug() << "Loading Instances..."; + qInfo() << "Loading Instances..."; m_instances->loadList(); - qDebug() << "<> Instances loaded."; + qInfo() << "<> Instances loaded."; } // and accounts { m_accounts.reset(new AccountList(this)); - qDebug() << "Loading accounts..."; + qInfo() << "Loading accounts..."; m_accounts->setListFilePath("accounts.json", true); m_accounts->loadList(); m_accounts->fillQueue(); - qDebug() << "<> Accounts loaded."; + qInfo() << "<> Accounts loaded."; } // init the http meta cache @@ -905,7 +978,7 @@ Application::Application(int& argc, char** argv) : QApplication(argc, argv) m_metacache->addBase("meta", QDir("meta").absolutePath()); m_metacache->addBase("java", QDir("cache/java").absolutePath()); m_metacache->Load(); - qDebug() << "<> Cache initialized."; + qInfo() << "<> Cache initialized."; } // now we have network, download translation updates diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index e10921d3e..ca5a5bea9 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -99,7 +99,7 @@ set(CORE_SOURCES MTPixmapCache.h ) if (UNIX AND NOT CYGWIN AND NOT APPLE) -set(CORE_SOURCES + set(CORE_SOURCES ${CORE_SOURCES} # MangoHud @@ -589,8 +589,8 @@ set(ATLAUNCHER_SOURCES ) set(LINKEXE_SOURCES - WindowsConsole.cpp - WindowsConsole.h + console/WindowsConsole.h + console/WindowsConsole.cpp filelink/FileLink.h filelink/FileLink.cpp @@ -659,6 +659,14 @@ set(PRISMUPDATER_SOURCES ) +if(WIN32) + set(PRISMUPDATER_SOURCES + console/WindowsConsole.h + console/WindowsConsole.cpp + ${PRISMUPDATER_SOURCES} + ) +endif() + ######## Logging categories ######## ecm_qt_declare_logging_category(CORE_SOURCES @@ -786,6 +794,9 @@ SET(LAUNCHER_SOURCES SysInfo.h SysInfo.cpp + # console utils + console/Console.h + # GUI - general utilities DesktopServices.h DesktopServices.cpp @@ -926,7 +937,7 @@ SET(LAUNCHER_SOURCES ui/pages/instance/McResolver.h ui/pages/instance/ServerPingTask.cpp ui/pages/instance/ServerPingTask.h - + # GUI - global settings pages ui/pages/global/AccountListPage.cpp ui/pages/global/AccountListPage.h @@ -1154,7 +1165,7 @@ SET(LAUNCHER_SOURCES ) if (NOT Apple) -set(LAUNCHER_SOURCES + set(LAUNCHER_SOURCES ${LAUNCHER_SOURCES} ui/dialogs/UpdateAvailableDialog.h @@ -1164,8 +1175,8 @@ endif() if(WIN32) set(LAUNCHER_SOURCES - WindowsConsole.cpp - WindowsConsole.h + console/WindowsConsole.h + console/WindowsConsole.cpp ${LAUNCHER_SOURCES} ) endif() @@ -1325,11 +1336,11 @@ if(APPLE) set(CMAKE_INSTALL_RPATH "@loader_path/../Frameworks/") if(Launcher_ENABLE_UPDATER) - file(DOWNLOAD ${MACOSX_SPARKLE_DOWNLOAD_URL} ${CMAKE_BINARY_DIR}/Sparkle.tar.xz EXPECTED_HASH SHA256=${MACOSX_SPARKLE_SHA256}) - file(ARCHIVE_EXTRACT INPUT ${CMAKE_BINARY_DIR}/Sparkle.tar.xz DESTINATION ${CMAKE_BINARY_DIR}/frameworks/Sparkle) + file(DOWNLOAD ${MACOSX_SPARKLE_DOWNLOAD_URL} ${CMAKE_BINARY_DIR}/Sparkle.tar.xz EXPECTED_HASH SHA256=${MACOSX_SPARKLE_SHA256}) + file(ARCHIVE_EXTRACT INPUT ${CMAKE_BINARY_DIR}/Sparkle.tar.xz DESTINATION ${CMAKE_BINARY_DIR}/frameworks/Sparkle) - find_library(SPARKLE_FRAMEWORK Sparkle "${CMAKE_BINARY_DIR}/frameworks/Sparkle") - add_compile_definitions(SPARKLE_ENABLED) + find_library(SPARKLE_FRAMEWORK Sparkle "${CMAKE_BINARY_DIR}/frameworks/Sparkle") + add_compile_definitions(SPARKLE_ENABLED) endif() target_link_libraries(Launcher_logic @@ -1339,7 +1350,7 @@ if(APPLE) "-framework ApplicationServices" ) if(Launcher_ENABLE_UPDATER) - target_link_libraries(Launcher_logic ${SPARKLE_FRAMEWORK}) + target_link_libraries(Launcher_logic ${SPARKLE_FRAMEWORK}) endif() endif() diff --git a/launcher/DataMigrationTask.cpp b/launcher/DataMigrationTask.cpp index 92e310a16..18decc7c3 100644 --- a/launcher/DataMigrationTask.cpp +++ b/launcher/DataMigrationTask.cpp @@ -37,11 +37,7 @@ 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; } @@ -75,11 +71,7 @@ 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; } diff --git a/launcher/FileIgnoreProxy.cpp b/launcher/FileIgnoreProxy.cpp index 89c91ec1d..0314057d1 100644 --- a/launcher/FileIgnoreProxy.cpp +++ b/launcher/FileIgnoreProxy.cpp @@ -282,11 +282,7 @@ void FileIgnoreProxy::loadBlockedPathsFromFile(const QString& fileName) } auto ignoreData = ignoreFile.readAll(); auto string = QString::fromUtf8(ignoreData); -#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) setBlockedPaths(string.split('\n', Qt::SkipEmptyParts)); -#else - setBlockedPaths(string.split('\n', QString::SkipEmptyParts)); -#endif } void FileIgnoreProxy::saveBlockedPathsToFile(const QString& fileName) diff --git a/launcher/FileSystem.cpp b/launcher/FileSystem.cpp index 7189ca841..08dc7d2cc 100644 --- a/launcher/FileSystem.cpp +++ b/launcher/FileSystem.cpp @@ -679,9 +679,6 @@ bool deletePath(QString path) bool trash(QString path, QString* pathInTrash) { -#if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) - return false; -#else // FIXME: Figure out trash in Flatpak. Qt seemingly doesn't use the Trash portal if (DesktopServices::isFlatpak()) return false; @@ -690,7 +687,6 @@ bool trash(QString path, QString* pathInTrash) return false; #endif return QFile::moveToTrash(path, pathInTrash); -#endif } QString PathCombine(const QString& path1, const QString& path2) @@ -724,11 +720,7 @@ int pathDepth(const QString& path) QFileInfo info(path); -#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) - auto parts = QDir::toNativeSeparators(info.path()).split(QDir::separator(), QString::SkipEmptyParts); -#else auto parts = QDir::toNativeSeparators(info.path()).split(QDir::separator(), Qt::SkipEmptyParts); -#endif int numParts = parts.length(); numParts -= parts.count("."); @@ -748,11 +740,7 @@ QString pathTruncate(const QString& path, int depth) return pathTruncate(trunc, depth); } -#if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) - auto parts = QDir::toNativeSeparators(trunc).split(QDir::separator(), QString::SkipEmptyParts); -#else auto parts = QDir::toNativeSeparators(trunc).split(QDir::separator(), Qt::SkipEmptyParts); -#endif if (parts.startsWith(".") && !path.startsWith(".")) { parts.removeFirst(); diff --git a/launcher/GZip.cpp b/launcher/GZip.cpp index eaf1c9035..29c71c012 100644 --- a/launcher/GZip.cpp +++ b/launcher/GZip.cpp @@ -139,64 +139,80 @@ bool GZip::zip(const QByteArray& uncompressedBytes, QByteArray& compressedBytes) return true; } -GZipStream::GZipStream(const QString& filePath) : GZipStream(new QFile(filePath)) {} - -GZipStream::GZipStream(QFile* file) : m_file(file) {} - -bool GZipStream::initStream() +int inf(QFile* source, std::function handleBlock) { - memset(&m_strm, 0, sizeof(m_strm)); - return (inflateInit2(&m_strm, 16 + MAX_WBITS) == Z_OK); -} + constexpr auto CHUNK = 16384; + int ret; + unsigned have; + z_stream strm; + memset(&strm, 0, sizeof(strm)); + char in[CHUNK]; + unsigned char out[CHUNK]; -bool GZipStream::unzipBlockByBlock(QByteArray& uncompressedBytes) -{ - uncompressedBytes.clear(); - if (!m_file->isOpen()) { - if (!m_file->open(QIODevice::ReadOnly)) { - qWarning() << "Failed to open file:" << (m_file->fileName()); - return false; + ret = inflateInit2(&strm, (16 + MAX_WBITS)); + if (ret != Z_OK) + return ret; + + /* decompress until deflate stream ends or end of file */ + do { + strm.avail_in = source->read(in, CHUNK); + if (source->error()) { + (void)inflateEnd(&strm); + return Z_ERRNO; } - } + if (strm.avail_in == 0) + break; + strm.next_in = reinterpret_cast(in); - if (!m_strm.state && !initStream()) { - return false; - } + /* run inflate() on input until output buffer not full */ + do { + strm.avail_out = CHUNK; + strm.next_out = out; + ret = inflate(&strm, Z_NO_FLUSH); + assert(ret != Z_STREAM_ERROR); /* state not clobbered */ + switch (ret) { + case Z_NEED_DICT: + ret = Z_DATA_ERROR; /* and fall through */ + case Z_DATA_ERROR: + case Z_MEM_ERROR: + (void)inflateEnd(&strm); + return ret; + } + have = CHUNK - strm.avail_out; + if (!handleBlock(QByteArray(reinterpret_cast(out), have))) { + (void)inflateEnd(&strm); + return Z_OK; + } - QByteArray compressedBlock; - unsigned int blockSize = 4096; + } while (strm.avail_out == 0); - compressedBlock = m_file->read(blockSize); - if (compressedBlock.isEmpty()) { - return true; // End of file reached - } + /* done when inflate() says it's done */ + } while (ret != Z_STREAM_END); - bool done = processBlock(compressedBlock, uncompressedBytes); - if (inflateEnd(&m_strm) != Z_OK || !done) { - return false; - } - return done; + /* clean up and return */ + (void)inflateEnd(&strm); + return ret == Z_STREAM_END ? Z_OK : Z_DATA_ERROR; } -bool GZipStream::processBlock(const QByteArray& compressedBlock, QByteArray& uncompressedBytes) +QString zerr(int ret) { - m_strm.next_in = (Bytef*)compressedBlock.data(); - m_strm.avail_in = compressedBlock.size(); - - unsigned int uncompLength = uncompressedBytes.size(); - if (m_strm.total_out >= uncompLength) { - uncompressedBytes.resize(uncompLength * 2); - uncompLength *= 2; + switch (ret) { + case Z_ERRNO: + return QObject::tr("error handling file"); + case Z_STREAM_ERROR: + return QObject::tr("invalid compression level"); + case Z_DATA_ERROR: + return QObject::tr("invalid or incomplete deflate data"); + case Z_MEM_ERROR: + return QObject::tr("out of memory"); + case Z_VERSION_ERROR: + return QObject::tr("zlib version mismatch!"); } - - m_strm.next_out = reinterpret_cast(uncompressedBytes.data() + m_strm.total_out); - m_strm.avail_out = uncompLength - m_strm.total_out; - - int err = inflate(&m_strm, Z_NO_FLUSH); - if (err != Z_OK && err != Z_STREAM_END) { - qWarning() << "Decompression failed with error code" << err; - return false; - } - - return true; + return {}; } + +QString GZip::readGzFileByBlocks(QFile* source, std::function handleBlock) +{ + auto ret = inf(source, handleBlock); + return zerr(ret); +} \ No newline at end of file diff --git a/launcher/GZip.h b/launcher/GZip.h index dd4162839..b736ca93f 100644 --- a/launcher/GZip.h +++ b/launcher/GZip.h @@ -1,28 +1,11 @@ #pragma once -#include #include #include -class GZip { - public: - static bool unzip(const QByteArray& compressedBytes, QByteArray& uncompressedBytes); - static bool zip(const QByteArray& uncompressedBytes, QByteArray& compressedBytes); -}; +namespace GZip { -class GZipStream { - public: - explicit GZipStream(const QString& filePath); - explicit GZipStream(QFile* file); +bool unzip(const QByteArray& compressedBytes, QByteArray& uncompressedBytes); +bool zip(const QByteArray& uncompressedBytes, QByteArray& compressedBytes); +QString readGzFileByBlocks(QFile* source, std::function handleBlock); - // Decompress the next block and return the decompressed data - bool unzipBlockByBlock(QByteArray& uncompressedBytes); - - private: - bool initStream(); - - bool processBlock(const QByteArray& compressedBlock, QByteArray& uncompressedBytes); - - private: - QFile* m_file; - z_stream m_strm; -}; +} // namespace GZip diff --git a/launcher/InstanceList.cpp b/launcher/InstanceList.cpp index 918fa1073..89e7dc04d 100644 --- a/launcher/InstanceList.cpp +++ b/launcher/InstanceList.cpp @@ -428,7 +428,7 @@ static QMap getIdMapping(const QList& QList InstanceList::discoverInstances() { - qDebug() << "Discovering instances in" << m_instDir; + qInfo() << "Discovering instances in" << m_instDir; QList out; QDirIterator iter(m_instDir, QDir::Dirs | QDir::NoDot | QDir::NoDotDot | QDir::Readable | QDir::Hidden, QDirIterator::FollowSymlinks); while (iter.hasNext()) { @@ -447,13 +447,9 @@ QList InstanceList::discoverInstances() } auto id = dirInfo.fileName(); out.append(id); - qDebug() << "Found instance ID" << id; + qInfo() << "Found instance ID" << id; } -#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) instanceSet = QSet(out.begin(), out.end()); -#else - instanceSet = out.toSet(); -#endif m_instancesProbed = true; return out; } @@ -468,7 +464,7 @@ InstanceList::InstListError InstanceList::loadList() if (existingIds.contains(id)) { auto instPair = existingIds[id]; existingIds.remove(id); - qDebug() << "Should keep and soft-reload" << id; + qInfo() << "Should keep and soft-reload" << id; } else { InstancePtr instPtr = loadInstance(id); if (instPtr) { diff --git a/launcher/StringUtils.cpp b/launcher/StringUtils.cpp index edda9f247..2ea67762e 100644 --- a/launcher/StringUtils.cpp +++ b/launcher/StringUtils.cpp @@ -53,7 +53,7 @@ static inline QChar getNextChar(const QString& s, int location) int StringUtils::naturalCompare(const QString& s1, const QString& s2, Qt::CaseSensitivity cs) { int l1 = 0, l2 = 0; - while (l1 <= s1.count() && l2 <= s2.count()) { + while (l1 <= s1.size() && l2 <= s2.size()) { // skip spaces, tabs and 0's QChar c1 = getNextChar(s1, l1); while (c1.isSpace()) diff --git a/launcher/Version.h b/launcher/Version.h index b06e256aa..12e7f0832 100644 --- a/launcher/Version.h +++ b/launcher/Version.h @@ -72,22 +72,14 @@ class Version { } } -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) auto numPart = QStringView{ m_fullString }.left(cutoff); -#else - auto numPart = m_fullString.leftRef(cutoff); -#endif if (!numPart.isEmpty()) { m_isNull = false; m_numPart = numPart.toInt(); } -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) auto stringPart = QStringView{ m_fullString }.mid(cutoff); -#else - auto stringPart = m_fullString.midRef(cutoff); -#endif if (!stringPart.isEmpty()) { m_isNull = false; diff --git a/launcher/console/Console.h b/launcher/console/Console.h new file mode 100644 index 000000000..7aaf83dcc --- /dev/null +++ b/launcher/console/Console.h @@ -0,0 +1,33 @@ +#pragma once + +#include + +#include +#if defined Q_OS_WIN32 +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include +#else +#include +#include +#endif + +namespace console { + +inline bool isConsole() +{ +#if defined Q_OS_WIN32 + DWORD procIDs[2]; + DWORD maxCount = 2; + DWORD result = GetConsoleProcessList((LPDWORD)procIDs, maxCount); + return result > 1; +#else + if (isatty(fileno(stdout))) { + return true; + } + return false; +#endif +} + +} // namespace console diff --git a/launcher/WindowsConsole.cpp b/launcher/console/WindowsConsole.cpp similarity index 78% rename from launcher/WindowsConsole.cpp rename to launcher/console/WindowsConsole.cpp index 83cad5afa..4a0eb3d3d 100644 --- a/launcher/WindowsConsole.cpp +++ b/launcher/console/WindowsConsole.cpp @@ -16,13 +16,18 @@ * */ +#include "WindowsConsole.h" +#include + #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif +#include + #include #include #include -#include +#include #include void RedirectHandle(DWORD handle, FILE* stream, const char* mode) @@ -126,3 +131,29 @@ bool AttachWindowsConsole() return false; } + +std::error_code EnableAnsiSupport() +{ + // ref: https://docs.microsoft.com/en-us/windows/win32/api/fileapi/nf-fileapi-createfilew + // Using `CreateFileW("CONOUT$", ...)` to retrieve the console handle works correctly even if STDOUT and/or STDERR are redirected + HANDLE console_handle = CreateFileW(L"CONOUT$", FILE_GENERIC_READ | FILE_GENERIC_WRITE, FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0); + if (console_handle == INVALID_HANDLE_VALUE) { + return std::error_code(GetLastError(), std::system_category()); + } + + // ref: https://docs.microsoft.com/en-us/windows/console/getconsolemode + DWORD console_mode; + if (0 == GetConsoleMode(console_handle, &console_mode)) { + return std::error_code(GetLastError(), std::system_category()); + } + + // VT processing not already enabled? + if ((console_mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING) == 0) { + // https://docs.microsoft.com/en-us/windows/console/setconsolemode + if (0 == SetConsoleMode(console_handle, console_mode | ENABLE_VIRTUAL_TERMINAL_PROCESSING)) { + return std::error_code(GetLastError(), std::system_category()); + } + } + + return {}; +} diff --git a/launcher/WindowsConsole.h b/launcher/console/WindowsConsole.h similarity index 93% rename from launcher/WindowsConsole.h rename to launcher/console/WindowsConsole.h index ab53864b4..4c1f3ee28 100644 --- a/launcher/WindowsConsole.h +++ b/launcher/console/WindowsConsole.h @@ -21,5 +21,8 @@ #pragma once +#include + void BindCrtHandlesToStdHandles(bool bindStdIn, bool bindStdOut, bool bindStdErr); bool AttachWindowsConsole(); +std::error_code EnableAnsiSupport(); diff --git a/launcher/filelink/FileLink.cpp b/launcher/filelink/FileLink.cpp index a082b4b5b..1494fa8cc 100644 --- a/launcher/filelink/FileLink.cpp +++ b/launcher/filelink/FileLink.cpp @@ -37,7 +37,10 @@ #include #if defined Q_OS_WIN32 -#include "WindowsConsole.h" +#ifndef WIN32_LEAN_AND_MEAN +#define WIN32_LEAN_AND_MEAN +#endif +#include "console/WindowsConsole.h" #endif #include diff --git a/launcher/icons/IconList.cpp b/launcher/icons/IconList.cpp index 7369d8b4b..8a2a482e1 100644 --- a/launcher/icons/IconList.cpp +++ b/launcher/icons/IconList.cpp @@ -137,11 +137,7 @@ QString formatName(const QDir& iconsDir, const QFileInfo& iconFile) /// Split into a separate function because the preprocessing impedes readability QSet toStringSet(const QList& list) { -#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) QSet set(list.begin(), list.end()); -#else - QSet set = list.toSet(); -#endif return set; } @@ -477,4 +473,4 @@ QString IconList::iconDirectory(const QString& key) const } } return getDirectory(); -} +} \ No newline at end of file diff --git a/launcher/java/JavaChecker.cpp b/launcher/java/JavaChecker.cpp index 07b5d7b40..0aa725705 100644 --- a/launcher/java/JavaChecker.cpp +++ b/launcher/java/JavaChecker.cpp @@ -137,11 +137,7 @@ void JavaChecker::finished(int exitcode, QProcess::ExitStatus status) QMap results; -#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) QStringList lines = m_stdout.split("\n", Qt::SkipEmptyParts); -#else - QStringList lines = m_stdout.split("\n", QString::SkipEmptyParts); -#endif for (QString line : lines) { line = line.trimmed(); // NOTE: workaround for GH-4125, where garbage is getting printed into stdout on bedrock linux @@ -149,11 +145,7 @@ void JavaChecker::finished(int exitcode, QProcess::ExitStatus status) continue; } -#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) auto parts = line.split('=', Qt::SkipEmptyParts); -#else - auto parts = line.split('=', QString::SkipEmptyParts); -#endif if (parts.size() != 2 || parts[0].isEmpty() || parts[1].isEmpty()) { continue; } else { diff --git a/launcher/launch/steps/PostLaunchCommand.cpp b/launcher/launch/steps/PostLaunchCommand.cpp index 5d893c71f..6b960974e 100644 --- a/launcher/launch/steps/PostLaunchCommand.cpp +++ b/launcher/launch/steps/PostLaunchCommand.cpp @@ -49,14 +49,10 @@ void PostLaunchCommand::executeTask() { auto cmd = m_parent->substituteVariables(m_command); emit logLine(tr("Running Post-Launch command: %1").arg(cmd), MessageLevel::Launcher); -#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) auto args = QProcess::splitCommand(cmd); const QString program = args.takeFirst(); m_process.start(program, args); -#else - m_process.start(cmd); -#endif } void PostLaunchCommand::on_state(LoggedProcess::State state) diff --git a/launcher/launch/steps/PreLaunchCommand.cpp b/launcher/launch/steps/PreLaunchCommand.cpp index 318237e99..7e843ca3f 100644 --- a/launcher/launch/steps/PreLaunchCommand.cpp +++ b/launcher/launch/steps/PreLaunchCommand.cpp @@ -49,13 +49,9 @@ void PreLaunchCommand::executeTask() { auto cmd = m_parent->substituteVariables(m_command); emit logLine(tr("Running Pre-Launch command: %1").arg(cmd), MessageLevel::Launcher); -#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) auto args = QProcess::splitCommand(cmd); const QString program = args.takeFirst(); m_process.start(program, args); -#else - m_process.start(cmd); -#endif } void PreLaunchCommand::on_state(LoggedProcess::State state) diff --git a/launcher/minecraft/MinecraftInstance.cpp b/launcher/minecraft/MinecraftInstance.cpp index 1009d7c42..eeda53307 100644 --- a/launcher/minecraft/MinecraftInstance.cpp +++ b/launcher/minecraft/MinecraftInstance.cpp @@ -757,11 +757,7 @@ QStringList MinecraftInstance::processMinecraftArgs(AuthSessionPtr session, Mine token_mapping["assets_root"] = absAssetsDir; token_mapping["assets_index_name"] = assets->id; -#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) QStringList parts = args_pattern.split(' ', Qt::SkipEmptyParts); -#else - QStringList parts = args_pattern.split(' ', QString::SkipEmptyParts); -#endif for (int i = 0; i < parts.length(); i++) { parts[i] = replaceTokensIn(parts[i], token_mapping); } @@ -816,11 +812,7 @@ QString MinecraftInstance::createLaunchScript(AuthSessionPtr session, MinecraftT auto mainWindow = qobject_cast(w); if (mainWindow) { auto m = mainWindow->windowHandle()->frameMargins(); -#if (QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)) screenGeometry = screenGeometry.shrunkBy(m); -#else - screenGeometry = { screenGeometry.width() - m.left() - m.right(), screenGeometry.height() - m.top() - m.bottom() }; -#endif break; } } diff --git a/launcher/minecraft/PackProfile.cpp b/launcher/minecraft/PackProfile.cpp index 4deee9712..8475a1f32 100644 --- a/launcher/minecraft/PackProfile.cpp +++ b/launcher/minecraft/PackProfile.cpp @@ -645,11 +645,7 @@ void PackProfile::move(const int index, const MoveDirection direction) return; } beginMoveRows(QModelIndex(), index, index, QModelIndex(), togap); -#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) d->components.swapItemsAt(index, theirIndex); -#else - d->components.swap(index, theirIndex); -#endif endMoveRows(); invalidateLaunchProfile(); scheduleSave(); diff --git a/launcher/minecraft/WorldList.cpp b/launcher/minecraft/WorldList.cpp index 5f192740e..6a821ba60 100644 --- a/launcher/minecraft/WorldList.cpp +++ b/launcher/minecraft/WorldList.cpp @@ -309,11 +309,7 @@ class WorldMimeData : public QMimeData { QStringList formats() const { return QMimeData::formats() << "text/uri-list"; } protected: -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) QVariant retrieveData(const QString& mimetype, QMetaType type) const -#else - QVariant retrieveData(const QString& mimetype, QVariant::Type type) const -#endif { QList urls; for (auto& world : m_worlds) { diff --git a/launcher/minecraft/auth/MinecraftAccount.cpp b/launcher/minecraft/auth/MinecraftAccount.cpp index 1ed39b5ca..1613a42b1 100644 --- a/launcher/minecraft/auth/MinecraftAccount.cpp +++ b/launcher/minecraft/auth/MinecraftAccount.cpp @@ -106,11 +106,7 @@ QPixmap MinecraftAccount::getFace() const return QPixmap(); } QPixmap skin = QPixmap(8, 8); -#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) skin.fill(QColorConstants::Transparent); -#else - skin.fill(QColor(0, 0, 0, 0)); -#endif QPainter painter(&skin); painter.drawPixmap(0, 0, skinTexture.copy(8, 8, 8, 8)); painter.drawPixmap(0, 0, skinTexture.copy(40, 8, 8, 8)); @@ -290,13 +286,8 @@ QUuid MinecraftAccount::uuidFromUsername(QString username) // basically a reimplementation of Java's UUID#nameUUIDFromBytes QByteArray digest = QCryptographicHash::hash(input, QCryptographicHash::Md5); -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - auto bOr = [](QByteArray& array, int index, char value) { array[index] = array.at(index) | value; }; - auto bAnd = [](QByteArray& array, int index, char value) { array[index] = array.at(index) & value; }; -#else auto bOr = [](QByteArray& array, qsizetype index, char value) { array[index] |= value; }; auto bAnd = [](QByteArray& array, qsizetype index, char value) { array[index] &= value; }; -#endif bAnd(digest, 6, (char)0x0f); // clear version bOr(digest, 6, (char)0x30); // set to version 3 bAnd(digest, 8, (char)0x3f); // clear variant diff --git a/launcher/minecraft/auth/Parsers.cpp b/launcher/minecraft/auth/Parsers.cpp index f9d89baa2..de1ffda86 100644 --- a/launcher/minecraft/auth/Parsers.cpp +++ b/launcher/minecraft/auth/Parsers.cpp @@ -315,11 +315,7 @@ bool parseMinecraftProfileMojang(QByteArray& data, MinecraftProfile& output) auto value = pObj.value("value"); if (value.isString()) { -#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) texturePayload = QByteArray::fromBase64(value.toString().toUtf8(), QByteArray::AbortOnBase64DecodingErrors); -#else - texturePayload = QByteArray::fromBase64(value.toString().toUtf8()); -#endif } if (!texturePayload.isEmpty()) { diff --git a/launcher/minecraft/auth/steps/MSAStep.cpp b/launcher/minecraft/auth/steps/MSAStep.cpp index 87a0f8f08..aa972be71 100644 --- a/launcher/minecraft/auth/steps/MSAStep.cpp +++ b/launcher/minecraft/auth/steps/MSAStep.cpp @@ -168,13 +168,8 @@ void MSAStep::perform() m_oauth2.setRefreshToken(m_data->msaToken.refresh_token); m_oauth2.refreshAccessToken(); } else { -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) // QMultiMap param changed in 6.0 m_oauth2.setModifyParametersFunction( [](QAbstractOAuth::Stage stage, QMultiMap* map) { map->insert("prompt", "select_account"); }); -#else - m_oauth2.setModifyParametersFunction( - [](QAbstractOAuth::Stage stage, QMap* map) { map->insert("prompt", "select_account"); }); -#endif *m_data = AccountData(); m_data->msaClientID = m_clientId; @@ -182,4 +177,4 @@ void MSAStep::perform() } } -#include "MSAStep.moc" \ No newline at end of file +#include "MSAStep.moc" diff --git a/launcher/minecraft/mod/ResourceFolderModel.cpp b/launcher/minecraft/mod/ResourceFolderModel.cpp index 5f4748b92..bf40c81d7 100644 --- a/launcher/minecraft/mod/ResourceFolderModel.cpp +++ b/launcher/minecraft/mod/ResourceFolderModel.cpp @@ -363,16 +363,11 @@ void ResourceFolderModel::onUpdateSucceeded() auto& new_resources = update_results->resources; -#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) auto current_list = m_resources_index.keys(); QSet current_set(current_list.begin(), current_list.end()); auto new_list = new_resources.keys(); QSet new_set(new_list.begin(), new_list.end()); -#else - QSet current_set(m_resources_index.keys().toSet()); - QSet new_set(new_resources.keys().toSet()); -#endif applyUpdates(current_set, new_set, new_resources); } diff --git a/launcher/modplatform/atlauncher/ATLPackInstallTask.cpp b/launcher/modplatform/atlauncher/ATLPackInstallTask.cpp index a0898edbd..a9706a768 100644 --- a/launcher/modplatform/atlauncher/ATLPackInstallTask.cpp +++ b/launcher/modplatform/atlauncher/ATLPackInstallTask.cpp @@ -678,13 +678,8 @@ void PackInstallTask::extractConfigs() return; } -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) m_extractFuture = QtConcurrent::run(QThreadPool::globalInstance(), QOverload::of(MMCZip::extractDir), archivePath, extractDir.absolutePath() + "/minecraft"); -#else - m_extractFuture = - QtConcurrent::run(QThreadPool::globalInstance(), MMCZip::extractDir, archivePath, extractDir.absolutePath() + "/minecraft"); -#endif connect(&m_extractFutureWatcher, &QFutureWatcher::finished, this, [this]() { downloadMods(); }); connect(&m_extractFutureWatcher, &QFutureWatcher::canceled, this, [this]() { emitAborted(); }); m_extractFutureWatcher.setFuture(m_extractFuture); @@ -897,13 +892,8 @@ void PackInstallTask::onModsDownloaded() jobPtr.reset(); if (!modsToExtract.empty() || !modsToDecomp.empty() || !modsToCopy.empty()) { -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) m_modExtractFuture = QtConcurrent::run(QThreadPool::globalInstance(), &PackInstallTask::extractMods, this, modsToExtract, modsToDecomp, modsToCopy); -#else - m_modExtractFuture = - QtConcurrent::run(QThreadPool::globalInstance(), this, &PackInstallTask::extractMods, modsToExtract, modsToDecomp, modsToCopy); -#endif connect(&m_modExtractFutureWatcher, &QFutureWatcher::finished, this, &PackInstallTask::onModsExtracted); connect(&m_modExtractFutureWatcher, &QFutureWatcher::canceled, this, &PackInstallTask::emitAborted); m_modExtractFutureWatcher.setFuture(m_modExtractFuture); diff --git a/launcher/modplatform/legacy_ftb/PackFetchTask.cpp b/launcher/modplatform/legacy_ftb/PackFetchTask.cpp index a0beeddcc..aea9cefad 100644 --- a/launcher/modplatform/legacy_ftb/PackFetchTask.cpp +++ b/launcher/modplatform/legacy_ftb/PackFetchTask.cpp @@ -79,7 +79,7 @@ void PackFetchTask::fetchPrivate(const QStringList& toFetch) QObject::connect(job, &NetJob::succeeded, this, [this, job, data, packCode] { ModpackList packs; parseAndAddPacks(*data, PackType::Private, packs); - foreach (Modpack currentPack, packs) { + for (auto& currentPack : packs) { currentPack.packCode = packCode; emit privateFileDownloadFinished(currentPack); } diff --git a/launcher/modplatform/legacy_ftb/PackInstallTask.cpp b/launcher/modplatform/legacy_ftb/PackInstallTask.cpp index c04c0b2f3..2b9bd127a 100644 --- a/launcher/modplatform/legacy_ftb/PackInstallTask.cpp +++ b/launcher/modplatform/legacy_ftb/PackInstallTask.cpp @@ -108,13 +108,8 @@ void PackInstallTask::unzip() return; } -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) m_extractFuture = QtConcurrent::run(QThreadPool::globalInstance(), QOverload::of(MMCZip::extractDir), archivePath, extractDir.absolutePath() + "/unzip"); -#else - m_extractFuture = - QtConcurrent::run(QThreadPool::globalInstance(), MMCZip::extractDir, archivePath, extractDir.absolutePath() + "/unzip"); -#endif connect(&m_extractFutureWatcher, &QFutureWatcher::finished, this, &PackInstallTask::onUnzipFinished); connect(&m_extractFutureWatcher, &QFutureWatcher::canceled, this, &PackInstallTask::onUnzipCanceled); m_extractFutureWatcher.setFuture(m_extractFuture); @@ -165,7 +160,7 @@ void PackInstallTask::install() // we only care about the libs QJsonArray libs = doc.object().value("libraries").toArray(); - foreach (const QJsonValue& value, libs) { + for (const auto& value : libs) { QString nameValue = value.toObject().value("name").toString(); if (!nameValue.startsWith("net.minecraftforge")) { continue; diff --git a/launcher/modplatform/legacy_ftb/PrivatePackManager.cpp b/launcher/modplatform/legacy_ftb/PrivatePackManager.cpp index 2ae351329..17e9f7d76 100644 --- a/launcher/modplatform/legacy_ftb/PrivatePackManager.cpp +++ b/launcher/modplatform/legacy_ftb/PrivatePackManager.cpp @@ -44,12 +44,8 @@ namespace LegacyFTB { void PrivatePackManager::load() { try { -#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) auto foo = QString::fromUtf8(FS::read(m_filename)).split('\n', Qt::SkipEmptyParts); currentPacks = QSet(foo.begin(), foo.end()); -#else - currentPacks = QString::fromUtf8(FS::read(m_filename)).split('\n', QString::SkipEmptyParts).toSet(); -#endif dirty = false; } catch (...) { diff --git a/launcher/net/NetRequest.cpp b/launcher/net/NetRequest.cpp index 310653508..ef533f599 100644 --- a/launcher/net/NetRequest.cpp +++ b/launcher/net/NetRequest.cpp @@ -104,12 +104,10 @@ void NetRequest::executeTask() header_proxy->writeHeaders(request); } -#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) #if defined(LAUNCHER_APPLICATION) request.setTransferTimeout(APPLICATION->settings()->get("RequestTimeout").toInt() * 1000); #else request.setTransferTimeout(); -#endif #endif m_last_progress_time = m_clock.now(); @@ -122,11 +120,7 @@ void NetRequest::executeTask() connect(rep, &QNetworkReply::uploadProgress, this, &NetRequest::onProgress); connect(rep, &QNetworkReply::downloadProgress, this, &NetRequest::onProgress); connect(rep, &QNetworkReply::finished, this, &NetRequest::downloadFinished); -#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) // QNetworkReply::errorOccurred added in 5.15 connect(rep, &QNetworkReply::errorOccurred, this, &NetRequest::downloadError); -#else - connect(rep, QOverload::of(&QNetworkReply::error), this, &NetRequest::downloadError); -#endif connect(rep, &QNetworkReply::sslErrors, this, &NetRequest::sslErrors); connect(rep, &QNetworkReply::readyRead, this, &NetRequest::downloadReadyRead); } @@ -323,11 +317,7 @@ auto NetRequest::abort() -> bool { m_state = State::AbortedByUser; if (m_reply) { -#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) // QNetworkReply::errorOccurred added in 5.15 disconnect(m_reply.get(), &QNetworkReply::errorOccurred, nullptr, nullptr); -#else - disconnect(m_reply.get(), QOverload::of(&QNetworkReply::error), nullptr, nullptr); -#endif m_reply->abort(); } return true; diff --git a/launcher/net/PasteUpload.cpp b/launcher/net/PasteUpload.cpp index c67d3b23c..86a44669e 100644 --- a/launcher/net/PasteUpload.cpp +++ b/launcher/net/PasteUpload.cpp @@ -130,11 +130,7 @@ void PasteUpload::executeTask() connect(rep, &QNetworkReply::uploadProgress, this, &Task::setProgress); connect(rep, &QNetworkReply::finished, this, &PasteUpload::downloadFinished); -#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) connect(rep, &QNetworkReply::errorOccurred, this, &PasteUpload::downloadError); -#else - connect(rep, QOverload::of(&QNetworkReply::error), this, &PasteUpload::downloadError); -#endif m_reply = std::shared_ptr(rep); diff --git a/launcher/translations/TranslationsModel.cpp b/launcher/translations/TranslationsModel.cpp index 429ead47d..e863dfef4 100644 --- a/launcher/translations/TranslationsModel.cpp +++ b/launcher/translations/TranslationsModel.cpp @@ -480,7 +480,7 @@ bool TranslationsModel::selectLanguage(QString key) bool successful = false; // FIXME: this is likely never present. FIX IT. d->m_qt_translator.reset(new QTranslator()); - if (d->m_qt_translator->load("qt_" + langCode, QLibraryInfo::location(QLibraryInfo::TranslationsPath))) { + if (d->m_qt_translator->load("qt_" + langCode, QLibraryInfo::path(QLibraryInfo::TranslationsPath))) { qDebug() << "Loading Qt Language File for" << langCode.toLocal8Bit().constData() << "..."; if (!QCoreApplication::installTranslator(d->m_qt_translator.get())) { qCritical() << "Loading Qt Language File failed."; diff --git a/launcher/ui/MainWindow.cpp b/launcher/ui/MainWindow.cpp index d8716b3ea..d190c6a02 100644 --- a/launcher/ui/MainWindow.cpp +++ b/launcher/ui/MainWindow.cpp @@ -721,7 +721,7 @@ void MainWindow::changeActiveAccount() QAction* sAction = (QAction*)sender(); // Profile's associated Mojang username - if (sAction->data().type() != QVariant::Type::Int) + if (sAction->data().typeId() != QMetaType::Int) return; QVariant action_data = sAction->data(); @@ -811,11 +811,7 @@ void MainWindow::updateNewsLabel() QList stringToIntList(const QString& string) { -#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) QStringList split = string.split(',', Qt::SkipEmptyParts); -#else - QStringList split = string.split(',', QString::SkipEmptyParts); -#endif QList out; for (int i = 0; i < split.size(); ++i) { out.append(split.at(i).toInt()); diff --git a/launcher/ui/dialogs/NewInstanceDialog.cpp b/launcher/ui/dialogs/NewInstanceDialog.cpp index d9ea0aafb..6036663ba 100644 --- a/launcher/ui/dialogs/NewInstanceDialog.cpp +++ b/launcher/ui/dialogs/NewInstanceDialog.cpp @@ -136,11 +136,7 @@ NewInstanceDialog::NewInstanceDialog(const QString& initialGroup, if (APPLICATION->settings()->get("NewInstanceGeometry").isValid()) { restoreGeometry(QByteArray::fromBase64(APPLICATION->settings()->get("NewInstanceGeometry").toByteArray())); } else { -#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) auto screen = parent->screen(); -#else - auto screen = QGuiApplication::primaryScreen(); -#endif auto geometry = screen->availableSize(); resize(width(), qMin(geometry.height() - 50, 710)); } diff --git a/launcher/ui/dialogs/skins/draw/SkinOpenGLWindow.cpp b/launcher/ui/dialogs/skins/draw/SkinOpenGLWindow.cpp index 97fe44175..e1e539050 100644 --- a/launcher/ui/dialogs/skins/draw/SkinOpenGLWindow.cpp +++ b/launcher/ui/dialogs/skins/draw/SkinOpenGLWindow.cpp @@ -76,8 +76,8 @@ void SkinOpenGLWindow::mousePressEvent(QMouseEvent* e) void SkinOpenGLWindow::mouseMoveEvent(QMouseEvent* event) { if (m_isMousePressed) { - int dx = event->x() - m_mousePosition.x(); - int dy = event->y() - m_mousePosition.y(); + int dx = event->position().x() - m_mousePosition.x(); + int dy = event->position().y() - m_mousePosition.y(); m_yaw += dx * 0.5f; m_pitch += dy * 0.5f; diff --git a/launcher/ui/instanceview/InstanceView.cpp b/launcher/ui/instanceview/InstanceView.cpp index c677f3951..f52c994d3 100644 --- a/launcher/ui/instanceview/InstanceView.cpp +++ b/launcher/ui/instanceview/InstanceView.cpp @@ -400,12 +400,8 @@ void InstanceView::mouseReleaseEvent(QMouseEvent* event) if (event->button() == Qt::LeftButton) { emit clicked(index); } -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) QStyleOptionViewItem option; initViewItemOption(&option); -#else - QStyleOptionViewItem option = viewOptions(); -#endif if (m_pressedAlreadySelected) { option.state |= QStyle::State_Selected; } @@ -422,7 +418,7 @@ void InstanceView::mouseDoubleClickEvent(QMouseEvent* event) QModelIndex index = indexAt(event->pos()); if (!index.isValid() || !(index.flags() & Qt::ItemIsEnabled) || (m_pressedIndex != index)) { - QMouseEvent me(QEvent::MouseButtonPress, event->localPos(), event->windowPos(), event->screenPos(), event->button(), + QMouseEvent me(QEvent::MouseButtonPress, event->position(), event->scenePosition(), event->globalPosition(), event->button(), event->buttons(), event->modifiers()); mousePressEvent(&me); return; @@ -431,12 +427,8 @@ void InstanceView::mouseDoubleClickEvent(QMouseEvent* event) QPersistentModelIndex persistent = index; emit doubleClicked(persistent); -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) QStyleOptionViewItem option; initViewItemOption(&option); -#else - QStyleOptionViewItem option = viewOptions(); -#endif if ((model()->flags(index) & Qt::ItemIsEnabled) && !style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, &option, this)) { emit activated(index); } @@ -472,12 +464,8 @@ void InstanceView::paintEvent([[maybe_unused]] QPaintEvent* event) painter.setOpacity(1.0); } -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) QStyleOptionViewItem option; initViewItemOption(&option); -#else - QStyleOptionViewItem option = viewOptions(); -#endif option.widget = this; if (model()->rowCount() == 0) { @@ -610,7 +598,7 @@ void InstanceView::dragEnterEvent(QDragEnterEvent* event) if (!isDragEventAccepted(event)) { return; } - m_lastDragPosition = event->pos() + offset(); + m_lastDragPosition = event->position().toPoint() + offset(); viewport()->update(); event->accept(); } @@ -622,7 +610,7 @@ void InstanceView::dragMoveEvent(QDragMoveEvent* event) if (!isDragEventAccepted(event)) { return; } - m_lastDragPosition = event->pos() + offset(); + m_lastDragPosition = event->position().toPoint() + offset(); viewport()->update(); event->accept(); } @@ -648,7 +636,7 @@ void InstanceView::dropEvent(QDropEvent* event) if (event->source() == this) { if (event->possibleActions() & Qt::MoveAction) { - std::pair dropPos = rowDropPos(event->pos()); + std::pair dropPos = rowDropPos(event->position().toPoint()); const VisualGroup* group = dropPos.first; auto hitResult = dropPos.second; @@ -732,12 +720,8 @@ QRect InstanceView::geometryRect(const QModelIndex& index) const int x = pos.first; // int y = pos.second; -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) QStyleOptionViewItem option; initViewItemOption(&option); -#else - QStyleOptionViewItem option = viewOptions(); -#endif QRect out; out.setTop(cat->verticalPosition() + cat->headerHeight() + 5 + cat->rowTopOf(index)); @@ -784,12 +768,8 @@ QPixmap InstanceView::renderToPixmap(const QModelIndexList& indices, QRect* r) c QPixmap pixmap(r->size()); pixmap.fill(Qt::transparent); QPainter painter(&pixmap); -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) QStyleOptionViewItem option; initViewItemOption(&option); -#else - QStyleOptionViewItem option = viewOptions(); -#endif option.state |= QStyle::State_Selected; for (int j = 0; j < paintPairs.count(); ++j) { option.rect = paintPairs.at(j).first.translated(-r->topLeft()); diff --git a/launcher/ui/instanceview/VisualGroup.cpp b/launcher/ui/instanceview/VisualGroup.cpp index 83103c502..089db8ad7 100644 --- a/launcher/ui/instanceview/VisualGroup.cpp +++ b/launcher/ui/instanceview/VisualGroup.cpp @@ -73,12 +73,8 @@ void VisualGroup::update() positionInRow = 0; maxRowHeight = 0; } -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) QStyleOptionViewItem viewItemOption; view->initViewItemOption(&viewItemOption); -#else - QStyleOptionViewItem viewItemOption = view->viewOptions(); -#endif auto itemHeight = view->itemDelegate()->sizeHint(viewItemOption, item).height(); if (itemHeight > maxRowHeight) { diff --git a/launcher/ui/pages/instance/OtherLogsPage.cpp b/launcher/ui/pages/instance/OtherLogsPage.cpp index 80a9c0fdc..7f2a72ea5 100644 --- a/launcher/ui/pages/instance/OtherLogsPage.cpp +++ b/launcher/ui/pages/instance/OtherLogsPage.cpp @@ -174,48 +174,6 @@ void OtherLogsPage::on_selectLogBox_currentIndexChanged(const int index) } } -class ReadLineAbstract { - public: - ReadLineAbstract(QFile* file) : m_file(file) - { - if (file->fileName().endsWith(".gz")) - m_gz = new GZipStream(file); - } - ~ReadLineAbstract() { delete m_gz; } - - QString readLine() - { - if (!m_gz) - return QString::fromUtf8(m_file->readLine()); - QString line; - for (;;) { - if (!m_decodedData.isEmpty()) { - int newlineIndex = m_decodedData.indexOf('\n'); - if (newlineIndex != -1) { - line += QString::fromUtf8(m_decodedData).left(newlineIndex); - m_decodedData.remove(0, newlineIndex + 1); - return line; - } - - line += QString::fromUtf8(m_decodedData); - m_decodedData.clear(); - } - - if (!m_gz->unzipBlockByBlock(m_decodedData)) { // If error occurs during unzipping - m_decodedData.clear(); - return QObject::tr("The content of the file(%1) could not be decoded.").arg(m_file->fileName()); - } - } - } - - bool done() { return m_gz ? m_decodedData.isEmpty() : m_file->atEnd(); } - - private: - QFile* m_file; - GZipStream* m_gz = nullptr; - QByteArray m_decodedData; -}; - void OtherLogsPage::on_btnReload_clicked() { if (m_currentFile.isEmpty()) { @@ -243,15 +201,9 @@ void OtherLogsPage::on_btnReload_clicked() showTooBig(); return; } - - ReadLineAbstract stream(&file); - - // Try to determine a level for each line - ui->text->clear(); - ui->text->setModel(nullptr); - m_model->clear(); - auto line = stream.readLine(); - while (!stream.done()) { // just read until the model is full or the file ended + auto handleLine = [this](QString line) { + if (line.isEmpty()) + return false; if (line.back() == '\n') line = line.remove(line.size() - 1, 1); MessageLevel::Enum level = MessageLevel::Unknown; @@ -268,10 +220,40 @@ void OtherLogsPage::on_btnReload_clicked() } m_model->append(level, line); - if (m_model->isOverFlow()) - break; + return m_model->isOverFlow(); + }; - line = stream.readLine(); + // Try to determine a level for each line + ui->text->clear(); + ui->text->setModel(nullptr); + m_model->clear(); + if (file.fileName().endsWith(".gz")) { + QString line; + auto error = GZip::readGzFileByBlocks(&file, [&line, handleLine](const QByteArray& d) { + auto block = d; + int newlineIndex = block.indexOf('\n'); + while (newlineIndex != -1) { + line += QString::fromUtf8(block).left(newlineIndex); + block.remove(0, newlineIndex + 1); + if (handleLine(line)) { + line.clear(); + return false; + } + line.clear(); + newlineIndex = block.indexOf('\n'); + } + line += QString::fromUtf8(block); + return true; + }); + if (!error.isEmpty()) { + setPlainText(tr("The file (%1) encountered an error when reading: %2.").arg(file.fileName(), error)); + return; + } else if (!line.isEmpty()) { + handleLine(line); + } + } else { + while (!file.atEnd() && !handleLine(QString::fromUtf8(file.readLine()))) { + } } ui->text->setModel(m_proxy); ui->text->scrollToBottom(); diff --git a/launcher/ui/pages/instance/ServersPage.cpp b/launcher/ui/pages/instance/ServersPage.cpp index f8cd8304f..245bbffe2 100644 --- a/launcher/ui/pages/instance/ServersPage.cpp +++ b/launcher/ui/pages/instance/ServersPage.cpp @@ -255,11 +255,7 @@ class ServersModel : public QAbstractListModel { return false; } beginMoveRows(QModelIndex(), row, row, QModelIndex(), row - 1); -#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) m_servers.swapItemsAt(row - 1, row); -#else - m_servers.swap(row - 1, row); -#endif endMoveRows(); scheduleSave(); return true; @@ -275,11 +271,7 @@ class ServersModel : public QAbstractListModel { return false; } beginMoveRows(QModelIndex(), row, row, QModelIndex(), row + 2); -#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) m_servers.swapItemsAt(row + 1, row); -#else - m_servers.swap(row + 1, row); -#endif endMoveRows(); scheduleSave(); return true; diff --git a/launcher/updater/prismupdater/PrismUpdater.cpp b/launcher/updater/prismupdater/PrismUpdater.cpp index f9ffeb658..365647db9 100644 --- a/launcher/updater/prismupdater/PrismUpdater.cpp +++ b/launcher/updater/prismupdater/PrismUpdater.cpp @@ -46,11 +46,8 @@ #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN #endif -#include -#include -#include #include -#include +#include "console/WindowsConsole.h" #endif #include @@ -87,112 +84,12 @@ void appDebugOutput(QtMsgType type, const QMessageLogContext& context, const QSt } } -#if defined Q_OS_WIN32 - -// taken from https://stackoverflow.com/a/25927081 -// getting a proper output to console with redirection support on windows is apparently hell -void BindCrtHandlesToStdHandles(bool bindStdIn, bool bindStdOut, bool bindStdErr) -{ - // Re-initialize the C runtime "FILE" handles with clean handles bound to "nul". We do this because it has been - // observed that the file number of our standard handle file objects can be assigned internally to a value of -2 - // when not bound to a valid target, which represents some kind of unknown internal invalid state. In this state our - // call to "_dup2" fails, as it specifically tests to ensure that the target file number isn't equal to this value - // before allowing the operation to continue. We can resolve this issue by first "re-opening" the target files to - // use the "nul" device, which will place them into a valid state, after which we can redirect them to our target - // using the "_dup2" function. - if (bindStdIn) { - FILE* dummyFile; - freopen_s(&dummyFile, "nul", "r", stdin); - } - if (bindStdOut) { - FILE* dummyFile; - freopen_s(&dummyFile, "nul", "w", stdout); - } - if (bindStdErr) { - FILE* dummyFile; - freopen_s(&dummyFile, "nul", "w", stderr); - } - - // Redirect unbuffered stdin from the current standard input handle - if (bindStdIn) { - HANDLE stdHandle = GetStdHandle(STD_INPUT_HANDLE); - if (stdHandle != INVALID_HANDLE_VALUE) { - int fileDescriptor = _open_osfhandle((intptr_t)stdHandle, _O_TEXT); - if (fileDescriptor != -1) { - FILE* file = _fdopen(fileDescriptor, "r"); - if (file != NULL) { - int dup2Result = _dup2(_fileno(file), _fileno(stdin)); - if (dup2Result == 0) { - setvbuf(stdin, NULL, _IONBF, 0); - } - } - } - } - } - - // Redirect unbuffered stdout to the current standard output handle - if (bindStdOut) { - HANDLE stdHandle = GetStdHandle(STD_OUTPUT_HANDLE); - if (stdHandle != INVALID_HANDLE_VALUE) { - int fileDescriptor = _open_osfhandle((intptr_t)stdHandle, _O_TEXT); - if (fileDescriptor != -1) { - FILE* file = _fdopen(fileDescriptor, "w"); - if (file != NULL) { - int dup2Result = _dup2(_fileno(file), _fileno(stdout)); - if (dup2Result == 0) { - setvbuf(stdout, NULL, _IONBF, 0); - } - } - } - } - } - - // Redirect unbuffered stderr to the current standard error handle - if (bindStdErr) { - HANDLE stdHandle = GetStdHandle(STD_ERROR_HANDLE); - if (stdHandle != INVALID_HANDLE_VALUE) { - int fileDescriptor = _open_osfhandle((intptr_t)stdHandle, _O_TEXT); - if (fileDescriptor != -1) { - FILE* file = _fdopen(fileDescriptor, "w"); - if (file != NULL) { - int dup2Result = _dup2(_fileno(file), _fileno(stderr)); - if (dup2Result == 0) { - setvbuf(stderr, NULL, _IONBF, 0); - } - } - } - } - } - - // Clear the error state for each of the C++ standard stream objects. We need to do this, as attempts to access the - // standard streams before they refer to a valid target will cause the iostream objects to enter an error state. In - // versions of Visual Studio after 2005, this seems to always occur during startup regardless of whether anything - // has been read from or written to the targets or not. - if (bindStdIn) { - std::wcin.clear(); - std::cin.clear(); - } - if (bindStdOut) { - std::wcout.clear(); - std::cout.clear(); - } - if (bindStdErr) { - std::wcerr.clear(); - std::cerr.clear(); - } -} -#endif - PrismUpdaterApp::PrismUpdaterApp(int& argc, char** argv) : QApplication(argc, argv) { #if defined Q_OS_WIN32 // attach the parent console if stdout not already captured - auto stdout_type = GetFileType(GetStdHandle(STD_OUTPUT_HANDLE)); - if (stdout_type == FILE_TYPE_CHAR || stdout_type == FILE_TYPE_UNKNOWN) { - if (AttachConsole(ATTACH_PARENT_PROCESS)) { - BindCrtHandlesToStdHandles(true, true, true); - consoleAttached = true; - } + if (AttachWindowsConsole()) { + consoleAttached = true; } #endif setOrganizationName(BuildConfig.LAUNCHER_NAME); diff --git a/libraries/LocalPeer/CMakeLists.txt b/libraries/LocalPeer/CMakeLists.txt index f6de6581c..dd78647c0 100644 --- a/libraries/LocalPeer/CMakeLists.txt +++ b/libraries/LocalPeer/CMakeLists.txt @@ -1,9 +1,7 @@ cmake_minimum_required(VERSION 3.15) project(LocalPeer) -if(QT_VERSION_MAJOR EQUAL 5) - find_package(Qt5 COMPONENTS Core Network REQUIRED) -elseif(Launcher_QT_VERSION_MAJOR EQUAL 6) +if(Launcher_QT_VERSION_MAJOR EQUAL 6) find_package(Qt6 COMPONENTS Core Network Core5Compat REQUIRED) list(APPEND LocalPeer_LIBS Qt${QT_VERSION_MAJOR}::Core5Compat) endif() diff --git a/libraries/LocalPeer/src/LocalPeer.cpp b/libraries/LocalPeer/src/LocalPeer.cpp index c1875bf98..3761c109e 100644 --- a/libraries/LocalPeer/src/LocalPeer.cpp +++ b/libraries/LocalPeer/src/LocalPeer.cpp @@ -75,7 +75,7 @@ ApplicationId ApplicationId::fromTraditionalApp() prefix.remove(QRegularExpression("[^a-zA-Z]")); prefix.truncate(6); QByteArray idc = protoId.toUtf8(); - quint16 idNum = qChecksum(idc.constData(), idc.size()); + quint16 idNum = qChecksum(idc); auto socketName = QLatin1String("pl") + prefix + QLatin1Char('-') + QString::number(idNum, 16).left(12); #if defined(Q_OS_WIN) if (!pProcessIdToSessionId) { diff --git a/libraries/launcher/org/prismlauncher/launcher/impl/StandardLauncher.java b/libraries/launcher/org/prismlauncher/launcher/impl/StandardLauncher.java index 084fbc849..968499ff6 100644 --- a/libraries/launcher/org/prismlauncher/launcher/impl/StandardLauncher.java +++ b/libraries/launcher/org/prismlauncher/launcher/impl/StandardLauncher.java @@ -97,6 +97,19 @@ public final class StandardLauncher extends AbstractLauncher { gameArgs.add(worldName); } + StringBuilder joinedGameArgs = new StringBuilder(); + for (String gameArg : gameArgs) { + if (joinedGameArgs.length() > 0) { + joinedGameArgs.append('\u001F'); // unit separator, designed for this purpose + } + joinedGameArgs.append(gameArg); + } + + // pass the real main class and game arguments in so mods can access them + System.setProperty("org.prismlauncher.launch.mainclass", mainClassName); + // unit separator ('\u001F') delimited list of game args + System.setProperty("org.prismlauncher.launch.gameargs", joinedGameArgs.toString()); + // find and invoke the main method MethodHandle method = ReflectionUtils.findMainMethod(mainClassName); method.invokeExact(gameArgs.toArray(new String[0])); diff --git a/libraries/qdcss/CMakeLists.txt b/libraries/qdcss/CMakeLists.txt index ab8aaef94..7e497feca 100644 --- a/libraries/qdcss/CMakeLists.txt +++ b/libraries/qdcss/CMakeLists.txt @@ -1,9 +1,7 @@ cmake_minimum_required(VERSION 3.15) project(qdcss) -if(QT_VERSION_MAJOR EQUAL 5) - find_package(Qt5 COMPONENTS Core REQUIRED) -elseif(Launcher_QT_VERSION_MAJOR EQUAL 6) +if(Launcher_QT_VERSION_MAJOR EQUAL 6) find_package(Qt6 COMPONENTS Core Core5Compat REQUIRED) list(APPEND qdcss_LIBS Qt${QT_VERSION_MAJOR}::Core5Compat) endif() diff --git a/libraries/rainbow/CMakeLists.txt b/libraries/rainbow/CMakeLists.txt index 0867b2d27..c971889d8 100644 --- a/libraries/rainbow/CMakeLists.txt +++ b/libraries/rainbow/CMakeLists.txt @@ -1,9 +1,7 @@ cmake_minimum_required(VERSION 3.15) project(rainbow) -if(QT_VERSION_MAJOR EQUAL 5) - find_package(Qt5 COMPONENTS Core Gui REQUIRED) -elseif(Launcher_QT_VERSION_MAJOR EQUAL 6) +if(Launcher_QT_VERSION_MAJOR EQUAL 6) find_package(Qt6 COMPONENTS Core Gui REQUIRED) endif() diff --git a/libraries/systeminfo/CMakeLists.txt b/libraries/systeminfo/CMakeLists.txt index 33d246050..80b6b8094 100644 --- a/libraries/systeminfo/CMakeLists.txt +++ b/libraries/systeminfo/CMakeLists.txt @@ -1,8 +1,6 @@ project(systeminfo) -if(QT_VERSION_MAJOR EQUAL 5) - find_package(Qt5 COMPONENTS Core REQUIRED) -elseif(Launcher_QT_VERSION_MAJOR EQUAL 6) +if(Launcher_QT_VERSION_MAJOR EQUAL 6) find_package(Qt6 COMPONENTS Core Core5Compat REQUIRED) list(APPEND systeminfo_LIBS Qt${QT_VERSION_MAJOR}::Core5Compat) endif() diff --git a/libraries/systeminfo/src/distroutils.cpp b/libraries/systeminfo/src/distroutils.cpp index 57e6c8320..5891282fe 100644 --- a/libraries/systeminfo/src/distroutils.cpp +++ b/libraries/systeminfo/src/distroutils.cpp @@ -145,11 +145,7 @@ void Sys::lsb_postprocess(Sys::LsbInfo& lsb, Sys::DistributionInfo& out) vers = lsb.codename; } else { // ubuntu, debian, gentoo, scientific, slackware, ... ? -#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) auto parts = dist.split(QRegularExpression("\\s+"), Qt::SkipEmptyParts); -#else - auto parts = dist.split(QRegularExpression("\\s+"), QString::SkipEmptyParts); -#endif if (parts.size()) { dist = parts[0]; } @@ -182,11 +178,7 @@ QString Sys::_extract_distribution(const QString& x) if (release.startsWith("suse linux enterprise")) { return "sles"; } -#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) QStringList list = release.split(QRegularExpression("\\s+"), Qt::SkipEmptyParts); -#else - QStringList list = release.split(QRegularExpression("\\s+"), QString::SkipEmptyParts); -#endif if (list.size()) { return list[0]; } @@ -196,11 +188,7 @@ QString Sys::_extract_distribution(const QString& x) QString Sys::_extract_version(const QString& x) { QRegularExpression versionish_string(QRegularExpression::anchoredPattern("\\d+(?:\\.\\d+)*$")); -#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0) QStringList list = x.split(QRegularExpression("\\s+"), Qt::SkipEmptyParts); -#else - QStringList list = x.split(QRegularExpression("\\s+"), QString::SkipEmptyParts); -#endif for (int i = list.size() - 1; i >= 0; --i) { QString chunk = list[i]; if (versionish_string.match(chunk).hasMatch()) { diff --git a/nix/unwrapped.nix b/nix/unwrapped.nix index 060518242..b5b02b101 100644 --- a/nix/unwrapped.nix +++ b/nix/unwrapped.nix @@ -98,9 +98,6 @@ stdenv.mkDerivation { ++ lib.optionals (msaClientID != null) [ (lib.cmakeFeature "Launcher_MSA_CLIENT_ID" (toString msaClientID)) ] - ++ lib.optionals (lib.versionOlder kdePackages.qtbase.version "6") [ - (lib.cmakeFeature "Launcher_QT_VERSION_MAJOR" "5") - ] ++ lib.optionals stdenv.hostPlatform.isDarwin [ # we wrap our binary manually (lib.cmakeFeature "INSTALL_BUNDLE" "nodeps") diff --git a/shell.nix b/shell.nix new file mode 100644 index 000000000..21bab1009 --- /dev/null +++ b/shell.nix @@ -0,0 +1,4 @@ +(import (fetchTarball { + url = "https://github.com/edolstra/flake-compat/archive/ff81ac966bb2cae68946d5ed5fc4994f96d0ffec.tar.gz"; + sha256 = "sha256-NeCCThCEP3eCl2l/+27kNNK7QrwZB1IJCrXfrbv5oqU="; +}) { src = ./.; }).shellNix