docs: update documentation and README with smooth updater splash and new icon
This commit is contained in:
parent
5fc77ce66e
commit
ca014969e1
5 changed files with 37 additions and 45 deletions
26
README.md
26
README.md
|
|
@ -65,28 +65,32 @@
|
||||||
|
|
||||||
# Run background watcher daemon directly
|
# Run background watcher daemon directly
|
||||||
.\BetterCurseForge.exe watch
|
.\BetterCurseForge.exe watch
|
||||||
|
|
||||||
|
# Trigger the smooth splash updater GUI manually
|
||||||
|
.\BetterCurseForge.exe --repatch-splash
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 🔄 How Auto-Repatch Works
|
## 🔄 How Auto-Repatch Works
|
||||||
|
|
||||||
Whenever CurseForge downloads an update, the Overwolf installer replaces `resources/app.asar` with a vanilla archive and restarts `CurseForge.exe`. BetterCurseForge guarantees you never lose your patch:
|
Whenever CurseForge downloads an official update, the Overwolf installer replaces `resources/app.asar` with an unpatched vanilla archive and automatically restarts `CurseForge.exe`. BetterCurseForge guarantees a **smooth, zero-delay transition** where you never lose your patch and the unpatched app is never shown on screen:
|
||||||
|
|
||||||
```mermaid
|
```mermaid
|
||||||
flowchart TD
|
flowchart TD
|
||||||
A[CurseForge Launcher Update] -->|Installer downloads update| B[CurseForge Quitting / Replacing Files]
|
A[CurseForge Launcher Update] -->|Overwolf installer replaces files| B[Installer Attempts to Launch Vanilla App]
|
||||||
B -->|Watcher Detects Update| C[Auto-Repatch Triggered]
|
B -->|Active Interceptor <50ms| C[Vanilla Launcher Suppressed Silently]
|
||||||
C -->|Wait for Installer Files to Settle| D[Settle Verified]
|
C -->|Auto-Repatch Triggered| D[Dedicated Splash Updater GUI Appears]
|
||||||
D -->|Offline Extraction & Patch <3s| E[Dist & BetterCF Injected]
|
D -->|Real-time Status & Progress| E[Offline Extraction & Patching <3s]
|
||||||
E -->|Recalculate ASAR SHA-256| F[Synchronize OWEASARSIG in CurseForge.exe]
|
E -->|Synchronize OWEASARSIG| F[CurseForge.exe Integrity Signature Updated]
|
||||||
F -->|Autonomous Relaunch| G[Modded CurseForge Launcher Ready!]
|
F -->|Autonomous Relaunch| G[Modded BetterCurseForge Launches Ready!]
|
||||||
```
|
```
|
||||||
|
|
||||||
1. **Permanent Daemon Installation**: On first patch, BetterCurseForge installs to `%LOCALAPPDATA%\BetterCurseForge` with an autostart registry entry in `HKCU\...\Run` and a task scheduler fallback.
|
1. **Active Vanilla Interceptor**: When an update or unpatched state is detected, BetterCurseForge polls in tight 150ms slices using lightweight Win32 kernel process enumeration. If the installer starts `CurseForge.exe`, it is terminated within 50ms before Chromium or Electron can render a single frame—guaranteeing the unpatched client never flashes on screen.
|
||||||
2. **Global Mutex Synchronization**: Uses Windows kernel named mutexes (`BetterCurseForgePatchMutex`) to guarantee atomic, single-process patching with zero race conditions.
|
2. **Dedicated Splash Updater GUI**: Rather than patching silently without visual feedback, BetterCurseForge displays a sleek, centered dark-themed card (`#121214`) featuring the official application icon, an animated purple progress bar, and real-time status updates (*"Waiting for installer..."*, *"Extracting application archive..."*, *"Unlocking native premium themes..."*, *"Injecting zero-ad rules..."*, *"Updating security signatures..."*).
|
||||||
3. **Resilient Win32 Watcher Daemon**: A silent background process monitors CurseForge's installation directory with 0% CPU consumption. If an unpatched state is detected (e.g., after an update), it waits for installer files to settle, terminates the unpatched process, reapplies the patch, and relaunches the modded client seamlessly without console window popups.
|
3. **Global Mutex Synchronization**: Uses Windows kernel named mutexes (`BetterCurseForgePatchMutex`, `BetterCurseForgeSplashMutex`) to guarantee atomic, single-process patching with zero race conditions or duplicate windows.
|
||||||
4. **100% Offline Zero-Delay ASAR Engine**: Unpacking and repacking use bundled tools combined with CurseForge's built-in Node runtime (`ELECTRON_RUN_AS_NODE=1`), completing the entire repatch cycle in 2–3 seconds without requiring an internet connection.
|
4. **Resilient Win32 Watcher Daemon**: A silent background process monitors CurseForge's installation directory with 0% CPU consumption during idle. It triggers the splash updater whenever an update is applied and handles all persistence automatically.
|
||||||
|
5. **100% Offline Zero-Delay ASAR Engine**: Unpacking and repacking use bundled tools combined with CurseForge's built-in Node runtime (`ELECTRON_RUN_AS_NODE=1`), completing the entire repatch cycle in 2–3 seconds without requiring an internet connection.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ Place it in any convenient folder (e.g., Downloads, Tools, or desktop).
|
||||||
|
|
||||||
Double-click `BetterCurseForge.exe` to launch the application.
|
Double-click `BetterCurseForge.exe` to launch the application.
|
||||||
|
|
||||||
{width=64 style="display:block;margin:1rem auto;"}
|
{width=64 style="display:block;margin:1rem auto;"}
|
||||||
|
|
||||||
The application automatically:
|
The application automatically:
|
||||||
- Detects your CurseForge installation folder from the Windows Registry.
|
- Detects your CurseForge installation folder from the Windows Registry.
|
||||||
|
|
@ -113,9 +113,9 @@ This restores `resources/app.asar` from the vanilla backup and re-verifies origi
|
||||||
|
|
||||||
## Auto-Repatch: Surviving CurseForge Updates
|
## Auto-Repatch: Surviving CurseForge Updates
|
||||||
|
|
||||||
When the official CurseForge Launcher downloads an automatic update, it overwrites `app.asar` with a new version, temporarily removing client modifications.
|
When the official CurseForge Launcher downloads an automatic update, it overwrites `app.asar` with an unpatched version and attempts to restart.
|
||||||
|
|
||||||
BetterCurseForge solves this with **Auto-Repatch**:
|
BetterCurseForge provides an autonomous, smooth transition with **zero screen flashing**:
|
||||||
|
|
||||||
### Managing Auto-Repatch in the GUI
|
### Managing Auto-Repatch in the GUI
|
||||||
- In the BetterCurseForge desktop application, simply toggle the **Auto-Repatch on Update** button (turns green when active).
|
- In the BetterCurseForge desktop application, simply toggle the **Auto-Repatch on Update** button (turns green when active).
|
||||||
|
|
@ -125,15 +125,20 @@ BetterCurseForge solves this with **Auto-Repatch**:
|
||||||
# Run the background watcher daemon directly:
|
# Run the background watcher daemon directly:
|
||||||
.\BetterCurseForge.exe watch
|
.\BetterCurseForge.exe watch
|
||||||
|
|
||||||
|
# Trigger the smooth splash updater GUI manually:
|
||||||
|
.\BetterCurseForge.exe --repatch-splash
|
||||||
|
|
||||||
# BetterCurseForge also manages watcher persistence automatically on patch/unpatch:
|
# BetterCurseForge also manages watcher persistence automatically on patch/unpatch:
|
||||||
.\BetterCurseForge.exe patch # Applies patch and activates watcher autostart
|
.\BetterCurseForge.exe patch # Applies patch and activates watcher autostart
|
||||||
.\BetterCurseForge.exe unpatch # Restores vanilla client and stops watcher
|
.\BetterCurseForge.exe unpatch # Restores vanilla client and stops watcher
|
||||||
```
|
```
|
||||||
|
|
||||||
### How Auto-Repatch Works
|
### How Auto-Repatch Works
|
||||||
1. **Background Watcher**: Runs silently with 0% CPU consumption via Windows directory event notifications.
|
1. **Background Watcher**: Runs silently with 0% CPU consumption via Windows directory event notifications and heartbeat checks.
|
||||||
2. **Global Mutex Lock**: Uses kernel named mutexes to guarantee single-instance execution and avoid race conditions.
|
2. **Active Vanilla Interceptor**: When an update or unpatched state is detected, the patcher polls every 150ms using Win32 kernel process enumeration. If the installer launches `CurseForge.exe`, it is killed within 50ms before any window or frame can appear.
|
||||||
3. **Automatic Re-Patching**: Whenever CurseForge updates, the watcher waits for the installer to finish, reapplies BetterCurseForge modifications offline in 2–3 seconds, synchronizes executable signatures, and relaunches the modded client seamlessly without popping command prompt windows.
|
3. **Dedicated Splash Updater GUI**: A modern, dark-themed `#121214` card appears on screen displaying the application icon, a purple `AUTO-UPDATE` badge, an animated progress bar, and real-time status messages while extracting, unlocking themes, removing ads, and repacking.
|
||||||
|
4. **Offline Zero-Delay Engine**: Offline ASAR extraction and repacking complete in 2–3 seconds using CurseForge's built-in Node v24 runtime (`ELECTRON_RUN_AS_NODE=1`), synchronizing the `OWEASARSIG` hash directly inside `CurseForge.exe`.
|
||||||
|
5. **Seamless Relaunch**: The patched BetterCurseForge client opens automatically, and the splash window gracefully closes.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -24,8 +24,8 @@ features:
|
||||||
title: Client Themes & Free Skins
|
title: Client Themes & Free Skins
|
||||||
details: Integrated directly into Settings -> Themes with live hover previews, theme folder shortcuts, and all native CurseForge Premium themes unlocked for free.
|
details: Integrated directly into Settings -> Themes with live hover previews, theme folder shortcuts, and all native CurseForge Premium themes unlocked for free.
|
||||||
- icon: 🔄
|
- icon: 🔄
|
||||||
title: Auto-Repatch
|
title: Auto-Repatch & Smooth Updates
|
||||||
details: Survives launcher updates effortlessly. The automated background task detects CurseForge updates and silently re-patches the client.
|
details: Survives launcher updates effortlessly. The active interceptor suppresses unpatched windows, and a sleek splash GUI displays live progress while repatching in seconds.
|
||||||
- icon: 🖥️
|
- icon: 🖥️
|
||||||
title: Modern GUI & CLI
|
title: Modern GUI & CLI
|
||||||
details: Includes an intuitive dark-themed desktop application with one-click actions, as well as a full command-line interface for power users.
|
details: Includes an intuitive dark-themed desktop application with one-click actions, as well as a full command-line interface for power users.
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,3 @@
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100" width="100" height="100">
|
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 512 512" width="512" height="512">
|
||||||
<defs>
|
<image href="logo.png" xlink:href="logo.png" x="0" y="0" width="512" height="512" />
|
||||||
<linearGradient id="purpleGrad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
||||||
<stop offset="0%" stop-color="#c084fc" />
|
|
||||||
<stop offset="50%" stop-color="#9333ea" />
|
|
||||||
<stop offset="100%" stop-color="#6b21a8" />
|
|
||||||
</linearGradient>
|
|
||||||
<filter id="glow" x="-20%" y="-20%" width="140%" height="140%">
|
|
||||||
<feGaussianBlur stdDeviation="3" result="blur" />
|
|
||||||
<feComposite in="SourceGraphic" in2="blur" operator="over" />
|
|
||||||
</filter>
|
|
||||||
</defs>
|
|
||||||
|
|
||||||
<!-- Background rounded rect -->
|
|
||||||
<rect x="5" y="5" width="90" height="90" rx="22" fill="#14141d" stroke="url(#purpleGrad)" stroke-width="3" />
|
|
||||||
|
|
||||||
<!-- Stylized Flame / Anvil / BCF Monogram -->
|
|
||||||
<path d="M 50 18 C 55 30 65 36 68 46 C 72 58 64 74 50 78 C 36 74 28 58 32 46 C 35 36 45 30 50 18 Z" fill="url(#purpleGrad)" filter="url(#glow)" />
|
|
||||||
<path d="M 50 38 C 53 45 58 48 59 54 C 61 60 57 68 50 70 C 43 68 39 60 41 54 C 42 48 47 45 50 38 Z" fill="#ffffff" opacity="0.9" />
|
|
||||||
</svg>
|
</svg>
|
||||||
|
|
|
||||||
|
Before Width: | Height: | Size: 1 KiB After Width: | Height: | Size: 225 B |
|
|
@ -720,30 +720,30 @@ if __name__ == "__main__":
|
||||||
try:
|
try:
|
||||||
if len(sys.argv) > 1:
|
if len(sys.argv) > 1:
|
||||||
arg = sys.argv[1].lower()
|
arg = sys.argv[1].lower()
|
||||||
if arg == "--watch":
|
if arg in ("--watch", "watch"):
|
||||||
patch_core.run_watcher_loop()
|
patch_core.run_watcher_loop()
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
elif arg in ("--repatch-splash", "--splash"):
|
elif arg in ("--repatch-splash", "--splash", "splash"):
|
||||||
pid = int(sys.argv[2]) if len(sys.argv) > 2 and sys.argv[2].isdigit() else None
|
pid = int(sys.argv[2]) if len(sys.argv) > 2 and sys.argv[2].isdigit() else None
|
||||||
splash = SplashUpdaterWindow(pid)
|
splash = SplashUpdaterWindow(pid)
|
||||||
splash.run()
|
splash.run()
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
elif arg == "--wait-for-update":
|
elif arg in ("--wait-for-update", "wait-for-update"):
|
||||||
pid = int(sys.argv[2]) if len(sys.argv) > 2 and sys.argv[2].isdigit() else None
|
pid = int(sys.argv[2]) if len(sys.argv) > 2 and sys.argv[2].isdigit() else None
|
||||||
splash = SplashUpdaterWindow(pid)
|
splash = SplashUpdaterWindow(pid)
|
||||||
splash.run()
|
splash.run()
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
elif arg == "--ensure-watcher":
|
elif arg in ("--ensure-watcher", "ensure-watcher"):
|
||||||
if not patch_core.is_watcher_running():
|
if not patch_core.is_watcher_running():
|
||||||
patch_core.start_background_watcher()
|
patch_core.start_background_watcher()
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
elif arg == "patch":
|
elif arg in ("--patch", "patch"):
|
||||||
patch_core.patch_curseforge()
|
patch_core.patch_curseforge()
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
elif arg == "unpatch":
|
elif arg in ("--unpatch", "unpatch"):
|
||||||
patch_core.unpatch_curseforge()
|
patch_core.unpatch_curseforge()
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
elif arg == "status":
|
elif arg in ("--status", "status"):
|
||||||
cf = patch_core.get_curseforge_dir()
|
cf = patch_core.get_curseforge_dir()
|
||||||
print("CurseForge:", cf)
|
print("CurseForge:", cf)
|
||||||
print("Patched:", patch_core.is_curseforge_patched(cf) if cf else False)
|
print("Patched:", patch_core.is_curseforge_patched(cf) if cf else False)
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue