diff --git a/.github/workflows/aur.yml b/.github/workflows/aur.yml index af296fc..431beb6 100644 --- a/.github/workflows/aur.yml +++ b/.github/workflows/aur.yml @@ -1,8 +1,6 @@ -name: Publish AUR packages +name: Check AUR packages on: - push: - branches: [main] workflow_dispatch: permissions: @@ -13,8 +11,8 @@ concurrency: cancel-in-progress: true jobs: - publish: - name: Publish AUR packages + metadata: + name: Refresh AUR metadata runs-on: ubuntu-24.04 timeout-minutes: 15 steps: @@ -27,10 +25,9 @@ jobs: shell: bash run: | set -Eeuo pipefail - package_dir="$GITHUB_WORKSPACE/packaging/aur/mocktail-git" - version="$(sed -n \ - 's/^[[:space:]]*VERSION[[:space:]]\+\([0-9][0-9.]*\).*/\1/p' \ - CMakeLists.txt | head -n 1)" + package_dir="$GITHUB_WORKSPACE/packaging/aur/nightcap-git" + version="$(git describe --tags --abbrev=0 --match='v[0-9]*')" + version="${version#v}" [[ "$version" =~ ^[0-9]+(\.[0-9]+)*$ ]] pkgver="${version}.r$(git rev-list --count HEAD).g$(git rev-parse --short=7 HEAD)" sed -i "s/^pkgver=.*/pkgver=${pkgver}/" "$package_dir/PKGBUILD" @@ -39,76 +36,21 @@ jobs: --volume "$package_dir:/pkg" \ archlinux:base-devel bash -Eeuo pipefail -c ' useradd --create-home builder - install -d -o builder -g builder /tmp/mocktail-git + install -d -o builder -g builder /tmp/nightcap-git install -o builder -g builder -m 0644 \ - /pkg/PKGBUILD /tmp/mocktail-git/PKGBUILD + /pkg/PKGBUILD /tmp/nightcap-git/PKGBUILD runuser -u builder -- bash -c \ - "cd /tmp/mocktail-git && makepkg --printsrcinfo" \ + "cd /tmp/nightcap-git && makepkg --printsrcinfo" \ > /pkg/.SRCINFO ' grep -Fqx "pkgver=${pkgver}" "$package_dir/PKGBUILD" grep -Fqx $'\tpkgver = '"${pkgver}" "$package_dir/.SRCINFO" - printf 'AUR_PKGVER=%s\n' "$pkgver" >> "$GITHUB_ENV" - - name: Publish to the AUR - shell: bash - env: - AUR_SSH_PRIVATE_KEY: ${{ secrets.AUR_SSH_PRIVATE_KEY }} - AUR_SSH_KEY_PASSPHRASE: ${{ secrets.AUR_SSH_KEY_PASSPHRASE }} - run: | - set -Eeuo pipefail - [[ -n "$AUR_SSH_PRIVATE_KEY" ]] - [[ -n "$AUR_SSH_KEY_PASSPHRASE" ]] - - private_key="$RUNNER_TEMP/aur_ed25519" - askpass="$RUNNER_TEMP/aur_askpass" - known_hosts="$RUNNER_TEMP/aur_known_hosts" - printf '%s\n' "$AUR_SSH_PRIVATE_KEY" > "$private_key" - unset AUR_SSH_PRIVATE_KEY - chmod 0600 "$private_key" - printf '%s\n' \ - '#!/usr/bin/env bash' \ - 'printf '\''%s\n'\'' "$AUR_SSH_KEY_PASSPHRASE"' \ - > "$askpass" - chmod 0700 "$askpass" - eval "$(ssh-agent -s)" - trap 'ssh-agent -k >/dev/null; rm -f -- "$private_key" "$askpass"' EXIT - DISPLAY=:0 SSH_ASKPASS="$askpass" SSH_ASKPASS_REQUIRE=force \ - ssh-add "$private_key" "$known_hosts" - fingerprint="$(ssh-keygen -lf "$known_hosts" -E sha256 | awk '{print $2}')" - [[ "$fingerprint" == \ - 'SHA256:RFzBCUItH9LZS0cKB5UE6ceAYhBD5C8GeOBip8Z11+4' ]] - - export GIT_SSH_COMMAND="ssh -F /dev/null -i $private_key \ - -o BatchMode=yes -o IdentitiesOnly=yes \ - -o StrictHostKeyChecking=yes \ - -o UserKnownHostsFile=$known_hosts" - publish_aur_package() { - local package_name="$1" - local commit_message="$2" - local source_dir="packaging/aur/$package_name" - local aur_dir="$RUNNER_TEMP/${package_name}-aur" - - git clone --branch master --single-branch \ - "ssh://aur@aur.archlinux.org/${package_name}.git" "$aur_dir" - install -m 0644 "$source_dir/PKGBUILD" "$aur_dir/PKGBUILD" - install -m 0644 "$source_dir/.SRCINFO" "$aur_dir/.SRCINFO" - - git -C "$aur_dir" config user.name komaruworld - git -C "$aur_dir" config user.email rtysus228@gmail.com - git -C "$aur_dir" add PKGBUILD .SRCINFO - if git -C "$aur_dir" diff --cached --quiet; then - printf '%s is already published\n' "$package_name" - return - fi - git -C "$aur_dir" commit -m "$commit_message" - git -C "$aur_dir" push origin HEAD:master - } - - publish_aur_package mocktail-git "Update to ${AUR_PKGVER}" - publish_aur_package mocktail 'make builds stable' - publish_aur_package mocktail-bin 'make builds stable' + - name: Upload AUR metadata + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: Nightcap-AUR + path: packaging/aur/nightcap-git/.SRCINFO + if-no-files-found: error + retention-days: 14 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index abb57dc..feacf6a 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -126,10 +126,153 @@ jobs: if-no-files-found: error retention-days: 14 + deb: + name: DEB (Ubuntu 26.04) + runs-on: ubuntu-24.04 + timeout-minutes: 45 + steps: + - name: Check out source + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 0 + submodules: recursive + + - name: Build DEB + shell: bash + run: | + set -Eeuo pipefail + docker run --rm \ + --volume "$GITHUB_WORKSPACE:/workspace" \ + --workdir /workspace \ + --env MOCKTAIL_PACKAGE_VERSION="$(./scripts/package_version.sh)" \ + ubuntu:26.04 bash -Eeuo pipefail -c ' + export DEBIAN_FRONTEND=noninteractive + apt-get update + apt-get install --yes --no-install-recommends \ + build-essential cmake git ninja-build pkg-config lld fakeroot \ + dpkg-dev file libsdl3-dev libsdl3-ttf-dev \ + libcurl4-openssl-dev libssl-dev nlohmann-json3-dev \ + libyaml-dev libelf-dev libminizip-dev libcapstone-dev \ + libgtk-4-dev libadwaita-1-dev libwebkitgtk-6.0-dev \ + libutf8proc-dev libfontconfig1-dev libegl-dev \ + libvulkan-dev libplacebo-dev zlib1g-dev libpng-dev + cmake -S . -B build-deb -G Ninja \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=/usr \ + -DMOCKTAIL_PACKAGE_NAME=nightcap \ + -DMOCKTAIL_PACKAGE_VERSION="$MOCKTAIL_PACKAGE_VERSION" \ + -DBUILD_TESTING=OFF + cmake --build build-deb --parallel 4 + cpack --config build-deb/CPackConfig.cmake \ + -G DEB -B dist/deb + dpkg-deb --info dist/deb/*.deb >/dev/null + ' + + - name: Upload DEB + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: Nightcap-DEB + path: dist/deb/*.deb + if-no-files-found: error + retention-days: 14 + + rpm: + name: RPM (Fedora 44) + runs-on: ubuntu-24.04 + timeout-minutes: 45 + steps: + - name: Check out source + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 0 + submodules: recursive + + - name: Build RPM + shell: bash + run: | + set -Eeuo pipefail + docker run --rm \ + --volume "$GITHUB_WORKSPACE:/workspace" \ + --workdir /workspace \ + --env MOCKTAIL_PACKAGE_VERSION="$(./scripts/package_version.sh)" \ + fedora:44 bash -Eeuo pipefail -c ' + dnf install --assumeyes \ + gcc-c++ cmake git ninja-build pkgconf-pkg-config lld rpm-build \ + SDL3-devel SDL3_ttf-devel libcurl-devel openssl-devel \ + nlohmann-json-devel libyaml-devel elfutils-libelf-devel \ + minizip-ng-compat-devel capstone-devel gtk4-devel libadwaita-devel \ + webkitgtk6.0-devel utf8proc-devel fontconfig-devel \ + libglvnd-devel vulkan-headers vulkan-loader-devel \ + libplacebo-devel zlib-ng-compat-devel libpng-devel + cmake -S . -B build-rpm -G Ninja \ + -DCMAKE_BUILD_TYPE=Release \ + -DCMAKE_INSTALL_PREFIX=/usr \ + -DCMAKE_INSTALL_LIBDIR=lib \ + -DMOCKTAIL_PACKAGE_NAME=nightcap \ + -DMOCKTAIL_PACKAGE_VERSION="$MOCKTAIL_PACKAGE_VERSION" \ + -DBUILD_TESTING=OFF + cmake --build build-rpm --parallel 4 + cpack --config build-rpm/CPackConfig.cmake \ + -G RPM -B dist/rpm + rpm --query --package --info dist/rpm/*.rpm >/dev/null + ' + + - name: Upload RPM + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: Nightcap-RPM + path: dist/rpm/*.rpm + if-no-files-found: error + retention-days: 14 + + arch: + name: Pacman package (Arch Linux) + runs-on: ubuntu-24.04 + timeout-minutes: 45 + steps: + - name: Check out source + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 0 + submodules: recursive + + - name: Build pacman package + shell: bash + run: | + set -Eeuo pipefail + version="$(./scripts/package_version.sh)" + sed -i "s/^pkgver=.*/pkgver=${version}/" packaging/arch/PKGBUILD + docker run --rm \ + --volume "$GITHUB_WORKSPACE:/workspace" \ + --workdir /workspace \ + ghcr.io/archlinux/archlinux:base-devel@sha256:c3953446016873a756fb7814f10087cac1634c127f7302e80c81c512da796d05 bash -Eeuo pipefail -c ' + pacman -Syu --needed --noconfirm \ + cmake git ninja pkgconf lld sdl3 sdl3_ttf curl openssl \ + nlohmann-json libyaml libelf minizip capstone gtk4 \ + libadwaita webkitgtk-6.0 libutf8proc fontconfig libpng \ + libplacebo vulkan-headers vulkan-icd-loader libglvnd zlib + useradd --create-home builder + chown -R builder:builder /workspace + runuser -u builder -- env MOCKTAIL_SOURCE_DIR=/workspace \ + makepkg --dir /workspace/packaging/arch \ + --noconfirm --cleanbuild --force + install -d dist/arch + cp packaging/arch/*.pkg.tar.zst dist/arch/ + pacman -Qp dist/arch/*.pkg.tar.zst >/dev/null + ' + + - name: Upload pacman package + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 + with: + name: Nightcap-Arch + path: dist/arch/*.pkg.tar.zst + if-no-files-found: error + retention-days: 14 + publish: name: Publish GitHub release if: startsWith(github.ref, 'refs/tags/v') - needs: [appimage] + needs: [appimage, deb, rpm, arch] runs-on: ubuntu-24.04 timeout-minutes: 15 permissions: @@ -138,6 +281,13 @@ jobs: - name: Check out source uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + - name: Download packages + uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 + with: + pattern: 'Nightcap-*' + merge-multiple: true + path: release + - name: Download AppImage uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: @@ -152,7 +302,28 @@ jobs: set -Eeuo pipefail tag="${GITHUB_REF_NAME}" mv release/Mocktail-x86_64.AppImage release/Nightcap-x86_64.AppImage - (cd release && sha256sum Nightcap-x86_64.AppImage > Nightcap-x86_64.AppImage.sha256) + # An unmatched glob would otherwise reach sha256sum and gh as its own + # literal text, so every package pattern has to match before upload. + shopt -s nullglob + assets=(Nightcap-x86_64.AppImage) + for glob in '*.deb' '*.rpm' '*.pkg.tar.zst'; do + matched=(release/$glob) + if [[ ${#matched[@]} -eq 0 ]]; then + echo "::error::no ${glob} package among the release artifacts" + exit 1 + fi + assets+=("${matched[@]#release/}") + done + uploads=() + for asset in "${assets[@]}"; do + uploads+=("release/$asset" "release/$asset.sha256") + done + ( + cd release + for asset in "${assets[@]}"; do + sha256sum "$asset" > "$asset.sha256" + done + ) ./scripts/release_notes.sh "$tag" > release/notes.md # The Flatpak workflow creates the same release; whichever job # arrives second sees "already exists" and continues. @@ -164,5 +335,4 @@ jobs: gh release edit "$tag" --repo "$GITHUB_REPOSITORY" \ --title "Nightcap $tag" --notes-file release/notes.md gh release upload "$tag" --repo "$GITHUB_REPOSITORY" --clobber \ - release/Nightcap-x86_64.AppImage \ - release/Nightcap-x86_64.AppImage.sha256 + "${uploads[@]}" diff --git a/.gitignore b/.gitignore index cfa7074..8c4c8a8 100644 --- a/.gitignore +++ b/.gitignore @@ -177,3 +177,6 @@ lsan.log* # Test fixtures !/third_party/mcpelauncher-linker/core/libziparchive/**/*.zip !/third_party/mcpelauncher-linker/core/libziparchive/**/*.apk + +# Working plans, not part of the shipped documentation +/docs/plans/ diff --git a/CHANGELOG.md b/CHANGELOG.md index 6a7afa1..e520eb4 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,61 @@ GitHub are taken from the matching section here. ## [Unreleased] +## [0.3.1] - 2026-09-20 + +### Added + +- Each release carries a DEB, an RPM, and a pacman package beside the + AppImage, with a `.sha256` for every file. They install `/usr/bin/mocktail` + and conflict with each other and with upstream's `mocktail` package. + Nightcap is in no distribution repository or the AUR; the recipes under + `packaging/aur/nightcap{,-bin,-git}` build from this repository locally. +- The AppStream metadata lists the Nightcap releases, so software centres + show the release history instead of upstream's. + +### Fixed + +- ETC2 texture decoding no longer blocks the thread that submits the frame. + Uploads decode on a background dispatcher and the submit carries a timeline + semaphore wait, so the GPU waits for the texture instead of the render + thread. Reading the application's compressed bytes moves to that dispatcher + too whenever they are already mapped. In Blade Ball the worst + `vkQueueSubmit` fell from 140ms to 1ms, its p99 from 4.9ms to 0.05ms, and + the total time spent in submits from 2534ms to 309ms. Frame interval is + unchanged: the remaining tail is the engine's own main-thread step. A device + without the `timelineSemaphore` feature decodes inline as before, as does a + submit whose `pNext` already sizes arrays by its semaphore counts. +- The mouse pointer jumped when a right-click camera drag ended, and drifted + to the viewport edge during one. The input router inferred pointer capture + from SDL reporting zero absolute coordinates, which holds on X11 but not on + Wayland, where the reported position accumulates the relative deltas and + leaves the window. Motion, button, and wheel events now carry the window's + relative mouse mode. The right-click camera fallback also only captures + inside an experience, so the cursor stays free over the app surface. +- Shutting the window down while an experience was starting or leaving could + free the pointer capture owner underneath the thread using it. Callers off + the SDL thread now hold a reference for the length of their call. +- The TextBox caret did not move when a trailing space was typed in a + single-line field. The final cluster rect SDL_ttf reports stops at the last + inked glyph, so the laid-out width is used there instead. Wrapped layouts + keep the clamp, because their width is the widest line rather than the last. +- Every TextBox keystroke re-ran `TTF_Init`, a fontconfig sort, six + `TTF_OpenFont` calls, and `TTF_Quit` on the render thread. The overlay holds + its opened fonts and reopens them only when the Roblox font or the point + size changes, keeping the current set when a reopen fails. Measured over 100 + rasters, 1.59ms to 0.12ms per keystroke. +- Staged ETC2 copies now carry an explicit host-write barrier. A queue + submission only makes host writes from before it visible to the device, and + an asynchronous decode writes after the submit, so without the barrier those + texels were not guaranteed to reach the copy that reads them. + +### Changed + +- `docs/PERFORMANCE.md` documents the GameMode settings to run with. A + `desiredgov=powersave` in `~/.config/gamemode.ini` overrides the packaged + `performance` default and clocks the CPU down for the whole session while + still reporting an active performance request. + ## [0.3.0] - 2026-09-18 ### Added @@ -135,7 +190,8 @@ First Nightcap release, forked from komaruworld/mocktail. - The AppImage build no longer fails on stale checksums for the slimmed Arch packages. -[Unreleased]: https://github.com/CoderDayton/nightcap/compare/v0.3.0...HEAD +[Unreleased]: https://github.com/CoderDayton/nightcap/compare/v0.3.1...HEAD +[0.3.1]: https://github.com/CoderDayton/nightcap/releases/tag/v0.3.1 [0.3.0]: https://github.com/CoderDayton/nightcap/releases/tag/v0.3.0 [0.2.0]: https://github.com/CoderDayton/nightcap/releases/tag/v0.2.0 [0.1.0]: https://github.com/CoderDayton/nightcap/releases/tag/v0.1.0 diff --git a/CMakeLists.txt b/CMakeLists.txt index 0df5b53..e70f30c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -786,23 +786,29 @@ install(CODE " endif() ") +set(MOCKTAIL_PACKAGE_NAMES mocktail mocktail-nightly nightcap nightcap-nightly) set(MOCKTAIL_PACKAGE_NAME "mocktail" CACHE STRING "Native package name" ) +set(MOCKTAIL_PACKAGE_VERSION "${PROJECT_VERSION}" CACHE STRING + "Native package version" +) set(MOCKTAIL_PACKAGE_VERSION_SUFFIX "" CACHE STRING "Native package version suffix" ) -if(NOT MOCKTAIL_PACKAGE_NAME STREQUAL "mocktail" AND - NOT MOCKTAIL_PACKAGE_NAME STREQUAL "mocktail-nightly") +if(NOT MOCKTAIL_PACKAGE_NAME IN_LIST MOCKTAIL_PACKAGE_NAMES) + string(JOIN ", " MOCKTAIL_PACKAGE_NAMES_TEXT ${MOCKTAIL_PACKAGE_NAMES}) message(FATAL_ERROR - "MOCKTAIL_PACKAGE_NAME must be mocktail or mocktail-nightly") + "MOCKTAIL_PACKAGE_NAME must be one of ${MOCKTAIL_PACKAGE_NAMES_TEXT}") endif() set(CPACK_PACKAGE_NAME "${MOCKTAIL_PACKAGE_NAME}") -set(CPACK_PACKAGE_VERSION "${PROJECT_VERSION}${MOCKTAIL_PACKAGE_VERSION_SUFFIX}") -set(CPACK_PACKAGE_VENDOR "Mocktail Project") -set(CPACK_PACKAGE_CONTACT "komaruworld ") -set(CPACK_PACKAGE_HOMEPAGE_URL "https://github.com/komaruworld/mocktail") +set(CPACK_PACKAGE_VERSION + "${MOCKTAIL_PACKAGE_VERSION}${MOCKTAIL_PACKAGE_VERSION_SUFFIX}" +) +set(CPACK_PACKAGE_VENDOR "Nightcap") +set(CPACK_PACKAGE_CONTACT "vii ") +set(CPACK_PACKAGE_HOMEPAGE_URL "https://github.com/CoderDayton/nightcap") set(CPACK_PACKAGE_DESCRIPTION_SUMMARY "${PROJECT_DESCRIPTION}") set(CPACK_PACKAGE_DESCRIPTION "Runs the Android x86-64 Roblox client on Linux." @@ -812,7 +818,7 @@ set(CPACK_PACKAGING_INSTALL_PREFIX "/usr") set(CPACK_STRIP_FILES TRUE) set(CPACK_DEBIAN_FILE_NAME DEB-DEFAULT) -set(CPACK_DEBIAN_PACKAGE_MAINTAINER "komaruworld ") +set(CPACK_DEBIAN_PACKAGE_MAINTAINER "vii ") set(CPACK_DEBIAN_PACKAGE_SECTION "games") set(CPACK_DEBIAN_PACKAGE_PRIORITY "optional") set(CPACK_DEBIAN_PACKAGE_SHLIBDEPS ON) @@ -822,15 +828,14 @@ set(CPACK_RPM_PACKAGE_LICENSE "Apache-2.0") set(CPACK_RPM_PACKAGE_GROUP "Amusements/Games") set(CPACK_RPM_PACKAGE_AUTOREQPROV ON) -if(MOCKTAIL_PACKAGE_NAME STREQUAL "mocktail-nightly") - set(CPACK_DEBIAN_PACKAGE_CONFLICTS "mocktail") - set(CPACK_DEBIAN_PACKAGE_REPLACES "mocktail") - set(CPACK_RPM_PACKAGE_CONFLICTS "mocktail") -else() - set(CPACK_DEBIAN_PACKAGE_CONFLICTS "mocktail-nightly") - set(CPACK_DEBIAN_PACKAGE_REPLACES "mocktail-nightly") - set(CPACK_RPM_PACKAGE_CONFLICTS "mocktail-nightly") -endif() +# Every variant installs the same /usr/bin/mocktail and /usr/share/mocktail, +# so only one of them can be present at a time. +set(MOCKTAIL_PACKAGE_SIBLINGS ${MOCKTAIL_PACKAGE_NAMES}) +list(REMOVE_ITEM MOCKTAIL_PACKAGE_SIBLINGS "${MOCKTAIL_PACKAGE_NAME}") +string(JOIN ", " MOCKTAIL_PACKAGE_CONFLICTS ${MOCKTAIL_PACKAGE_SIBLINGS}) +set(CPACK_DEBIAN_PACKAGE_CONFLICTS "${MOCKTAIL_PACKAGE_CONFLICTS}") +set(CPACK_DEBIAN_PACKAGE_REPLACES "${MOCKTAIL_PACKAGE_CONFLICTS}") +set(CPACK_RPM_PACKAGE_CONFLICTS "${MOCKTAIL_PACKAGE_CONFLICTS}") include(CPack) add_dependencies(mocktail all_stubs) diff --git a/README.md b/README.md index 3ac2d4f..6f6efa8 100644 --- a/README.md +++ b/README.md @@ -61,10 +61,24 @@ chmod +x Nightcap-x86_64.AppImage ./Nightcap-x86_64.AppImage ``` -Or build and install it from source using the steps under -[Building](#building). There are no AUR, DEB, or RPM packages of Nightcap. -Upstream ships those for unmodified Mocktail, see -[komaruworld/mocktail](https://github.com/komaruworld/mocktail#readme). +## Distribution packages + +Each release also carries a DEB, an RPM, and a pacman package, with a +`.sha256` beside every file on the +[releases page](https://github.com/CoderDayton/nightcap/releases/latest): + +```bash +sudo apt install ./nightcap_-1_amd64.deb +sudo dnf install ./nightcap--1.x86_64.rpm +sudo pacman -U nightcap--1-x86_64.pkg.tar.zst +``` + +They install `/usr/bin/mocktail`, so they conflict with upstream's `mocktail` +package. Nightcap is not in any distribution repository or the AUR; the +recipes under `packaging/aur` are kept for local builds only. + +Or build and install from source using the steps under +[Building](#building). ## How it works diff --git a/docs/BENCHMARKING.md b/docs/BENCHMARKING.md index f662383..3f84705 100644 --- a/docs/BENCHMARKING.md +++ b/docs/BENCHMARKING.md @@ -44,7 +44,8 @@ Each slice is named after the call it times, on the thread that made it. | `present` | `host present`: the host driver's present, nested inside the slice above | | | `wait` | `vkAcquireNextImageKHR`, `vkAcquireNextImage2KHR`, `vkWaitForFences`, `vkWaitSemaphores`, `vkWaitSemaphoresKHR`, `vkQueueWaitIdle`, `vkDeviceWaitIdle` | | | `submit` | `vkQueueSubmit`, `vkQueueSubmit2`, `vkQueueSubmit2KHR` | `submits` | -| `texture` | `etc2 decode`: CPU decode of ETC2 textures before a submit | `uploads`, `compressed_bytes`, `decoded_bytes` | +| `texture` | `etc2 decode`: CPU decode of ETC2 textures. On a device with a timeline semaphore this runs on the decode dispatcher, not the submitting thread | `uploads`, `compressed_bytes`, `decoded_bytes` | +| `texture` | `etc2 gather`: the part of an asynchronous upload that stays on the submitting thread. Absent when the decode ran inline | `uploads`, `compressed_bytes`, `decoded_bytes`, `ticket` | | `pipeline` | `vkCreateGraphicsPipelines`, `vkCreateComputePipelines` | `count`, `cache` (1 when a pipeline cache was passed), `result` | | `pipeline` | `vkCreateShaderModule` | `bytes`, `result` | | `pipeline` | `vkCreatePipelineCache` | `initial_bytes`, `result` | @@ -61,6 +62,17 @@ Run every scenario before and after the change, on the same build type Record `graphics.frame_rate_limit` and `graphics.vsync` in the pull request, because a frame cap hides frame time gains. +Record `~/.config/gamemode.ini` too, and do not change it between the before +and after runs. `desiredgov` there decides the CPU governor for the whole +session and therefore which engine pump mode is chosen, which moves process +CPU by more than most changes under test. See +[PERFORMANCE.md](PERFORMANCE.md). + +Frame interval p99 varies by 2 ms or more between identical runs, so a +difference that size is not a result. Three runs per scenario is the minimum +for any frame-time claim; slice totals for a specific subsystem are far less +noisy and can be read from fewer. + | Scenario | How to start | What to do | What it shows | | --- | --- | --- | --- | | Home screen, cold | `mocktail --profile home-cold.json` with an empty shader cache (below) | Wait 30 s on the home screen, exit | First-load stutter: `pipeline` and `texture` slices | diff --git a/docs/PERFORMANCE.md b/docs/PERFORMANCE.md index 6dcd951..fb7656c 100644 --- a/docs/PERFORMANCE.md +++ b/docs/PERFORMANCE.md @@ -27,20 +27,48 @@ request. If GameMode narrowed it, Nightcap ends the request and prints: ``` The trade is that GameMode's governor and priority boost go with it. To keep -those and lose only the pinning, turn pinning off for every game on the host: +those and lose only the pinning, turn pinning off for every game on the host. + +These are the settings to run with: ```ini # ~/.config/gamemode.ini +[general] +desiredgov=performance + [cpu] pin_cores=no park_cores=no ``` +`desiredgov` is the one to check first. The packaged default in +`/usr/share/gamemode/gamemode.ini` is already `performance`, but a value in +your own file replaces it, and `desiredgov=powersave` there means GameMode +clocks the CPU **down** for the whole session while still reporting +`[gamemode] performance request active`. The symptoms are a low CPU clock +under load, a GPU that never leaves its lower SM clocks, and the engine pump +falling back to `tpause` — which costs about 70% of a core instead of 3%, +because `sleep` is only chosen when the governor reads `performance`. On one +13900K host, correcting `powersave` to `performance` took the process from +177% CPU to 42% and the package from 70°C to 53-63°C, at the same frame rate. + GameMode reads `$XDG_CONFIG_HOME`, `/usr/share/gamemode` and `/etc`, in that order. It does not read anything under Nightcap's own config directory, so this file has to live in one of those three places. The daemon reads it when it starts, so restart it after editing: `systemctl --user restart gamemoded`. +Restarting the daemon drops the session of any game already running; relaunch +the game for new settings to apply to it. + +`gamemoded` is D-Bus activated through +`com.feralinteractive.GameMode.service`, so `systemctl --user stop gamemoded` +does not hold — the next client request starts it again within seconds. To +measure with GameMode genuinely off, mask it: + +```bash +systemctl --user mask gamemoded # and --unmask afterwards +``` + The governor switch runs through polkit. Debian and Ubuntu only allow it for members of the `gamemode` group; without that, the daemon's journal shows `cpugovctl set performance: Not authorized` and the governor stays put while @@ -59,9 +87,20 @@ to the affinity. `off` never contacts the daemon. To see which CPUs the process may use: ```bash -taskset -pc $(pgrep -x mocktail) +pid=$(pgrep -x Main) +for t in /proc/$pid/task/*; do taskset -pc "${t##*/}"; done ``` +Two traps here. The engine process reports its name as `Main`, not +`mocktail`; `pgrep -x mocktail` finds only the launcher, which sits near 0% +CPU and tells you nothing. And `taskset -p` reads one thread, not the whole +process, so a single call reports the main thread's mask and says nothing +about the workers — which is where the game's load actually is. + +For the same reason, `ps -L -o psr=` shows which core each thread is running +on right now, not which cores it is allowed on. On a hybrid CPU the scheduler +preferring P-cores for runnable work is normal and is not a mask. + ## The main-thread pump Roblox posts its per-frame main-thread step at a time of its own choosing, @@ -99,6 +138,13 @@ threads while textures load, which shows up as a burst rather than a steady load. The enlarged textures then stay in GPU memory for the session and cost extra sampling bandwidth on every frame that uses them. +That decode does not run on the thread that submits the frame. On a device +with a timeline semaphore, uploads decode on a background dispatcher and the +submit carries a semaphore wait, so the GPU waits for the texture instead of +the render thread. In the trace this is the `etc2 decode` slice on its own +thread, with only a negligible `etc2 gather` left on the submitting one. A +device without that feature decodes inline as before. + Set it to `1` to turn upscaling off: ```bash diff --git a/include/mocktail/graphics/vulkan_etc2_emulation.h b/include/mocktail/graphics/vulkan_etc2_emulation.h index 7b01817..a356021 100644 --- a/include/mocktail/graphics/vulkan_etc2_emulation.h +++ b/include/mocktail/graphics/vulkan_etc2_emulation.h @@ -47,6 +47,14 @@ inline constexpr std::uint32_t kSmallTextureMaxExtent = 64; inline constexpr std::uint32_t kDefaultSmallTextureUpscale = 4; std::uint32_t SmallTextureUpscale(const char* value); +// A timeline semaphore and the value an asynchronous decode will signal. +// `semaphore` is VK_NULL_HANDLE when the decode already finished on the +// calling thread and the submit needs no extra wait. +struct Etc2SubmitWait { + VkSemaphore semaphore = VK_NULL_HANDLE; + std::uint64_t value = 0; +}; + // Reports ETC2/EAC support on hosts without native ETC2 (desktop GPUs) and // stores those textures decoded. Images are created with the host format; // each staged upload into one is redirected to a host-visible staging buffer @@ -66,10 +74,14 @@ class VulkanEtc2Emulation final { bool PhysicalDeviceNeedsEmulation(VkPhysicalDevice physical_device, PFN_vkGetPhysicalDeviceFeatures host); + // `timeline_semaphore` states whether the device was created with the + // timelineSemaphore feature enabled. Without it every decode runs on the + // calling thread. void RegisterDevice(VkDevice device, VkPhysicalDevice physical_device, bool emulated, const VkPhysicalDeviceMemoryProperties& memory, - PFN_vkGetDeviceProcAddr get_device_proc_addr); + PFN_vkGetDeviceProcAddr get_device_proc_addr, + bool timeline_semaphore = false); void DestroyDevice(VkDevice device); VkResult CreateImage(VkDevice device, const VkImageCreateInfo* create_info, @@ -112,12 +124,27 @@ class VulkanEtc2Emulation final { const VkCommandBuffer* secondaries); // Decodes every upload recorded into these command buffers and the - // secondary command buffers they execute. Large batches decode on worker - // threads; this returns once every upload is decoded. - void PrepareSubmit(const VkCommandBuffer* command_buffers, - std::uint32_t count); + // secondary command buffers they execute. + // + // With `allow_async` on a device that has a timeline semaphore, the decode + // runs on worker threads, and so does the gather of the compressed bytes + // whenever the application already has them mapped. The returned semaphore + // and value must then be added to the submit's waits, so the GPU copy + // cannot execute before the decode finishes. Values are signalled in the + // order they are handed out. + // + // Those threads read the application's source bytes after this returns, + // which Vulkan allows: the application may not write them between the + // submit and the copy's completion. Unmapping or freeing that memory waits + // for the decodes still reading it. + // + // Returns `{VK_NULL_HANDLE, 0}` when there was nothing to decode, when + // `allow_async` is false, or when the device has no timeline semaphore. In + // those cases every upload is already decoded when this returns. + Etc2SubmitWait PrepareSubmit(const VkCommandBuffer* command_buffers, + std::uint32_t count, bool allow_async = false); // Destroys the staging buffers owned by a command buffer that is no longer - // pending. + // pending, after waiting for any decode still writing into them. void ReleaseCommandBuffer(VkCommandBuffer command_buffer); struct State; diff --git a/include/mocktail/platform/platform_runtime.h b/include/mocktail/platform/platform_runtime.h index 33c9d87..b1817d3 100644 --- a/include/mocktail/platform/platform_runtime.h +++ b/include/mocktail/platform/platform_runtime.h @@ -152,6 +152,10 @@ struct MouseMotionEvent { float delta_x = 0.0f; float delta_y = 0.0f; std::uint32_t buttons = 0; + // True while the window holds relative mouse mode. The absolute coordinates + // are meaningless then: X11 reports zeroes, Wayland reports a position that + // accumulates the deltas and can leave the window entirely. + bool relative = false; }; struct MouseButtonEvent { @@ -160,6 +164,8 @@ struct MouseButtonEvent { std::uint8_t clicks = 0; float x = 0.0f; float y = 0.0f; + // See MouseMotionEvent::relative. + bool relative = false; }; struct MouseWheelEvent { @@ -167,6 +173,8 @@ struct MouseWheelEvent { float delta_y = 0.0f; float mouse_x = 0.0f; float mouse_y = 0.0f; + // See MouseMotionEvent::relative. + bool relative = false; }; struct TouchEvent { diff --git a/include/runtime/roblox_text_surface_overlay.h b/include/runtime/roblox_text_surface_overlay.h index 6a6b0f4..1ce7879 100644 --- a/include/runtime/roblox_text_surface_overlay.h +++ b/include/runtime/roblox_text_surface_overlay.h @@ -11,6 +11,8 @@ #include "mocktail/status.h" #include "runtime/roblox_text_display_state.h" +struct TTF_Font; + namespace mocktail { namespace runtime { @@ -39,6 +41,8 @@ class RobloxTextSurfaceOverlay final { const RobloxTextDisplayUpdate& update); void ApplyUpdate(const RobloxTextDisplayUpdate& update); Status RasterizeLocked(); + Status OpenFontsLocked(std::int32_t font, float point_size); + void CloseFontsLocked(); void ClearFrameLocked(); void RecordFailureLocked(Status status); @@ -46,10 +50,14 @@ class RobloxTextSurfaceOverlay final { RobloxTextDisplayState state_; RobloxTextOverlayViewport viewport_; std::vector rgba_; + std::vector fonts_; + std::int32_t fonts_font_ = 0; + float fonts_point_size_ = 0.0F; std::uint64_t state_revision_ = 0; std::uint64_t raster_revision_ = 0; Status failure_; bool initialized_ = false; + bool ttf_initialized_ = false; bool failure_logged_ = false; bool ready_logged_ = false; }; diff --git a/packaging/arch/PKGBUILD b/packaging/arch/PKGBUILD index 57b0bbb..6284e50 100644 --- a/packaging/arch/PKGBUILD +++ b/packaging/arch/PKGBUILD @@ -1,12 +1,14 @@ -# Maintainer: komaruworld +# Maintainer: vii -pkgname=mocktail -pkgver=1.0.3 -pkgrel=2 +pkgname=nightcap +pkgver=0.3.1 +pkgrel=1 pkgdesc='Android x86-64 Roblox compatibility runtime for Linux' arch=('x86_64') -url='https://github.com/komaruworld/mocktail' +url='https://github.com/CoderDayton/nightcap' license=('Apache-2.0') +provides=('mocktail') +conflicts=('mocktail') depends=( 'capstone' 'curl' diff --git a/packaging/aur/mocktail-bin/.SRCINFO b/packaging/aur/nightcap-bin/.SRCINFO similarity index 64% rename from packaging/aur/mocktail-bin/.SRCINFO rename to packaging/aur/nightcap-bin/.SRCINFO index 5bcf3a1..7fd41dd 100644 --- a/packaging/aur/mocktail-bin/.SRCINFO +++ b/packaging/aur/nightcap-bin/.SRCINFO @@ -1,8 +1,8 @@ -pkgbase = mocktail-bin +pkgbase = nightcap-bin pkgdesc = Android x86-64 Roblox compatibility runtime for Linux (prebuilt) - pkgver = 1.0.4 + pkgver = 0.3.1 pkgrel = 1 - url = https://github.com/komaruworld/mocktail + url = https://github.com/CoderDayton/nightcap arch = x86_64 license = Apache-2.0 depends = capstone @@ -30,12 +30,14 @@ pkgbase = mocktail-bin depends = zlib optdepends = gamemode: Feral GameMode integration provides = mocktail + provides = nightcap conflicts = mocktail - conflicts = mocktail-git - noextract = mocktail-1.0.4-x86_64.pkg.tar.zst + conflicts = nightcap + conflicts = nightcap-git + noextract = nightcap-0.3.1-1-x86_64.pkg.tar.zst options = !debug options = !strip - source = mocktail-1.0.4-x86_64.pkg.tar.zst::https://github.com/komaruworld/mocktail/releases/download/1.0.4/mocktail-1.0.4-x86_64.pkg.tar.zst - sha256sums = d5cc7216e88fd2889369e8eb7fba4276b2746c2b084dce566aaaa7505bc2ffb7 + source = nightcap-0.3.1-1-x86_64.pkg.tar.zst::https://github.com/CoderDayton/nightcap/releases/download/v0.3.1/nightcap-0.3.1-1-x86_64.pkg.tar.zst + sha256sums = SKIP -pkgname = mocktail-bin +pkgname = nightcap-bin diff --git a/packaging/aur/mocktail-bin/PKGBUILD b/packaging/aur/nightcap-bin/PKGBUILD similarity index 53% rename from packaging/aur/mocktail-bin/PKGBUILD rename to packaging/aur/nightcap-bin/PKGBUILD index b6752d5..3695011 100644 --- a/packaging/aur/mocktail-bin/PKGBUILD +++ b/packaging/aur/nightcap-bin/PKGBUILD @@ -1,11 +1,11 @@ -# Maintainer: komaruworld +# Maintainer: vii -pkgname=mocktail-bin -pkgver=1.0.4 +pkgname=nightcap-bin +pkgver=0.3.1 pkgrel=1 pkgdesc='Android x86-64 Roblox compatibility runtime for Linux (prebuilt)' arch=('x86_64') -url='https://github.com/komaruworld/mocktail' +url='https://github.com/CoderDayton/nightcap' license=('Apache-2.0') depends=( 'capstone' @@ -33,17 +33,18 @@ depends=( 'zlib' ) optdepends=('gamemode: Feral GameMode integration') -provides=('mocktail') -conflicts=('mocktail' 'mocktail-git') +provides=('mocktail' 'nightcap') +conflicts=('mocktail' 'nightcap' 'nightcap-git') options=('!debug' '!strip') -# Release asset names do not include the AUR package release. -_archive="mocktail-${pkgver}-${CARCH}.pkg.tar.zst" -source=("${_archive}::https://github.com/komaruworld/mocktail/releases/download/${pkgver}/${_archive}") +# The release asset carries the pacman package release built by release.yml. +_archive="nightcap-${pkgver}-1-${CARCH}.pkg.tar.zst" +source=("${_archive}::https://github.com/CoderDayton/nightcap/releases/download/v${pkgver}/${_archive}") noextract=("${_archive}") -sha256sums=('d5cc7216e88fd2889369e8eb7fba4276b2746c2b084dce566aaaa7505bc2ffb7') +# Replace with the checksum published beside the release asset. +sha256sums=('SKIP') package() { bsdtar -xf "${srcdir}/${_archive}" -C "${pkgdir}" usr - install -Dm644 "${pkgdir}/usr/share/licenses/mocktail/LICENSE" \ + install -Dm644 "${pkgdir}/usr/share/licenses/nightcap/LICENSE" \ "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE" } diff --git a/packaging/aur/mocktail/.SRCINFO b/packaging/aur/nightcap-git/.SRCINFO similarity index 72% rename from packaging/aur/mocktail/.SRCINFO rename to packaging/aur/nightcap-git/.SRCINFO index 7088c55..339d54e 100644 --- a/packaging/aur/mocktail/.SRCINFO +++ b/packaging/aur/nightcap-git/.SRCINFO @@ -1,8 +1,8 @@ -pkgbase = mocktail +pkgbase = nightcap-git pkgdesc = Android x86-64 Roblox compatibility runtime for Linux - pkgver = 1.0.4 + pkgver = 0.3.1.r0.g0000000 pkgrel = 1 - url = https://github.com/komaruworld/mocktail + url = https://github.com/CoderDayton/nightcap arch = x86_64 license = Apache-2.0 makedepends = cmake>=3.20 @@ -36,11 +36,13 @@ pkgbase = mocktail depends = webkitgtk-6.0 depends = zlib optdepends = gamemode: Feral GameMode integration - conflicts = mocktail-bin - conflicts = mocktail-git + provides = mocktail + provides = nightcap + conflicts = mocktail + conflicts = nightcap + conflicts = nightcap-bin options = !debug - options = !lto - source = mocktail::git+https://github.com/komaruworld/mocktail.git#tag=1.0.4 + source = nightcap::git+https://github.com/CoderDayton/nightcap.git#branch=main sha256sums = SKIP -pkgname = mocktail +pkgname = nightcap-git diff --git a/packaging/aur/mocktail-git/PKGBUILD b/packaging/aur/nightcap-git/PKGBUILD similarity index 73% rename from packaging/aur/mocktail-git/PKGBUILD rename to packaging/aur/nightcap-git/PKGBUILD index 5856f82..c437798 100644 --- a/packaging/aur/mocktail-git/PKGBUILD +++ b/packaging/aur/nightcap-git/PKGBUILD @@ -1,11 +1,11 @@ -# Maintainer: komaruworld +# Maintainer: vii -pkgname=mocktail-git -pkgver=1.0.2.r24.g9bdd737 +pkgname=nightcap-git +pkgver=0.3.1.r0.g0000000 pkgrel=1 pkgdesc='Android x86-64 Roblox compatibility runtime for Linux' arch=('x86_64') -url='https://github.com/komaruworld/mocktail' +url='https://github.com/CoderDayton/nightcap' license=('Apache-2.0') depends=( 'capstone' @@ -42,31 +42,30 @@ makedepends=( 'vulkan-headers' ) optdepends=('gamemode: Feral GameMode integration') -provides=('mocktail') -conflicts=('mocktail' 'mocktail-bin') +provides=('mocktail' 'nightcap') +conflicts=('mocktail' 'nightcap' 'nightcap-bin') options=('!debug') source=( - 'mocktail::git+https://github.com/komaruworld/mocktail.git#branch=main' + 'nightcap::git+https://github.com/CoderDayton/nightcap.git#branch=main' ) sha256sums=( 'SKIP' ) pkgver() { - cd mocktail + cd nightcap local version - version="$(sed -n \ - 's/^[[:space:]]*VERSION[[:space:]]\+\([0-9][0-9.]*\).*/\1/p' \ - CMakeLists.txt | head -n 1)" + version="$(git describe --tags --abbrev=0 --match='v[0-9]*' 2>/dev/null)" + version="${version#v}" printf '%s.r%s.g%s' \ - "${version}" \ + "${version:-0.0.0}" \ "$(git rev-list --count HEAD)" \ "$(git rev-parse --short=7 HEAD)" } prepare() { - cd mocktail + cd nightcap sed -i \ 's|add_subdirectory(third_party/Vulkan-Headers EXCLUDE_FROM_ALL)|find_package(VulkanHeaders CONFIG REQUIRED)|' \ @@ -74,7 +73,7 @@ prepare() { } build() { - cmake -S mocktail -B build -G Ninja \ + cmake -S nightcap -B build -G Ninja \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX=/usr \ -DCMAKE_INSTALL_LIBDIR=lib \ @@ -87,6 +86,6 @@ build() { package() { DESTDIR="${pkgdir}" cmake --install build - install -Dm644 mocktail/LICENSE \ + install -Dm644 nightcap/LICENSE \ "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE" } diff --git a/packaging/aur/mocktail-git/.SRCINFO b/packaging/aur/nightcap/.SRCINFO similarity index 78% rename from packaging/aur/mocktail-git/.SRCINFO rename to packaging/aur/nightcap/.SRCINFO index 76e6507..d2be0f0 100644 --- a/packaging/aur/mocktail-git/.SRCINFO +++ b/packaging/aur/nightcap/.SRCINFO @@ -1,8 +1,8 @@ -pkgbase = mocktail-git +pkgbase = nightcap pkgdesc = Android x86-64 Roblox compatibility runtime for Linux - pkgver = 1.0.2.r24.g9bdd737 + pkgver = 0.3.1 pkgrel = 1 - url = https://github.com/komaruworld/mocktail + url = https://github.com/CoderDayton/nightcap arch = x86_64 license = Apache-2.0 makedepends = cmake>=3.20 @@ -38,9 +38,11 @@ pkgbase = mocktail-git optdepends = gamemode: Feral GameMode integration provides = mocktail conflicts = mocktail - conflicts = mocktail-bin + conflicts = nightcap-bin + conflicts = nightcap-git options = !debug - source = mocktail::git+https://github.com/komaruworld/mocktail.git#branch=main + options = !lto + source = nightcap::git+https://github.com/CoderDayton/nightcap.git#tag=v0.3.1 sha256sums = SKIP -pkgname = mocktail-git +pkgname = nightcap diff --git a/packaging/aur/mocktail/PKGBUILD b/packaging/aur/nightcap/PKGBUILD similarity index 78% rename from packaging/aur/mocktail/PKGBUILD rename to packaging/aur/nightcap/PKGBUILD index 2a985bb..69c6233 100644 --- a/packaging/aur/mocktail/PKGBUILD +++ b/packaging/aur/nightcap/PKGBUILD @@ -1,11 +1,11 @@ -# Maintainer: komaruworld +# Maintainer: vii -pkgname=mocktail -pkgver=1.0.4 +pkgname=nightcap +pkgver=0.3.1 pkgrel=1 pkgdesc='Android x86-64 Roblox compatibility runtime for Linux' arch=('x86_64') -url='https://github.com/komaruworld/mocktail' +url='https://github.com/CoderDayton/nightcap' license=('Apache-2.0') depends=( 'capstone' @@ -42,17 +42,18 @@ makedepends=( 'vulkan-headers' ) optdepends=('gamemode: Feral GameMode integration') -conflicts=('mocktail-bin' 'mocktail-git') +provides=('mocktail') +conflicts=('mocktail' 'nightcap-bin' 'nightcap-git') options=('!debug' '!lto') source=( - "mocktail::git+https://github.com/komaruworld/mocktail.git#tag=${pkgver}" + "nightcap::git+https://github.com/CoderDayton/nightcap.git#tag=v${pkgver}" ) sha256sums=( 'SKIP' ) prepare() { - cd mocktail + cd nightcap sed -i \ 's|add_subdirectory(third_party/Vulkan-Headers EXCLUDE_FROM_ALL)|find_package(VulkanHeaders CONFIG REQUIRED)|' \ @@ -60,7 +61,7 @@ prepare() { } build() { - cmake -S mocktail -B build -G Ninja \ + cmake -S nightcap -B build -G Ninja \ -DCMAKE_BUILD_TYPE=Release \ -DCMAKE_INSTALL_PREFIX=/usr \ -DCMAKE_INSTALL_LIBDIR=lib \ @@ -73,6 +74,6 @@ build() { package() { DESTDIR="${pkgdir}" cmake --install build - install -Dm644 mocktail/LICENSE \ + install -Dm644 nightcap/LICENSE \ "${pkgdir}/usr/share/licenses/${pkgname}/LICENSE" } diff --git a/packaging/io.github.CoderDayton.nightcap.metainfo.xml b/packaging/io.github.CoderDayton.nightcap.metainfo.xml index f3a5ae8..f85ef46 100644 --- a/packaging/io.github.CoderDayton.nightcap.metainfo.xml +++ b/packaging/io.github.CoderDayton.nightcap.metainfo.xml @@ -21,8 +21,9 @@ Sign in to Roblox, browse experiences, and play them on Linux.

- Mocktail is an independent community project. It is not affiliated with - Roblox Corporation or VinegarHQ, and the Roblox client is not included. + Nightcap is an independent community project, forked from Mocktail. It + is not affiliated with Roblox Corporation or VinegarHQ, and the Roblox + client is not included.

@@ -56,45 +57,49 @@ mocktail - +
    -
  • Fixed login issues
  • -
  • Fixed low-resolution textures, skybox rendering and HiDPI scaling.
  • -
  • Added vc support.
  • -
  • Added Xbox and PlayStation gamepad support.
  • -
  • Added Nix support
  • -
  • Improved text input, fullscreen mode, window sizing, and mouse controls.
  • -
  • Updated support for Roblox 2.736.1408.
  • +
  • Added DEB, RPM, and pacman packages to every release.
  • +
  • Smoother frames: textures no longer decode on the thread that submits the frame.
  • +
  • Fixed the mouse pointer jumping when a right-click camera drag ended.
  • +
  • Fixed the text caret not moving when a trailing space was typed.
  • +
  • Faster typing in text boxes.
- +
    -
  • Fixed issues with downloading Roblox on first launch
  • -
  • Added fflags.json for custom FFlags
  • -
  • Added a message if your cookies have expired
  • +
  • Added a custom Discord presence: set the title, state, and icons.
  • +
  • Added --profile to record a trace of the renderer's work.
  • +
  • Faster texture loading: compressed textures decode and resample on worker threads.
  • +
  • Lower CPU use while playing.
  • +
  • Fixed GameMode pinning the game to a few CPU cores.
- +
    -
  • Fixed the “Roblox is out of date” bug
  • -
  • Improved logging
  • -
  • Fixed issues with Discord RPC where the game you were playing wasn’t displayed
  • +
  • Discord Rich Presence is on by default.
  • +
  • Added input.raw_mouse for mouse look in the host's own units.
  • +
  • Fixed mouse look after a long turn.
  • +
  • Fixed a first-run failure with "cannot lock appStorage".
  • +
  • Values in fflags.json now win over the performance preset.
- +
    -
  • Fix issues with GameMode
  • -
  • Add Discord RPC support
  • +
  • First Nightcap release, forked from Mocktail.
  • +
  • Added ETC2 and EAC texture emulation on Vulkan.
  • +
  • Added PNG texture overrides.
  • +
  • Lower input latency.
  • +
  • Roblox now sees the real host RAM and display size.
-
diff --git a/scripts/package_version.sh b/scripts/package_version.sh new file mode 100755 index 0000000..89f0024 --- /dev/null +++ b/scripts/package_version.sh @@ -0,0 +1,18 @@ +#!/usr/bin/env bash +# Modified by vii from komaruworld/mocktail. See README "About this fork". +# Copyright 2026 Mocktail Project Authors +# SPDX-License-Identifier: Apache-2.0 +# +# Prints the native package version for the current ref. A release tag gives +# its own version; anything else gives 0.0.0, which sorts below every release. + +set -Eeuo pipefail + +ref="${1:-${GITHUB_REF_NAME:-}}" +version="${ref#v}" + +if [[ "${version}" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + printf '%s\n' "${version}" +else + printf '0.0.0\n' +fi diff --git a/site/index.html b/site/index.html index 25bd8c1..6ab54b4 100644 --- a/site/index.html +++ b/site/index.html @@ -22,6 +22,10 @@

Flatpak

flatpak install --user https://coderdayton.github.io/nightcap/nightcap.flatpakref flatpak run io.github.CoderDayton.nightcap +

DEB, RPM and pacman

+ sudo apt install ./nightcap_<version>-1_amd64.deb +sudo dnf install ./nightcap-<version>-1.x86_64.rpm +sudo pacman -U nightcap-<version>-1-x86_64.pkg.tar.zst

Build from source

git clone --recurse-submodules https://github.com/CoderDayton/nightcap.git cd nightcap && make build @@ -40,6 +44,7 @@ cd nightcap && make build