Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
17 commits
Select commit Hold shift + click to select a range
52b8d21
feat: add native GPUI desktop alternative and evaluation workflow
Oct 2, 2026
770f46e
feat(gpui): match Electron UI and promote native app to primary
boggedbrush Oct 3, 2026
2f289c5
feat(native): run GPUI on in-process patchops-core Rust backend
boggedbrush Oct 4, 2026
691dbbc
test(core): add Python-golden parity suite for patchops-core
boggedbrush Oct 4, 2026
88f1c3b
feat(gpui): custom titlebar, translucent backdrop, progress UI and la…
boggedbrush Oct 4, 2026
088becc
feat(gpui): stream core log and progress events into the UI
boggedbrush Oct 4, 2026
d59d7bf
ci(native): smoke test the GPUI window on headless Weston Wayland
boggedbrush Oct 4, 2026
1f2982a
fix(core): match Python config and Steam behavior with safe legacy ad…
boggedbrush Oct 4, 2026
051beba
test(core): run all Python parity cases with exact adoption expectations
boggedbrush Oct 4, 2026
51d74f1
refactor(gpui): drop translucent backdrop, keep window fully opaque
boggedbrush Oct 4, 2026
88377be
fix(gpui): track Lucide license file excluded by the *.txt ignore rule
boggedbrush Oct 4, 2026
77d57ab
fix(gpui): cap refresh rate at 240 and allow picking DUMP.zip
boggedbrush Oct 4, 2026
1e0e455
ci(native): allow unprivileged user namespaces for the bubblewrap par…
boggedbrush Oct 4, 2026
e4c4241
ci(native): run the Wayland smoke test on headless sway
boggedbrush Oct 4, 2026
3d2b3d3
fix(native): gate platform-specific code for Windows clippy
boggedbrush Oct 4, 2026
aba60fd
fix(core): compare DXVK ownership paths canonically
boggedbrush Oct 4, 2026
f119dc1
ci(native): accept libwayland's older @id trace format in the Wayland…
boggedbrush Oct 4, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
110 changes: 110 additions & 0 deletions .github/workflows/gpui-build.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
name: PatchOpsIII Native Build

on:
pull_request:
paths:
- 'native/**'
- 'scripts/*gpui*.py'
- 'scripts/measure_desktop.py'
- 'presets.json'
- 'package.json'
- 'docs/gpui-architecture.md'
- '.github/workflows/gpui-build.yml'
workflow_dispatch:
inputs:
ref:
description: Git ref to build
required: false
type: string
default: ''
workflow_call:
inputs:
ref:
description: Git ref to build
required: false
type: string
default: ''

permissions:
contents: read

jobs:
native:
name: Native ${{ matrix.os }} archive
strategy:
fail-fast: false
matrix:
include:
- os: ubuntu-24.04
executable: native/target/release/patchopsiii-gpui
archive: dist/native/PatchOpsIII-native-linux-x64.zip
artifact: PatchOpsIII-native-Linux
- os: windows-2022
executable: native/target/release/patchopsiii-gpui.exe
archive: dist/native/PatchOpsIII-native-windows-x64.zip
artifact: PatchOpsIII-native-Windows
runs-on: ${{ matrix.os }}
env:
PYTHON_VERSION: '3.12'
steps:
- uses: actions/checkout@v4
with:
ref: ${{ inputs.ref != '' && inputs.ref || github.ref }}
- uses: actions/setup-python@v5
with:
python-version: ${{ env.PYTHON_VERSION }}
- uses: dtolnay/rust-toolchain@master
with:
toolchain: '1.99.0'
components: rustfmt, clippy
- uses: Swatinem/rust-cache@v2
with:
workspaces: native
- name: Linux native and packaging dependencies
if: runner.os == 'Linux'
run: sudo apt-get update && sudo apt-get install -y binutils libfontconfig1-dev libfreetype6-dev libxkbcommon-dev libxkbcommon-x11-dev libwayland-dev libvulkan-dev libx11-xcb-dev libxcb1-dev libasound2-dev libclang-dev mesa-vulkan-drivers xvfb xauth openbox xcompmgr xdotool bubblewrap sway
- name: Python lifecycle and packaging tests
run: python -m unittest scripts/test_gpui.py
- name: Format
run: cargo fmt --manifest-path native/Cargo.toml --all --check
- name: Lint
run: cargo clippy --locked --manifest-path native/Cargo.toml --workspace --all-targets -- -D warnings
- name: Core unit tests
run: cargo test --locked --manifest-path native/Cargo.toml -p patchops-core --lib
- name: Python-oracle parity tests (Linux isolation harness)
if: runner.os == 'Linux'
run: |
# Ubuntu 24.04 blocks unprivileged user namespaces via AppArmor;
# the bubblewrap sandbox needs them on this ephemeral runner.
sudo sysctl -w kernel.apparmor_restrict_unprivileged_userns=0
cargo test --locked --manifest-path native/Cargo.toml -p patchops-core --test parity
- name: GPUI tests
run: cargo test --locked --manifest-path native/Cargo.toml -p patchopsiii-gpui
- name: Build native release
run: python scripts/gpui.py build --release
- name: Create self-contained native archive
run: python scripts/package_gpui.py --executable ${{ matrix.executable }} --output ${{ matrix.archive }}
- name: Verify in-process status (Windows)
if: runner.os == 'Windows'
run: python scripts/smoke_gpui_linux.py --status-only --executable ${{ matrix.executable }}
- name: Smoke test the self-contained Linux archive
if: runner.os == 'Linux'
run: |
python -m zipfile -e ${{ matrix.archive }} "${RUNNER_TEMP}/patchops-native"
chmod +x "${RUNNER_TEMP}/patchops-native/PatchOpsIII/patchopsiii-gpui"
xvfb-run -a python scripts/smoke_gpui_linux.py --start-session --executable "${RUNNER_TEMP}/patchops-native/PatchOpsIII/patchopsiii-gpui"
- name: Smoke test the native Wayland window (headless sway)
if: runner.os == 'Linux'
run: python scripts/smoke_gpui_wayland.py --executable "${RUNNER_TEMP}/patchops-native/PatchOpsIII/patchopsiii-gpui" --compositor sway --keep-log "${RUNNER_TEMP}/wayland-smoke.log"
- name: Upload Wayland smoke log
if: failure() && runner.os == 'Linux'
uses: actions/upload-artifact@v4
with:
name: wayland-smoke-log
path: ${{ runner.temp }}/wayland-smoke.log
if-no-files-found: ignore
- uses: actions/upload-artifact@v4
with:
name: ${{ matrix.artifact }}
path: ${{ matrix.archive }}
if-no-files-found: error
28 changes: 28 additions & 0 deletions .github/workflows/release-beta.yml
Original file line number Diff line number Diff line change
Expand Up @@ -309,6 +309,14 @@ jobs:
ref: ${{ needs.prepare.outputs.tag }}
secrets: inherit

build-native:
# GPUI + patchops-core archives; no Python backend bundle in native assets.
needs:
- prepare
uses: ./.github/workflows/gpui-build.yml
with:
ref: ${{ needs.prepare.outputs.tag }}

release:
name: Publish beta release
runs-on: ubuntu-latest
Expand All @@ -318,6 +326,7 @@ jobs:
- prepare
- build-windows
- build-linux
- build-native
steps:
- name: Checkout repository
uses: actions/checkout@v4
Expand All @@ -334,6 +343,16 @@ jobs:
with:
name: ${{ needs.build-linux.outputs.artifact_name }}
path: artifacts/linux
- name: Download native Linux archive
uses: actions/download-artifact@v4
with:
name: PatchOpsIII-native-Linux
path: artifacts/native-linux
- name: Download native Windows archive
uses: actions/download-artifact@v4
with:
name: PatchOpsIII-native-Windows
path: artifacts/native-windows
- name: Inspect downloaded artifacts
run: |
set -euo pipefail
Expand Down Expand Up @@ -468,6 +487,15 @@ jobs:
if [ -f "$(dirname "$linux_exec")/PatchOpsIII.AppImage.sig" ]; then
cp "$(dirname "$linux_exec")/PatchOpsIII.AppImage.sig" "release/PatchOpsIII-Beta.AppImage.sig"
fi
native_linux=$(find artifacts/native-linux -type f -name 'PatchOpsIII-native-linux-x64.zip' -print -quit)
native_windows=$(find artifacts/native-windows -type f -name 'PatchOpsIII-native-windows-x64.zip' -print -quit)
if [ -z "$native_linux" ] || [ -z "$native_windows" ]; then
echo "Native desktop archives were not produced" >&2
find artifacts/native-linux artifacts/native-windows -type f -print >&2
exit 1
fi
cp "$native_linux" "release/PatchOpsIII-native-linux-x64.zip"
cp "$native_windows" "release/PatchOpsIII-native-windows-x64.zip"
- name: Publish GitHub release
uses: softprops/action-gh-release@v2
with:
Expand Down
28 changes: 28 additions & 0 deletions .github/workflows/release-stable.yml
Original file line number Diff line number Diff line change
Expand Up @@ -303,6 +303,14 @@ jobs:
update_information: gh-releases-zsync|boggedbrush|PatchOpsIII|latest|PatchOpsIII.AppImage.zsync
secrets: inherit

build-native:
# GPUI + patchops-core archives; no Python backend bundle in native assets.
needs:
- prepare
uses: ./.github/workflows/gpui-build.yml
with:
ref: ${{ needs.prepare.outputs.tag }}

release:
name: Publish stable release
runs-on: ubuntu-latest
Expand All @@ -312,6 +320,7 @@ jobs:
- prepare
- build-windows
- build-linux
- build-native
steps:
- name: Checkout repository
uses: actions/checkout@v4
Expand All @@ -328,6 +337,16 @@ jobs:
with:
name: ${{ needs.build-linux.outputs.artifact_name }}
path: artifacts/linux
- name: Download native Linux archive
uses: actions/download-artifact@v4
with:
name: PatchOpsIII-native-Linux
path: artifacts/native-linux
- name: Download native Windows archive
uses: actions/download-artifact@v4
with:
name: PatchOpsIII-native-Windows
path: artifacts/native-windows
- name: Inspect downloaded artifacts
run: |
set -euo pipefail
Expand Down Expand Up @@ -462,6 +481,15 @@ jobs:
if [ -f "$(dirname "$linux_exec")/PatchOpsIII.AppImage.sig" ]; then
cp "$(dirname "$linux_exec")/PatchOpsIII.AppImage.sig" "release/PatchOpsIII.AppImage.sig"
fi
native_linux=$(find artifacts/native-linux -type f -name 'PatchOpsIII-native-linux-x64.zip' -print -quit)
native_windows=$(find artifacts/native-windows -type f -name 'PatchOpsIII-native-windows-x64.zip' -print -quit)
if [ -z "$native_linux" ] || [ -z "$native_windows" ]; then
echo "Native desktop archives were not produced" >&2
find artifacts/native-linux artifacts/native-windows -type f -print >&2
exit 1
fi
cp "$native_linux" "release/PatchOpsIII-native-linux-x64.zip"
cp "$native_windows" "release/PatchOpsIII-native-windows-x64.zip"
- name: Publish GitHub release
uses: softprops/action-gh-release@v2
with:
Expand Down
5 changes: 3 additions & 2 deletions .github/workflows/virustotal-release-scan.yml
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ jobs:
--repo "$GITHUB_REPOSITORY" \
--pattern "*.exe" \
--pattern "*.AppImage" \
--pattern "PatchOpsIII-native-*.zip" \
--dir release-assets
find release-assets -maxdepth 1 -type f -print
- name: Determine VirusTotal CLI release
Expand Down Expand Up @@ -107,9 +108,9 @@ jobs:
printf "| `%s` | `%s` | [Report](%s) | `%s` |\n" \
"$(basename "$asset")" "$hash" "$vt_url" "$analysis_id" >> "$GITHUB_STEP_SUMMARY"
printf "%s %s %s\n" "$(basename "$asset")" "$hash" "$analysis_id"
done < <(find release-assets -maxdepth 1 -type f \( -name "*.exe" -o -name "*.AppImage" \) -print0)
done < <(find release-assets -maxdepth 1 -type f \( -name "*.exe" -o -name "*.AppImage" -o -name "PatchOpsIII-native-*.zip" \) -print0)

if [ "$found" -eq 0 ]; then
echo "No .exe or .AppImage assets found for ${{ inputs.tag }}." >&2
echo "No executable or native archive assets found for ${{ inputs.tag }}." >&2
exit 1
fi
7 changes: 6 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -23,9 +23,14 @@ node_modules/
# text files:
*.txt
!requirements.txt
!native/gpui/assets/icons/LICENSE-lucide.txt

# vdf files:
*.vdf

# codex:
.codex/
.codex/

# Rust native workspace build output (Cargo.lock is committed)
native/target/
native/gpui/target/
52 changes: 35 additions & 17 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@
- [Advanced Tab](#advanced-tab)
- [Terminal & Logging](#terminal--logging)
- [Installation](#installation)
- [Native desktop architecture](#native-desktop-architecture)
- [Legacy Electron app](#legacy-electron-app)
- [Forked Components](#forked-components)
- [Quick Start](#quick-start)
- [Screenshots](#screenshots)
Expand All @@ -32,7 +34,7 @@
- [Star History](#star-history)

## Overview
PatchOpsIII streamlines the setup and upkeep of Black Ops III by surfacing popular community tools and quality-of-life tweaks in a single polished Electron interface backed by a local Python API. Whether you are securing your game with T7 Patch, smoothing shader compilation stutter with DXVK, or fine-tuning launch options, PatchOpsIII consolidates every workflow into one cohesive experience.
PatchOpsIII streamlines the setup and upkeep of Black Ops III by surfacing popular community tools and quality-of-life tweaks in a native Rust/GPUI desktop interface with in-process Rust operations. Whether you are securing your game with T7 Patch, smoothing shader compilation stutter with DXVK, or fine-tuning launch options, PatchOpsIII consolidates every workflow into one cohesive experience. The previous Electron/React client remains available in this repository as a legacy fallback.

## Key Features

Expand All @@ -59,32 +61,46 @@ PatchOpsIII streamlines the setup and upkeep of Black Ops III by surfacing popul

## Installation
1. **Download:** Grab the latest release from the [Releases page](https://github.com/boggedbrush/PatchOpsIII/releases).
2. **Windows:** Run `PatchOpsIII.msi`, follow the installer, then launch PatchOpsIII. The `PatchOpsIII.exe` installer remains available for compatibility with older updaters.
3. **Linux & Steam Deck:** Download `PatchOpsIII.AppImage`, make it executable, then run it.
4. **Dependencies:** The packaged build bundles all required Python dependencies; no additional setup is needed.
2. **Windows:** Download `PatchOpsIII-native-windows-x64.zip`, extract the entire `PatchOpsIII` folder, and run `patchopsiii-gpui.exe` from that folder.
3. **Linux & Steam Deck:** Download `PatchOpsIII-native-linux-x64.zip`, extract it, run `chmod +x PatchOpsIII/patchopsiii-gpui`, then launch that executable from a desktop session.
4. **Dependencies:** Keep the executable and its `resources` directory together. The archive bundles one Rust executable, presets, metadata, and icons; Python is not required on the destination system. Linux still requires a supported X11/Wayland session, system fonts, and working graphics drivers.

The existing `PatchOpsIII.msi`, `PatchOpsIII.exe`, and `PatchOpsIII.AppImage` release assets are the legacy Electron fallback while native installer/updater work remains open.

### Developer Setup
PatchOpsIII uses a React + TypeScript renderer wrapped by Electron. Bun is the JavaScript runtime/package manager, while Python runs the local backend API.

The primary desktop app uses Rust 1.99.0, GPUI 0.2.2, GPUI Component 0.5.0,
and the `patchops-core` library in the `native/` Cargo workspace. Install Rust
through rustup and the platform build packages listed in the native README.

```bash
# install Python service dependencies
python -m venv .venv
source .venv/bin/activate # On Windows use: .venv\Scripts\activate
pip install -r requirements.txt
cargo +1.99.0 build --locked --manifest-path native/Cargo.toml -p patchopsiii-gpui
./native/target/debug/patchopsiii-gpui
# Optional Python standard-library launchers (no backend dependencies):
python scripts/gpui.py build
python scripts/gpui.py run
# Equivalent package scripts: bun run gpui:build / bun run gpui:run
```

# install desktop frontend dependencies
bun install
See [native/gpui/README.md](native/gpui/README.md) for release packaging,
validation commands, and remaining hardware checks. Rust operations run on a
worker thread within the native app; no Python service or HTTP listener starts.

# run Vite and the Python local API
bun run dev
## Native desktop architecture

# run the Electron desktop app
bun run dev:desktop
```
The primary Rust/GPUI client lives in [native/gpui](native/gpui/README.md) and
shares toolkit-independent operations from [native/core](native/core).
The worker dispatches existing `/api/...` action identifiers directly to Rust,
preserving the JSON shapes consumed by the UI. Downloads use outbound HTTPS.
See [the architecture and migration record](docs/gpui-architecture.md) for the
progress callback contract, migration details, and remaining validation work.

The browser development server uses Vite on `127.0.0.1:5173` and the Python API on `127.0.0.1:8765`. The Electron desktop command uses Vite on `127.0.0.1:5174` and its Python API on `127.0.0.1:8766`, so both commands can run at the same time. The renderer communicates with Python through HTTP APIs and `/ws` WebSockets; Electron IPC is reserved for desktop-specific bridge actions such as selecting a local game directory.
## Legacy Electron app

The Electron/React application in `src/` remains buildable as a fallback. To work on it, install Python 3.12 dependencies with `python -m pip install -r requirements.txt` and Bun dependencies with `bun install`, then use `bun run dev:desktop`; `bun run dist:linux` and `bun run dist:win` retain the established AppImage/MSI/NSIS builds. The browser development server remains available through `bun run dev`. Electron and GPUI share backend settings, logs, caches, and game files, so do not perform overlapping game mutations in both clients.

## Forked Components

- **BO3 Enhanced Proton fork metadata:** [bo3-enhanced-proton/README.md](bo3-enhanced-proton/README.md)
- Upstream source: https://github.com/Weather-OS/GDK-Proton
- Current base release: `release10-32`
Expand All @@ -99,6 +115,8 @@ The browser development server uses Vite on `127.0.0.1:5173` and the Python API
5. Visit the **Advanced** tab to unlock VRAM, tweak frame latency, and set your config to read-only once satisfied.

## Screenshots

These screenshots show the legacy Electron client; updated native screenshots are tracked with the native UI work.
<table>
<tr>
<td align="center"><img src="https://raw.githubusercontent.com/boggedbrush/PatchOpsIII/main/website/assets/img/screenshots/dashboard.png" alt="Dashboard" /><br/><sub>Dashboard</sub></td>
Expand Down
Loading
Loading