mirror of
https://github.com/ScreamAngel/gow3_launcher.git
synced 2026-11-09 04:49:43 -10:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
abd4c153a4 |
No files matched your search
@@ -0,0 +1,122 @@
|
||||
name: Build Cross-Platform Launchers
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
pull_request:
|
||||
branches: [ "main" ]
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
build-linux:
|
||||
name: Build Linux Launcher
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
- name: Install Linux build dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libasound2-dev libudev-dev libwayland-dev libxkbcommon-dev libx11-dev libxcursor-dev libxi-dev libxrandr-dev libgl1-mesa-dev
|
||||
|
||||
- name: Build Linux Launcher (Release)
|
||||
working-directory: launcher
|
||||
run: cargo build --release
|
||||
|
||||
- name: Prepare binary
|
||||
run: |
|
||||
cp launcher/target/release/launcher ./gow3-launcher
|
||||
chmod +x ./gow3-launcher
|
||||
|
||||
- name: Upload Linux Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: gow3-launcher-linux
|
||||
path: ./gow3-launcher
|
||||
|
||||
build-windows:
|
||||
name: Build Windows Launcher
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
- name: Build Windows Launcher (Release)
|
||||
working-directory: launcher
|
||||
run: cargo build --release
|
||||
|
||||
- name: Prepare binary
|
||||
run: |
|
||||
Copy-Item launcher/target/release/launcher.exe -Destination ./gow3-launcher-win.exe
|
||||
|
||||
- name: Upload Windows Artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: gow3-launcher-windows
|
||||
path: ./gow3-launcher-win.exe
|
||||
|
||||
publish-release:
|
||||
name: Publish Release & Sync Windows Binary
|
||||
needs: [build-linux, build-windows]
|
||||
if: github.ref == 'refs/heads/main'
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Download Linux binary
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: gow3-launcher-linux
|
||||
path: ./artifacts/
|
||||
|
||||
- name: Download Windows binary
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: gow3-launcher-windows
|
||||
path: ./artifacts/
|
||||
|
||||
- name: Commit Windows launcher to repo root
|
||||
run: |
|
||||
cp ./artifacts/gow3-launcher-win.exe ./gow3-launcher-win.exe
|
||||
git config --local user.email "[email protected]"
|
||||
git config --local user.name "GitHub Action"
|
||||
git add gow3-launcher-win.exe
|
||||
git diff --quiet && git diff --staged --quiet || (git commit -m "chore(build): sync gow3-launcher-win.exe to repo root [skip ci]" && git push origin main)
|
||||
|
||||
- name: Create or Update GitHub Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: latest
|
||||
name: "God of War III Native Launcher (Dual-Boot & Cross-Platform)"
|
||||
body: |
|
||||
## 🚀 God of War III Remastered - Native Launcher (Linux & Windows)
|
||||
|
||||
Aynı klasörde yan yana çalışabilen yerel ikili dosyalar:
|
||||
- 🐧 **Linux**: `gow3-launcher`
|
||||
- 🪟 **Windows / Dual-Boot**: `gow3-launcher-win.exe`
|
||||
|
||||
### ✨ Özellikler
|
||||
- **Dual-Boot Desteği:** Aynı klasörde hem Windows hem Linux için yan yana bağımsız launcher'lar!
|
||||
- **Modern Kayan Anahtarlar:** Klasik kutucuklar yerine animasyonlu Switch teması
|
||||
- **Kararlı 60 FPS / 120 FPS / 144 FPS / 240 FPS Pacing:** Fizik hızlanma sorunu olmadan akıcı oynanış
|
||||
- **Sinematikleri 'X' Tuşuyla Atlama Yaması:** Ara sahneleri kumandanızın X tuşuyla geçebilme seçeneği
|
||||
- **Sarı Doku Hatası Önleme Yaması (Instant Readbacks):** Karlı ve parlak sahnelerdeki renk bozulmasını engeller
|
||||
- **Dahili Donanım ve Ekran Hz Tespiti:** GPU, VRAM, RAM ve ekran yenileme hızına göre otomatik yapılandırma
|
||||
- **4 Farklı Dil Desteği:** Türkçe 🇹🇷, English 🇬🇧, Deutsch 🇩🇪, Español 🇪🇸
|
||||
- **%100 Rust Uyumlu Self-Updater:** Doğrudan GitHub üzerinden en son sürüme tek tıkla güncelleme
|
||||
files: |
|
||||
./artifacts/gow3-launcher
|
||||
./artifacts/gow3-launcher-win.exe
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -1,153 +0,0 @@
|
||||
name: Build & Release Single Executables (AppImage & Portable Exe)
|
||||
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
workflow_dispatch:
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
|
||||
jobs:
|
||||
build-linux:
|
||||
name: Build Linux AppImage & Binary
|
||||
runs-on: ubuntu-22.04
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
- name: Install Linux build dependencies
|
||||
run: |
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y libasound2-dev libudev-dev libwayland-dev libxkbcommon-dev libx11-dev libxcursor-dev libxi-dev libxrandr-dev libgl1-mesa-dev wget
|
||||
|
||||
- name: Build Linux Launcher (Release)
|
||||
working-directory: launcher
|
||||
run: cargo build --release
|
||||
|
||||
- name: Build AppImage
|
||||
run: |
|
||||
mkdir -p AppDir/usr/bin
|
||||
mkdir -p AppDir/usr/share/applications
|
||||
mkdir -p AppDir/usr/share/icons/hicolor/256x256/apps
|
||||
cp launcher/target/release/launcher AppDir/usr/bin/gow3-launcher
|
||||
cp gow3.png AppDir/usr/share/icons/hicolor/256x256/apps/gow3.png
|
||||
cp gow3.png AppDir/gow3.png
|
||||
|
||||
cat << 'EOF' > AppDir/gow3-launcher.desktop
|
||||
[Desktop Entry]
|
||||
Name=God of War III Launcher
|
||||
Exec=gow3-launcher
|
||||
Icon=gow3
|
||||
Type=Application
|
||||
Categories=Game;
|
||||
Terminal=false
|
||||
EOF
|
||||
cp AppDir/gow3-launcher.desktop AppDir/usr/share/applications/
|
||||
|
||||
cat << 'EOF' > AppDir/AppRun
|
||||
#!/bin/bash
|
||||
HERE="$(dirname "$(readlink -f "${0}")")"
|
||||
export PATH="${HERE}/usr/bin:${PATH}"
|
||||
exec "${HERE}/usr/bin/gow3-launcher" "$@"
|
||||
EOF
|
||||
chmod +x AppDir/AppRun
|
||||
|
||||
wget -q https://github.com/AppImage/appimagetool/releases/download/continuous/appimagetool-x86_64.AppImage -O appimagetool
|
||||
chmod +x appimagetool
|
||||
./appimagetool --appimage-extract
|
||||
ARCH=x86_64 ./squashfs-root/AppRun AppDir God_of_War_III_Launcher-x86_64.AppImage
|
||||
|
||||
cp launcher/target/release/launcher ./gow3-launcher
|
||||
|
||||
- name: Upload Linux Artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: linux-artifacts
|
||||
path: |
|
||||
God_of_War_III_Launcher-x86_64.AppImage
|
||||
gow3-launcher
|
||||
|
||||
build-windows:
|
||||
name: Build Windows Portable Exe
|
||||
runs-on: windows-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Setup Rust toolchain
|
||||
uses: dtolnay/rust-toolchain@stable
|
||||
|
||||
- name: Build Windows Launcher (Release)
|
||||
working-directory: launcher
|
||||
run: cargo build --release
|
||||
|
||||
- name: Prepare Windows Executables
|
||||
run: |
|
||||
Copy-Item launcher/target/release/launcher.exe -Destination ./gow3-launcher-win.exe
|
||||
Copy-Item launcher/target/release/launcher.exe -Destination ./God_of_War_III_Launcher-Windows.exe
|
||||
|
||||
- name: Upload Windows Artifacts
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
name: windows-artifacts
|
||||
path: |
|
||||
gow3-launcher-win.exe
|
||||
God_of_War_III_Launcher-Windows.exe
|
||||
|
||||
publish-release:
|
||||
name: Publish Release with Assets
|
||||
needs: [build-linux, build-windows]
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v4
|
||||
|
||||
- name: Download Linux artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: linux-artifacts
|
||||
path: ./dist/
|
||||
|
||||
- name: Download Windows artifacts
|
||||
uses: actions/download-artifact@v4
|
||||
with:
|
||||
name: windows-artifacts
|
||||
path: ./dist/
|
||||
|
||||
- name: Create or Update GitHub Release
|
||||
uses: softprops/action-gh-release@v2
|
||||
with:
|
||||
tag_name: ${{ github.ref_name }}
|
||||
name: "God of War III Launcher ${{ github.ref_name }}"
|
||||
draft: false
|
||||
prerelease: false
|
||||
make_latest: true
|
||||
body: |
|
||||
## 🚀 God of War III Remastered - Single Executable Release
|
||||
|
||||
Tek tıkla çalışan taşınabilir yürütülebilir dosyalar (Single Executables):
|
||||
|
||||
### 📦 İndirme Seçenekleri:
|
||||
- 🐧 **Linux (AppImage - Tek Dosya Kurulumsuz):** [`God_of_War_III_Launcher-x86_64.AppImage`](./God_of_War_III_Launcher-x86_64.AppImage)
|
||||
- *Kullanım:* İndirin, sağ tıklayıp özelliklerden "Çalıştırılabilir yap" (veya `chmod +x`) deyin ve çift tıklayın!
|
||||
- 🪟 **Windows (Portable Exe - Kurulumsuz):** [`God_of_War_III_Launcher-Windows.exe`](./God_of_War_III_Launcher-Windows.exe) / [`gow3-launcher-win.exe`](./gow3-launcher-win.exe)
|
||||
- 🐧 **Linux (Native ELF):** [`gow3-launcher`](./gow3-launcher)
|
||||
|
||||
### ✨ Yenilikler (${{ github.ref_name }})
|
||||
- **AppImage Desteği:** Linux üzerinde bağımlılık derdi olmadan tek tıkla çalışan resmi AppImage paketi.
|
||||
- **Windows Portable Exe:** Harici dosyalara ihtiyaç duymadan kendi simgesi ve arayüzüyle açılan taşınabilir Windows sürümü.
|
||||
- **Akıllı Konum & Donanım Tespiti:** Launcher artık doğrudan kendi bulunduğu dizini tanır, taşınabilir çalışır.
|
||||
- **Gelişmiş Oyun Arama:** Disklerde oyun bulunamadığında açıklayıcı modal uyarı penceresi ve anlık doğrulama.
|
||||
- **Otomatik Yama & FPS Ayarları:** 60/120/144/240 Hz pacing, sarı doku önleme ve sinematik atlama.
|
||||
files: |
|
||||
./dist/God_of_War_III_Launcher-x86_64.AppImage
|
||||
./dist/God_of_War_III_Launcher-Windows.exe
|
||||
./dist/gow3-launcher-win.exe
|
||||
./dist/gow3-launcher
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
@@ -1,11 +1,11 @@
|
||||
# gow3_pclauncher
|
||||
Launcher for God Of War 3 PC on Linux and Windows
|
||||
Launcher for God Of War 3 PC on Linux
|
||||
|
||||
# ⚡ God of War® III Remastered - Linux-Windows Port & Native Launcher
|
||||
# ⚡ God of War® III Remastered - Linux Port & Native Launcher
|
||||
|
||||
An optimized Linux-Windows port and native graphical launcher for **God of War® III Remastered** (*CUSA01623 / CUSA01715*), featuring hardware auto-tuning, 144Hz Delta-Time synchronization, crash diagnostics, and upstream GitHub integration.
|
||||
An optimized Linux port and native graphical launcher for **God of War® III Remastered** (*CUSA01623 / CUSA01715*), featuring hardware auto-tuning, 144Hz Delta-Time synchronization, crash diagnostics, and upstream GitHub integration.
|
||||
|
||||
[](https://kernel.org)
|
||||
[](https://kernel.org)
|
||||
[](https://www.rust-lang.org)
|
||||
[](https://www.vulkan.org)
|
||||
[](LICENSE)
|
||||
@@ -24,28 +24,19 @@ Launcher for God Of War 3 PC on Linux and Windows
|
||||
directories.
|
||||
- 🚨 **Crash & Error Diagnostic Assistant:** Automatically analyzes `gow3_log.txt` on exit. If an unexpected crash occurs, it displays a plain-language diagnosis and recommended fix.
|
||||
- 🔄 **GitHub Upstream Sync & Auto-Updater:** Checks upstream ([R-V-L/gow3_pc](https://github.com/R-V-L/gow3_pc)) for updates and re-applies all your custom directory paths, 144Hz patches, and VRAM budgets seamlessly.
|
||||
- 🌐 **Multi-Language Support:** Available in **Turkish 🇹🇷**, **English 🇬🇧**, **German 🇩🇪**, and **Spanish 🇪🇸**.
|
||||
|
||||
- 🌐 **Multi-Language Support:** Available in **Turkish 🇹🇷**, **English 🇬🇧**, **German 🇩🇪**, and **Spanish 🇪🇸**.
|
||||
|
||||
|
||||
|
||||
## 📋 System Requirements
|
||||
|
||||
| Component | Minimum | Recommended |
|
||||
|---|---|---|
|
||||
| **OS** | Linux (Arch, Ubuntu, Fedora, SteamOS, Debian) and Windows 10-11 | Any modern 64-bit Linux distro |
|
||||
| **OS** | Linux (Arch, Ubuntu, Fedora, SteamOS, Debian) | Any modern 64-bit Linux distro |
|
||||
| **CPU** | 6-core x86_64 processor | 8-core / 16-thread modern CPU |
|
||||
| **GPU** | Vulkan 1.3 compatible (4 GB VRAM) | Vulkan 1.3+ (6 GB+ VRAM, Nvidia / AMD) |
|
||||
| **RAM** | 8 GB | 16 GB+ |
|
||||
| **Dependencies** | Python 3, Vulkan drivers | `gamemode` (optional) |
|
||||
|
||||
## Video
|
||||
|
||||
You can watch the video for details.
|
||||
|
||||
<p align="center">
|
||||
<a href="https://www.youtube.com/watch?v=-yGAEjdQGzE"><img width="1920" height="1080" alt="vlc_ie5PhePn2o" src="https://github.com/user-attachments/assets/190f531e-55b0-4a4a-b883-440cd615a18a" /></a>
|
||||
</p>
|
||||
|
||||
| **Dependencies** | Python 3, Vulkan drivers | `gamemode` (optional) |
|
||||
|
||||
|
||||
|
||||
@@ -64,13 +55,9 @@ Launcher for God Of War 3 PC on Linux and Windows
|
||||
**Option B: Download Pre-compiled Binaries (GitHub Releases)**
|
||||
Download the executables directly from the GitHub Releases tab:
|
||||
- **Linux**: `gow3-launcher`
|
||||
- **Windows**: `gow3-launcher-win.exe`
|
||||
- **Windows / Dual-Boot**: `gow3-launcher-win.exe`
|
||||
|
||||
The launcher is completely standalone: it automatically detects your hardware, verifies the game dump, configures settings files, and applies all required patches without requiring external bash scripts.
|
||||
|
||||
|
||||
<img width="1920" height="1016" alt="gow3_launcher_win_BJ42UCuIvf" src="https://github.com/user-attachments/assets/3d57aaed-8869-446e-bdb7-89491275039d" />
|
||||
|
||||
|
||||
|
||||
### 2. Add Your Game Dump
|
||||
@@ -88,9 +75,6 @@ Launcher for God Of War 3 PC on Linux and Windows
|
||||
.\gow3-launcher-win.exe --play
|
||||
```
|
||||
|
||||
<img width="1920" height="1080" alt="gow3-probe_Hz51yYBACH" src="https://github.com/user-attachments/assets/651de8e7-15b9-454c-ab6d-a09dbd71f44e" />
|
||||
|
||||
|
||||
### 🔄 Dual-Boot Ready
|
||||
Both `gow3-launcher` and `gow3-launcher-win.exe` live side-by-side in the same directory. If you dual-boot between Linux and Windows, you can play on either operating system seamlessly while sharing the same game dumps and configurations!
|
||||
|
||||
@@ -131,12 +115,12 @@ Launcher for God Of War 3 PC on Linux and Windows
|
||||
|
||||
## 📜 Credits & Acknowledgments
|
||||
|
||||
- **Original Project:** [FelipePrado0](https://github.com/FelipePrado0/gow3_pc)
|
||||
- **Original Project:** https://github.com/FelipePrado0/gow3_pc
|
||||
- **Upstream Linux Port & Probe:** Developed by [R-V-L](https://github.com/R-V-L/gow3_pc) and community contributors.
|
||||
- **Launcher & Hardware Tuner:** Built with Rust, [egui/eframe](https://github.com/emilk/egui).
|
||||
|
||||
> **Disclaimer:** God of War is a registered trademark of Sony Interactive Entertainment LLC and Santa Monica Studio. This repository **does not contain any copyrighted game assets, ROMs, or binaries**. Users must supply their own legally obtained game files.
|
||||
|
||||
|
||||
## License
|
||||
#Licence
|
||||
GNU GPL v2 or later ([LICENSE](https://github.com/R-V-L/gow3_pc/blob/main/LICENSE)). Third-party components keep their own licenses.
|
||||
Binary file not shown.
Regular → Executable
BIN
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 449 KiB After Width: | Height: | Size: 12 KiB |
Binary file not shown.
+26
-305
@@ -67,8 +67,6 @@ pub struct LauncherApp {
|
||||
is_scanning: bool,
|
||||
scan_rx: Option<Receiver<Vec<GameCandidate>>>,
|
||||
found_candidates_modal: Option<Vec<GameCandidate>>,
|
||||
show_game_not_found_modal: bool,
|
||||
scan_failed_empty: bool,
|
||||
|
||||
// Updater state
|
||||
is_checking_update: bool,
|
||||
@@ -79,16 +77,6 @@ pub struct LauncherApp {
|
||||
is_game_running: bool,
|
||||
game_exit_rx: Option<Receiver<Option<i32>>>,
|
||||
|
||||
// Python dependency state
|
||||
has_python: bool,
|
||||
is_downloading_python: bool,
|
||||
python_dl_rx: Option<Receiver<Result<String, String>>>,
|
||||
|
||||
// Engine dependency state
|
||||
has_engine: bool,
|
||||
is_downloading_engine: bool,
|
||||
engine_dl_rx: Option<Receiver<Result<String, String>>>,
|
||||
|
||||
// Modals
|
||||
show_first_launch_modal: bool,
|
||||
active_crash_diagnosis: Option<CrashDiagnosis>,
|
||||
@@ -116,8 +104,6 @@ impl LauncherApp {
|
||||
let is_first = !config.first_launch_done;
|
||||
let game_valid = is_valid_game_dir(Path::new(&config.game_dir));
|
||||
let gamemode_avail = is_gamemode_available();
|
||||
let has_python = crate::runner::find_python(&base_dir).is_ok();
|
||||
let has_engine = crate::runner::find_game_engine(&base_dir).is_some();
|
||||
|
||||
let mut app = Self {
|
||||
base_dir,
|
||||
@@ -129,19 +115,11 @@ impl LauncherApp {
|
||||
is_scanning: false,
|
||||
scan_rx: None,
|
||||
found_candidates_modal: None,
|
||||
show_game_not_found_modal: false,
|
||||
scan_failed_empty: false,
|
||||
is_checking_update: false,
|
||||
update_rx: None,
|
||||
update_modal: None,
|
||||
is_game_running: false,
|
||||
game_exit_rx: None,
|
||||
has_python,
|
||||
is_downloading_python: false,
|
||||
python_dl_rx: None,
|
||||
has_engine,
|
||||
is_downloading_engine: false,
|
||||
engine_dl_rx: None,
|
||||
show_first_launch_modal: is_first,
|
||||
active_crash_diagnosis: None,
|
||||
show_log_modal: false,
|
||||
@@ -197,46 +175,21 @@ impl LauncherApp {
|
||||
}
|
||||
}
|
||||
|
||||
// Remastered title logo: gow3-remastered.png (checks base_dir, then embedded fallback)
|
||||
// Remastered title logo: gow3-remastered.png
|
||||
let logo_path = self.base_dir.join("gow3-remastered.png");
|
||||
let logo_img = if logo_path.is_file() {
|
||||
image::open(&logo_path).ok()
|
||||
} else {
|
||||
image::load_from_memory(include_bytes!("../../gow3-remastered.png")).ok()
|
||||
};
|
||||
if let Some(img) = logo_img {
|
||||
let size = [img.width() as _, img.height() as _];
|
||||
let img_buffer = img.to_rgba8();
|
||||
let pixels = img_buffer.as_flat_samples();
|
||||
let color_img = egui::ColorImage::from_rgba_unmultiplied(size, pixels.as_slice());
|
||||
self.logo_texture = Some(ctx.load_texture("gow3_remastered_logo", color_img, Default::default()));
|
||||
if logo_path.is_file() {
|
||||
if let Ok(img) = image::open(&logo_path) {
|
||||
let size = [img.width() as _, img.height() as _];
|
||||
let img_buffer = img.to_rgba8();
|
||||
let pixels = img_buffer.as_flat_samples();
|
||||
let color_img = egui::ColorImage::from_rgba_unmultiplied(size, pixels.as_slice());
|
||||
self.logo_texture = Some(ctx.load_texture("gow3_remastered_logo", color_img, Default::default()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn check_game_validity(&mut self) {
|
||||
self.is_game_valid = is_valid_game_dir(Path::new(&self.config.game_dir));
|
||||
if self.is_game_valid {
|
||||
self.scan_failed_empty = false;
|
||||
if let Some((_, is_err)) = self.status_message {
|
||||
if is_err {
|
||||
self.status_message = Some((self.t("game_valid").to_string(), false));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn set_game_directory(&mut self, path: &Path, ctx: &egui::Context) {
|
||||
self.config.game_dir = path.to_string_lossy().to_string();
|
||||
let _ = update_launch_scripts(&self.base_dir, path);
|
||||
let _ = self.config.save(&self.base_dir);
|
||||
self.check_game_validity();
|
||||
self.load_textures(ctx);
|
||||
self.scan_failed_empty = false;
|
||||
if self.is_game_valid {
|
||||
self.status_message = Some((self.t("game_valid").to_string(), false));
|
||||
} else {
|
||||
self.status_message = Some((self.t("game_invalid").to_string(), true));
|
||||
}
|
||||
}
|
||||
|
||||
fn apply_all_optimizations(&mut self) {
|
||||
@@ -268,7 +221,6 @@ impl LauncherApp {
|
||||
|
||||
fn start_game_scan(&mut self) {
|
||||
self.is_scanning = true;
|
||||
self.scan_failed_empty = false;
|
||||
let (tx, rx): (Sender<Vec<GameCandidate>>, Receiver<Vec<GameCandidate>>) = channel();
|
||||
self.scan_rx = Some(rx);
|
||||
|
||||
@@ -293,37 +245,6 @@ impl LauncherApp {
|
||||
});
|
||||
}
|
||||
|
||||
fn start_python_download(&mut self) {
|
||||
if self.is_downloading_python {
|
||||
return;
|
||||
}
|
||||
self.is_downloading_python = true;
|
||||
let (tx, rx) = channel();
|
||||
self.python_dl_rx = Some(rx);
|
||||
|
||||
let base_dir_clone = self.base_dir.clone();
|
||||
thread::spawn(move || {
|
||||
let res = crate::runner::download_portable_python(&base_dir_clone);
|
||||
let _ = tx.send(res);
|
||||
});
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
fn start_engine_download(&mut self) {
|
||||
if self.is_downloading_engine {
|
||||
return;
|
||||
}
|
||||
self.is_downloading_engine = true;
|
||||
let (tx, rx) = channel();
|
||||
self.engine_dl_rx = Some(rx);
|
||||
|
||||
let base_dir_clone = self.base_dir.clone();
|
||||
thread::spawn(move || {
|
||||
let res = crate::runner::download_engine(&base_dir_clone);
|
||||
let _ = tx.send(res);
|
||||
});
|
||||
}
|
||||
|
||||
fn launch_game(&mut self) {
|
||||
// Apply settings before launching
|
||||
self.apply_all_optimizations();
|
||||
@@ -365,12 +286,14 @@ impl eframe::App for LauncherApp {
|
||||
self.is_scanning = false;
|
||||
self.scan_rx = None;
|
||||
if candidates.is_empty() {
|
||||
let msg = self.t("scan_not_found_inline");
|
||||
let msg = match self.current_lang {
|
||||
Language::Turkish => "⚠️ Disklerde eksiksiz ve geçerli God of War III klasörü bulunamadı.",
|
||||
Language::English => "⚠️ No complete and valid God of War III directory found on drives.",
|
||||
Language::German => "⚠️ Kein vollständiger God of War III Ordner auf den Laufwerken gefunden.",
|
||||
Language::Spanish => "⚠️ No se encontró ninguna carpeta completa y válida en los discos.",
|
||||
};
|
||||
self.status_message = Some((msg.to_string(), true));
|
||||
self.scan_failed_empty = true;
|
||||
self.show_game_not_found_modal = true;
|
||||
} else {
|
||||
self.scan_failed_empty = false;
|
||||
// Open the candidates selection modal so the user chooses the exact one
|
||||
self.found_candidates_modal = Some(candidates);
|
||||
}
|
||||
@@ -405,41 +328,6 @@ impl eframe::App for LauncherApp {
|
||||
}
|
||||
}
|
||||
|
||||
// 4. Check background python downloader thread
|
||||
if let Some(ref rx) = self.python_dl_rx {
|
||||
if let Ok(res) = rx.try_recv() {
|
||||
self.is_downloading_python = false;
|
||||
self.python_dl_rx = None;
|
||||
match res {
|
||||
Ok(_) => {
|
||||
self.has_python = true;
|
||||
self.status_message = Some((self.t("python_download_success").to_string(), false));
|
||||
}
|
||||
Err(e) => {
|
||||
self.status_message = Some((format!("{}{}", self.t("python_download_err"), e), true));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 5. Check background engine downloader thread
|
||||
if let Some(ref rx) = self.engine_dl_rx {
|
||||
if let Ok(res) = rx.try_recv() {
|
||||
self.is_downloading_engine = false;
|
||||
self.engine_dl_rx = None;
|
||||
match res {
|
||||
Ok(_) => {
|
||||
self.has_engine = true;
|
||||
self.has_python = crate::runner::find_python(&self.base_dir).is_ok();
|
||||
self.status_message = Some((self.t("engine_download_success").to_string(), false));
|
||||
}
|
||||
Err(e) => {
|
||||
self.status_message = Some((format!("❌ {}", e), true));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// --- FULL SCREEN BACKGROUND WALLPAPER ---
|
||||
if let Some(ref tex) = self.bg_texture {
|
||||
let painter = ui.painter();
|
||||
@@ -601,93 +489,6 @@ impl eframe::App for LauncherApp {
|
||||
ui.label(egui::RichText::new(format!("{} Hz", hw.refresh_rate_hz)).color(egui::Color32::from_rgb(130, 205, 135)).strong());
|
||||
});
|
||||
});
|
||||
|
||||
ui.add_space(8.0);
|
||||
ui.separator();
|
||||
ui.horizontal(|ui| {
|
||||
ui.label(egui::RichText::new(self.t("python_dep")).color(egui::Color32::LIGHT_GRAY).size(12.0));
|
||||
if self.has_python {
|
||||
ui.label(
|
||||
egui::RichText::new(self.t("python_ready"))
|
||||
.color(egui::Color32::from_rgb(102, 225, 106))
|
||||
.strong()
|
||||
.size(12.0),
|
||||
);
|
||||
} else {
|
||||
ui.label(
|
||||
egui::RichText::new(self.t("python_missing"))
|
||||
.color(egui::Color32::from_rgb(239, 83, 80))
|
||||
.strong()
|
||||
.size(12.0),
|
||||
);
|
||||
|
||||
ui.add_space(8.0);
|
||||
if self.is_downloading_python {
|
||||
ui.spinner();
|
||||
ui.label(
|
||||
egui::RichText::new(self.t("python_downloading"))
|
||||
.color(egui::Color32::from_rgb(255, 213, 79))
|
||||
.size(12.0),
|
||||
);
|
||||
} else {
|
||||
let dl_btn = egui::Button::new(
|
||||
egui::RichText::new(self.t("python_download"))
|
||||
.size(11.0)
|
||||
.color(egui::Color32::WHITE)
|
||||
.strong(),
|
||||
)
|
||||
.fill(egui::Color32::from_rgb(45, 120, 185))
|
||||
.corner_radius(egui::CornerRadius::same(5));
|
||||
|
||||
if ui.add(dl_btn).clicked() {
|
||||
self.start_python_download();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
ui.add_space(6.0);
|
||||
ui.horizontal(|ui| {
|
||||
ui.label(egui::RichText::new(self.t("engine_label")).color(egui::Color32::LIGHT_GRAY).size(12.0));
|
||||
if self.has_engine {
|
||||
ui.label(
|
||||
egui::RichText::new(self.t("engine_ready"))
|
||||
.color(egui::Color32::from_rgb(102, 225, 106))
|
||||
.strong()
|
||||
.size(12.0),
|
||||
);
|
||||
} else {
|
||||
ui.label(
|
||||
egui::RichText::new(self.t("engine_missing"))
|
||||
.color(egui::Color32::from_rgb(239, 83, 80))
|
||||
.strong()
|
||||
.size(12.0),
|
||||
);
|
||||
|
||||
ui.add_space(8.0);
|
||||
if self.is_downloading_engine {
|
||||
ui.spinner();
|
||||
ui.label(
|
||||
egui::RichText::new(self.t("engine_downloading"))
|
||||
.color(egui::Color32::from_rgb(255, 213, 79))
|
||||
.size(12.0),
|
||||
);
|
||||
} else {
|
||||
let dl_btn = egui::Button::new(
|
||||
egui::RichText::new(self.t("engine_download"))
|
||||
.size(11.0)
|
||||
.color(egui::Color32::WHITE)
|
||||
.strong(),
|
||||
)
|
||||
.fill(egui::Color32::from_rgb(180, 80, 45))
|
||||
.corner_radius(egui::CornerRadius::same(5));
|
||||
|
||||
if ui.add(dl_btn).clicked() {
|
||||
self.start_engine_download();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
// --- 2. GAME DIRECTORY CARD ---
|
||||
@@ -711,7 +512,11 @@ impl eframe::App for LauncherApp {
|
||||
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
|
||||
if ui.button(egui::RichText::new(self.t("manual_select")).strong()).clicked() {
|
||||
if let Some(folder) = rfd::FileDialog::new().pick_folder() {
|
||||
self.set_game_directory(&folder, &ctx);
|
||||
self.config.game_dir = folder.to_string_lossy().to_string();
|
||||
let _ = update_launch_scripts(&self.base_dir, &folder);
|
||||
let _ = self.config.save(&self.base_dir);
|
||||
self.check_game_validity();
|
||||
self.load_textures(&ctx);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -724,7 +529,7 @@ impl eframe::App for LauncherApp {
|
||||
});
|
||||
});
|
||||
|
||||
// Validation badge & Scan status
|
||||
// Validation badge
|
||||
ui.add_space(4.0);
|
||||
if self.is_game_valid {
|
||||
ui.label(
|
||||
@@ -739,25 +544,6 @@ impl eframe::App for LauncherApp {
|
||||
.strong(),
|
||||
);
|
||||
}
|
||||
|
||||
if self.scan_failed_empty {
|
||||
ui.add_space(6.0);
|
||||
egui::Frame::group(ui.style())
|
||||
.fill(egui::Color32::from_rgba_unmultiplied(65, 20, 20, 215))
|
||||
.stroke(egui::Stroke::new(1.0, egui::Color32::from_rgb(245, 80, 80)))
|
||||
.inner_margin(10.0)
|
||||
.corner_radius(egui::CornerRadius::same(6))
|
||||
.show(ui, |ui| {
|
||||
ui.horizontal(|ui| {
|
||||
ui.label(egui::RichText::new("⚠️").size(18.0));
|
||||
ui.label(
|
||||
egui::RichText::new(self.t("scan_not_found_inline"))
|
||||
.color(egui::Color32::from_rgb(255, 140, 140))
|
||||
.strong(),
|
||||
);
|
||||
});
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// --- 3. PATCHES & OPTIMIZATIONS CARD ---
|
||||
@@ -944,7 +730,11 @@ impl eframe::App for LauncherApp {
|
||||
|
||||
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
|
||||
if ui.button(egui::RichText::new(self.t("select_this")).color(egui::Color32::from_rgb(105, 225, 110)).strong()).clicked() {
|
||||
self.set_game_directory(&c.path, &ctx);
|
||||
self.config.game_dir = c.path.to_string_lossy().to_string();
|
||||
let _ = update_launch_scripts(&self.base_dir, &c.path);
|
||||
let _ = self.config.save(&self.base_dir);
|
||||
self.check_game_validity();
|
||||
self.load_textures(&ctx);
|
||||
self.found_candidates_modal = None;
|
||||
let selected_name = c.title.clone();
|
||||
self.status_message = Some((format!("✅ {} seçildi ve kaydedildi!", selected_name), false));
|
||||
@@ -965,75 +755,6 @@ impl eframe::App for LauncherApp {
|
||||
});
|
||||
}
|
||||
|
||||
// --- MODAL: GAME NOT FOUND WARNING ---
|
||||
if self.show_game_not_found_modal {
|
||||
egui::Window::new(self.t("game_not_found_modal_title"))
|
||||
.collapsible(false)
|
||||
.resizable(false)
|
||||
.default_width(520.0)
|
||||
.anchor(egui::Align2::CENTER_CENTER, egui::vec2(0.0, 0.0))
|
||||
.show(&ctx, |ui| {
|
||||
ui.vertical_centered(|ui| {
|
||||
ui.add_space(6.0);
|
||||
ui.label(
|
||||
egui::RichText::new("⚠️")
|
||||
.size(36.0)
|
||||
.color(egui::Color32::from_rgb(255, 175, 50)),
|
||||
);
|
||||
ui.add_space(4.0);
|
||||
ui.label(
|
||||
egui::RichText::new(self.t("game_not_found_title"))
|
||||
.size(17.0)
|
||||
.strong()
|
||||
.color(egui::Color32::from_rgb(255, 105, 105)),
|
||||
);
|
||||
ui.add_space(6.0);
|
||||
});
|
||||
|
||||
let box_frame = egui::Frame::group(ui.style())
|
||||
.fill(egui::Color32::from_rgba_unmultiplied(35, 22, 22, 225))
|
||||
.stroke(egui::Stroke::new(1.0, egui::Color32::from_rgba_unmultiplied(230, 60, 60, 110)))
|
||||
.inner_margin(12.0)
|
||||
.corner_radius(egui::CornerRadius::same(8));
|
||||
|
||||
box_frame.show(ui, |ui| {
|
||||
ui.label(
|
||||
egui::RichText::new(self.t("game_not_found_desc"))
|
||||
.size(13.0)
|
||||
.color(egui::Color32::from_rgb(225, 225, 230)),
|
||||
);
|
||||
});
|
||||
|
||||
ui.add_space(10.0);
|
||||
ui.horizontal(|ui| {
|
||||
let manual_btn = egui::Button::new(
|
||||
egui::RichText::new(self.t("manual_select"))
|
||||
.strong()
|
||||
.color(egui::Color32::WHITE),
|
||||
)
|
||||
.fill(egui::Color32::from_rgb(45, 105, 205))
|
||||
.corner_radius(egui::CornerRadius::same(6))
|
||||
.min_size(egui::vec2(130.0, 32.0));
|
||||
|
||||
if ui.add(manual_btn).clicked() {
|
||||
if let Some(folder) = rfd::FileDialog::new().pick_folder() {
|
||||
self.set_game_directory(&folder, &ctx);
|
||||
self.show_game_not_found_modal = false;
|
||||
}
|
||||
}
|
||||
|
||||
ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| {
|
||||
let close_btn = egui::Button::new(self.t("close"))
|
||||
.min_size(egui::vec2(90.0, 32.0));
|
||||
if ui.add(close_btn).clicked() {
|
||||
self.show_game_not_found_modal = false;
|
||||
}
|
||||
});
|
||||
});
|
||||
ui.add_space(4.0);
|
||||
});
|
||||
}
|
||||
|
||||
// --- MODAL 2: FIRST LAUNCH SETUP ---
|
||||
if self.show_first_launch_modal {
|
||||
egui::Window::new(self.t("first_launch_title"))
|
||||
|
||||
@@ -86,10 +86,6 @@ pub fn text(lang: Language, key: &str) -> &'static str {
|
||||
(Language::Turkish, "first_launch_auto") => "⚡ Otomatik Tara ve Yapılandır",
|
||||
(Language::Turkish, "first_launch_manual") => "🔧 Manuel Olarak Kendim Ayarlayacağım",
|
||||
(Language::Turkish, "candidates_modal_title") => "🎮 Bulunan God of War III Klasörleri",
|
||||
(Language::Turkish, "game_not_found_modal_title") => "⚠️ Oyun Bulunamadı",
|
||||
(Language::Turkish, "game_not_found_title") => "Sistemde God of War III Yüklü Değil!",
|
||||
(Language::Turkish, "game_not_found_desc") => "Diskleriniz tarandı ancak geçerli bir God of War III Remastered (CUSA01623 / CUSA01715) kurulumu tespit edilemedi.\n\n• Oyun henüz sisteminizde yüklü olmayabilir.\n• Oyun harici bir diskte veya özel bir klasördeyse, lütfen aşağıdaki 'Manuel Seç' butonunu kullanarak 'eboot.bin' dosyasının bulunduğu ana oyun klasörünü seçin.",
|
||||
(Language::Turkish, "scan_not_found_inline") => "⚠️ Sistemde oyun yüklü değil veya klasör bulunamadı! Lütfen oyunu kurun veya 'Manuel Seç' butonunu kullanın.",
|
||||
(Language::Turkish, "select_this") => "Bu Klasörü Kullan",
|
||||
(Language::Turkish, "close") => "Kapat",
|
||||
(Language::Turkish, "diagnosis_title") => "🚨 Oyun Kapanma & Hata Teşhis Raporu",
|
||||
@@ -109,19 +105,6 @@ pub fn text(lang: Language, key: &str) -> &'static str {
|
||||
(Language::Turkish, "latest_commit") => "Son Değişiklik:",
|
||||
(Language::Turkish, "commit_date") => "Tarih:",
|
||||
(Language::Turkish, "view_on_github") => "🌐 GitHub'da Görüntüle",
|
||||
(Language::Turkish, "python_dep") => "Python 3 Bağımlılığı:",
|
||||
(Language::Turkish, "python_ready") => "Kurulu / Hazır",
|
||||
(Language::Turkish, "python_missing") => "Bulunamadı",
|
||||
(Language::Turkish, "python_download") => "📥 Taşınabilir Python 3 İndir (~10 MB, Kurulumsuz)",
|
||||
(Language::Turkish, "python_downloading") => "⏳ Python 3 indiriliyor ve hazırlanıyor...",
|
||||
(Language::Turkish, "python_download_success") => "✅ Taşınabilir Python 3 başarıyla kuruldu ve hazırlandı!",
|
||||
(Language::Turkish, "python_download_err") => "❌ Python 3 indirilemedi: ",
|
||||
(Language::Turkish, "engine_label") => "⚙️ Oyun Motoru:",
|
||||
(Language::Turkish, "engine_ready") => "Kurulu / Hazır (Vulkan Native)",
|
||||
(Language::Turkish, "engine_missing") => "Bulunamadı / Eksik!",
|
||||
(Language::Turkish, "engine_download") => "📥 Motoru Otomatik İndir (~74 MB)",
|
||||
(Language::Turkish, "engine_downloading") => "⏳ Oyun motoru paketi indiriliyor ve kuruluyor...",
|
||||
(Language::Turkish, "engine_download_success") => "✅ Oyun motoru başarıyla kuruldu!",
|
||||
|
||||
// English
|
||||
(Language::English, "app_title") => "GOD OF WAR® III REMASTERED",
|
||||
@@ -165,10 +148,6 @@ pub fn text(lang: Language, key: &str) -> &'static str {
|
||||
(Language::English, "first_launch_auto") => "⚡ Auto Scan & Configure",
|
||||
(Language::English, "first_launch_manual") => "🔧 I will configure manually",
|
||||
(Language::English, "candidates_modal_title") => "🎮 Found God of War III Directories",
|
||||
(Language::English, "game_not_found_modal_title") => "⚠️ Game Not Found",
|
||||
(Language::English, "game_not_found_title") => "God of War III Is Not Installed!",
|
||||
(Language::English, "game_not_found_desc") => "All drives were scanned, but a valid God of War III Remastered (CUSA01623 / CUSA01715) installation was not found.\n\n• The game might not be installed on your system yet.\n• If the game is on an external drive or custom folder, use the 'Browse Folder' button below to select the directory containing 'eboot.bin'.",
|
||||
(Language::English, "scan_not_found_inline") => "⚠️ Game is not installed on the system or folder not found! Please install the game or use 'Browse Folder'.",
|
||||
(Language::English, "select_this") => "Use This Folder",
|
||||
(Language::English, "close") => "Close",
|
||||
(Language::English, "diagnosis_title") => "🚨 Game Crash & Error Diagnosis Report",
|
||||
@@ -188,19 +167,6 @@ pub fn text(lang: Language, key: &str) -> &'static str {
|
||||
(Language::English, "latest_commit") => "Latest Commit:",
|
||||
(Language::English, "commit_date") => "Date:",
|
||||
(Language::English, "view_on_github") => "🌐 View on GitHub",
|
||||
(Language::English, "python_dep") => "Python 3 Dependency:",
|
||||
(Language::English, "python_ready") => "Installed / Ready",
|
||||
(Language::English, "python_missing") => "Not Found",
|
||||
(Language::English, "python_download") => "📥 Download Portable Python 3 (~10 MB, No Install)",
|
||||
(Language::English, "python_downloading") => "⏳ Downloading & configuring Python 3...",
|
||||
(Language::English, "python_download_success") => "✅ Portable Python 3 installed and configured successfully!",
|
||||
(Language::English, "python_download_err") => "❌ Failed to download Python 3: ",
|
||||
(Language::English, "engine_label") => "⚙️ Game Engine:",
|
||||
(Language::English, "engine_ready") => "Installed / Ready (Vulkan Native)",
|
||||
(Language::English, "engine_missing") => "Not Found / Missing!",
|
||||
(Language::English, "engine_download") => "📥 Download Engine (~74 MB)",
|
||||
(Language::English, "engine_downloading") => "⏳ Downloading and configuring game engine...",
|
||||
(Language::English, "engine_download_success") => "✅ Game engine installed successfully!",
|
||||
|
||||
// German
|
||||
(Language::German, "app_title") => "GOD OF WAR® III REMASTERED",
|
||||
@@ -244,10 +210,6 @@ pub fn text(lang: Language, key: &str) -> &'static str {
|
||||
(Language::German, "first_launch_auto") => "⚡ Automatisch scannen & konfigurieren",
|
||||
(Language::German, "first_launch_manual") => "🔧 Manuell konfigurieren",
|
||||
(Language::German, "candidates_modal_title") => "🎮 Gefundene Spielordner",
|
||||
(Language::German, "game_not_found_modal_title") => "⚠️ Spiel nicht gefunden",
|
||||
(Language::German, "game_not_found_title") => "God of War III ist nicht installiert!",
|
||||
(Language::German, "game_not_found_desc") => "Alle Laufwerke wurden durchsucht, aber es wurde keine gültige God of War III Remastered (CUSA01623 / CUSA01715) Installation gefunden.\n\n• Das Spiel ist möglicherweise noch nicht installiert.\n• Wenn sich das Spiel auf einem externen Laufwerk befindet, wählen Sie den Ordner bitte mit 'Durchsuchen' aus.",
|
||||
(Language::German, "scan_not_found_inline") => "⚠️ Das Spiel ist nicht auf dem System installiert oder der Ordner wurde nicht gefunden! Bitte installieren Sie das Spiel oder nutzen Sie 'Durchsuchen'.",
|
||||
(Language::German, "select_this") => "Diesen Ordner wählen",
|
||||
(Language::German, "close") => "Schließen",
|
||||
(Language::German, "diagnosis_title") => "🚨 Fehlerdiagnose-Bericht",
|
||||
@@ -267,19 +229,6 @@ pub fn text(lang: Language, key: &str) -> &'static str {
|
||||
(Language::German, "latest_commit") => "Letzter Commit:",
|
||||
(Language::German, "commit_date") => "Datum:",
|
||||
(Language::German, "view_on_github") => "🌐 Auf GitHub ansehen",
|
||||
(Language::German, "python_dep") => "Python 3 Abhängigkeit:",
|
||||
(Language::German, "python_ready") => "Installiert / Bereit",
|
||||
(Language::German, "python_missing") => "Nicht gefunden",
|
||||
(Language::German, "python_download") => "📥 Portables Python 3 herunterladen (~10 MB, Ohne Installation)",
|
||||
(Language::German, "python_downloading") => "⏳ Python 3 wird heruntergeladen und eingerichtet...",
|
||||
(Language::German, "python_download_success") => "✅ Portables Python 3 erfolgreich eingerichtet!",
|
||||
(Language::German, "python_download_err") => "❌ Fehler beim Herunterladen von Python 3: ",
|
||||
(Language::German, "engine_label") => "⚙️ Spiel-Engine:",
|
||||
(Language::German, "engine_ready") => "Installiert / Bereit (Vulkan Native)",
|
||||
(Language::German, "engine_missing") => "Nicht gefunden / Fehlt!",
|
||||
(Language::German, "engine_download") => "📥 Engine herunterladen (~74 MB)",
|
||||
(Language::German, "engine_downloading") => "⏳ Spiel-Engine wird heruntergeladen und eingerichtet...",
|
||||
(Language::German, "engine_download_success") => "✅ Spiel-Engine erfolgreich installiert!",
|
||||
|
||||
// Spanish
|
||||
(Language::Spanish, "app_title") => "GOD OF WAR® III REMASTERED",
|
||||
@@ -323,10 +272,6 @@ pub fn text(lang: Language, key: &str) -> &'static str {
|
||||
(Language::Spanish, "first_launch_auto") => "⚡ Escanear y Configurar",
|
||||
(Language::Spanish, "first_launch_manual") => "🔧 Configurar Manualmente",
|
||||
(Language::Spanish, "candidates_modal_title") => "🎮 Carpetas Encontradas",
|
||||
(Language::Spanish, "game_not_found_modal_title") => "⚠️ Juego no encontrado",
|
||||
(Language::Spanish, "game_not_found_title") => "¡God of War III no está instalado!",
|
||||
(Language::Spanish, "game_not_found_desc") => "Se escanearon todas las unidades pero no se encontró una instalación válida de God of War III Remastered (CUSA01623 / CUSA01715).\n\n• Es posible que el juego aún no esté instalado en su sistema.\n• Si el juego está en una unidad externa o carpeta personalizada, use el botón 'Explorar' para seleccionar la carpeta que contiene 'eboot.bin'.",
|
||||
(Language::Spanish, "scan_not_found_inline") => "⚠️ ¡El juego no está instalado en el sistema o no se encontró la carpeta! Por favor instale el juego o use 'Explorar'.",
|
||||
(Language::Spanish, "select_this") => "Usar Esta Carpeta",
|
||||
(Language::Spanish, "close") => "Cerrar",
|
||||
(Language::Spanish, "diagnosis_title") => "🚨 Informe de Diagnóstico de Error",
|
||||
@@ -346,19 +291,6 @@ pub fn text(lang: Language, key: &str) -> &'static str {
|
||||
(Language::Spanish, "latest_commit") => "Último Commit:",
|
||||
(Language::Spanish, "commit_date") => "Fecha:",
|
||||
(Language::Spanish, "view_on_github") => "🌐 Ver en GitHub",
|
||||
(Language::Spanish, "python_dep") => "Dependencia Python 3:",
|
||||
(Language::Spanish, "python_ready") => "Instalado / Listo",
|
||||
(Language::Spanish, "python_missing") => "No encontrado",
|
||||
(Language::Spanish, "python_download") => "📥 Descargar Python 3 portable (~10 MB, Sin instalación)",
|
||||
(Language::Spanish, "python_downloading") => "⏳ Descargando y configurando Python 3...",
|
||||
(Language::Spanish, "python_download_success") => "✅ ¡Python 3 portable configurado con éxito!",
|
||||
(Language::Spanish, "python_download_err") => "❌ Error al descargar Python 3: ",
|
||||
(Language::Spanish, "engine_label") => "⚙️ Motor del Juego:",
|
||||
(Language::Spanish, "engine_ready") => "Instalado / Listo (Vulkan Native)",
|
||||
(Language::Spanish, "engine_missing") => "¡No encontrado / Falta!",
|
||||
(Language::Spanish, "engine_download") => "📥 Descargar Motor (~74 MB)",
|
||||
(Language::Spanish, "engine_downloading") => "⏳ Descargando y configurando motor de juego...",
|
||||
(Language::Spanish, "engine_download_success") => "✅ ¡Motor de juego instalado con éxito!",
|
||||
|
||||
_ => "",
|
||||
}
|
||||
|
||||
+18
-34
@@ -13,24 +13,12 @@ use eframe::egui;
|
||||
use std::path::PathBuf;
|
||||
|
||||
fn main() -> eframe::Result<()> {
|
||||
// Determine base_dir:
|
||||
// 1. If running as an AppImage, use the directory where the .AppImage file is located
|
||||
// 2. If running as standalone executable, use the folder containing the binary
|
||||
// 3. Fallback to current working directory
|
||||
let base_dir = if let Ok(appimage) = std::env::var("APPIMAGE") {
|
||||
PathBuf::from(appimage).parent().unwrap_or(&PathBuf::from(".")).to_path_buf()
|
||||
} else if let Ok(exe_path) = std::env::current_exe() {
|
||||
let exe_dir = exe_path.parent().unwrap_or(&PathBuf::from(".")).to_path_buf();
|
||||
let cur = std::env::current_dir().unwrap_or_else(|_| PathBuf::from("."));
|
||||
if cur.ends_with("launcher") {
|
||||
cur.parent().unwrap_or(&cur).to_path_buf()
|
||||
} else if exe_dir.ends_with("target/release") || exe_dir.ends_with("target/debug") {
|
||||
cur
|
||||
} else {
|
||||
exe_dir
|
||||
}
|
||||
// Determine base_dir: If running inside 'launcher' folder, go up to parent, else use current dir
|
||||
let current_dir = std::env::current_dir().unwrap_or_else(|_| PathBuf::from("."));
|
||||
let base_dir = if current_dir.ends_with("launcher") {
|
||||
current_dir.parent().unwrap_or(¤t_dir).to_path_buf()
|
||||
} else {
|
||||
std::env::current_dir().unwrap_or_else(|_| PathBuf::from("."))
|
||||
current_dir
|
||||
};
|
||||
|
||||
let args: Vec<String> = std::env::args().collect();
|
||||
@@ -61,23 +49,19 @@ fn main() -> eframe::Result<()> {
|
||||
.with_min_inner_size([650.0, 550.0])
|
||||
.with_resizable(true);
|
||||
|
||||
// Try load window icon: check base_dir first, then fallback to embedded asset
|
||||
let icon_data = if let Ok(img) = image::open(base_dir.join("gow3.png")) {
|
||||
let width = img.width();
|
||||
let height = img.height();
|
||||
let rgba = img.to_rgba8().into_raw();
|
||||
Some(egui::IconData { rgba, width, height })
|
||||
} else if let Ok(img) = image::load_from_memory(include_bytes!("../../gow3.png")) {
|
||||
let width = img.width();
|
||||
let height = img.height();
|
||||
let rgba = img.to_rgba8().into_raw();
|
||||
Some(egui::IconData { rgba, width, height })
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
if let Some(icon) = icon_data {
|
||||
viewport = viewport.with_icon(icon);
|
||||
// Try load window icon
|
||||
let icon_path = base_dir.join("gow3.png");
|
||||
if icon_path.is_file() {
|
||||
if let Ok(img) = image::open(&icon_path) {
|
||||
let width = img.width();
|
||||
let height = img.height();
|
||||
let rgba = img.to_rgba8().into_raw();
|
||||
viewport = viewport.with_icon(egui::IconData {
|
||||
rgba,
|
||||
width,
|
||||
height,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
let native_options = eframe::NativeOptions {
|
||||
|
||||
+16
-320
@@ -71,315 +71,15 @@ pub fn ensure_runtime_assets(base_dir: &Path) -> Result<(PathBuf, PathBuf), Stri
|
||||
Ok((scripts_dir, patches_dir))
|
||||
}
|
||||
|
||||
/// Finds an available Python 3 interpreter (checking local runtime bundle first, then system PATH)
|
||||
pub fn find_python(base_dir: &Path) -> Result<String, String> {
|
||||
// 1. Check local runtime python folder (.runtime/python/python.exe or bin/python3)
|
||||
let candidates = [
|
||||
base_dir.join(".runtime/python/python.exe"),
|
||||
base_dir.join(".runtime/python/python"),
|
||||
base_dir.join(".runtime/python/bin/python3"),
|
||||
base_dir.join(".runtime/python/bin/python"),
|
||||
base_dir.join("python/python.exe"),
|
||||
];
|
||||
for p in &candidates {
|
||||
if p.is_file() {
|
||||
if let Ok(out) = Command::new(p).arg("--version").output() {
|
||||
if out.status.success() {
|
||||
return Ok(p.to_string_lossy().to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Check system-wide Python
|
||||
pub fn find_python() -> Result<String, String> {
|
||||
for cmd in &["python3", "python", "py"] {
|
||||
if let Ok(out) = Command::new(cmd).arg("--version").output() {
|
||||
if out.status.success() {
|
||||
let stdout = String::from_utf8_lossy(&out.stdout);
|
||||
let stderr = String::from_utf8_lossy(&out.stderr);
|
||||
let combined = format!("{} {}", stdout, stderr);
|
||||
if combined.contains("Python 3.") {
|
||||
return Ok(cmd.to_string());
|
||||
}
|
||||
return Ok(cmd.to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Err("Python 3 bulunamadı. Lütfen taşınabilir Python paketini indirin veya sisteminize kurun.".to_string())
|
||||
}
|
||||
|
||||
/// Automatically downloads and configures official portable Python 3 runtime into `.runtime/python`
|
||||
pub fn download_portable_python(base_dir: &Path) -> Result<String, String> {
|
||||
let runtime_dir = base_dir.join(".runtime");
|
||||
let python_dir = runtime_dir.join("python");
|
||||
let _ = fs::create_dir_all(&python_dir);
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
let ps_code = format!(
|
||||
r#"
|
||||
$ProgressPreference = 'SilentlyContinue';
|
||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;
|
||||
$url = 'https://www.python.org/ftp/python/3.11.9/python-3.11.9-embed-amd64.zip';
|
||||
$zip = Join-Path $env:TEMP 'gow3_python_embed.zip';
|
||||
$dest = '{}';
|
||||
if (Test-Path $zip) {{ Remove-Item $zip -Force }};
|
||||
Write-Host 'Downloading Python 3.11 embed package...';
|
||||
(New-Object System.Net.WebClient).DownloadFile($url, $zip);
|
||||
if (!(Test-Path $dest)) {{ New-Item -ItemType Directory -Path $dest -Force | Out-Null }};
|
||||
Write-Host 'Extracting archive...';
|
||||
Expand-Archive -Path $zip -DestinationPath $dest -Force;
|
||||
Remove-Item $zip -Force;
|
||||
"#,
|
||||
python_dir.to_string_lossy().replace('\'', "''")
|
||||
);
|
||||
|
||||
let status = Command::new("powershell")
|
||||
.args(["-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", &ps_code])
|
||||
.status()
|
||||
.map_err(|e| format!("PowerShell ile Python indirme komutu çalıştırılamadı: {}", e))?;
|
||||
|
||||
if !status.success() {
|
||||
return Err("PowerShell üzerinden Python 3 indirilemedi.".to_string());
|
||||
}
|
||||
|
||||
// Configure python311._pth to enable import site and recognize scripts directory
|
||||
let pth_file = python_dir.join("python311._pth");
|
||||
let pth_content = "python311.zip\n.\n..\n..\\scripts\n..\\..\\scripts\nimport site\n";
|
||||
let _ = fs::write(pth_file, pth_content);
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
{
|
||||
// On Linux / macOS fallback: if curl and unzip exist, download embed (usable with wine or testing)
|
||||
let zip_path = runtime_dir.join("python_embed.zip");
|
||||
let curl_res = Command::new("curl")
|
||||
.args([
|
||||
"-sL",
|
||||
"https://www.python.org/ftp/python/3.11.9/python-3.11.9-embed-amd64.zip",
|
||||
"-o",
|
||||
&zip_path.to_string_lossy(),
|
||||
])
|
||||
.status();
|
||||
|
||||
if let Ok(st) = curl_res {
|
||||
if st.success() {
|
||||
let _ = Command::new("unzip")
|
||||
.args(["-o", "-q", &zip_path.to_string_lossy(), "-d", &python_dir.to_string_lossy()])
|
||||
.status();
|
||||
let _ = fs::remove_file(&zip_path);
|
||||
|
||||
let pth_file = python_dir.join("python311._pth");
|
||||
let pth_content = "python311.zip\n.\n..\nimport site\n";
|
||||
let _ = fs::write(pth_file, pth_content);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
find_python(base_dir).map_err(|_| "Python 3 indirildi ancak doğrulanamadı.".to_string())
|
||||
}
|
||||
|
||||
/// Ensures Python 3 is available, automatically downloading portable package if missing
|
||||
pub fn ensure_python(base_dir: &Path) -> Result<String, String> {
|
||||
if let Ok(py) = find_python(base_dir) {
|
||||
return Ok(py);
|
||||
}
|
||||
download_portable_python(base_dir)
|
||||
}
|
||||
|
||||
pub fn find_game_engine(base_dir: &Path) -> Option<PathBuf> {
|
||||
#[cfg(target_os = "windows")]
|
||||
let probe_candidates = [
|
||||
base_dir.join("bin/gow3-probe.exe"),
|
||||
base_dir.join("out/gow3-probe.exe"),
|
||||
base_dir.join("gow3-probe.exe"),
|
||||
base_dir.join("bin/gow3.exe"),
|
||||
base_dir.join("gow3.exe"),
|
||||
base_dir.join("God of War III.exe"),
|
||||
];
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
let probe_candidates = [
|
||||
base_dir.join("bin/gow3-probe"),
|
||||
base_dir.join("out/gow3-probe"),
|
||||
base_dir.join("gow3-probe"),
|
||||
];
|
||||
|
||||
probe_candidates.into_iter().find(|p| p.is_file())
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn download_windows_engine(base_dir: &Path) -> Result<String, String> {
|
||||
let dest_bin = base_dir.join("bin");
|
||||
let _ = fs::create_dir_all(&dest_bin);
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
let ps_code = format!(
|
||||
r#"
|
||||
$ProgressPreference = 'SilentlyContinue';
|
||||
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12;
|
||||
$url = 'https://github.com/FelipePrado0/gow3_pc/releases/download/windows-v2.4.1/gow3-windows.zip';
|
||||
$zip = Join-Path $env:TEMP 'gow3_win_download.zip';
|
||||
$tempDir = Join-Path $env:TEMP 'gow3_win_extracted';
|
||||
if (Test-Path $tempDir) {{ Remove-Item $tempDir -Recurse -Force }};
|
||||
if (Test-Path $zip) {{ Remove-Item $zip -Force }};
|
||||
Write-Host 'Downloading Windows engine package (~74MB)...';
|
||||
(New-Object System.Net.WebClient).DownloadFile($url, $zip);
|
||||
Write-Host 'Extracting Windows package...';
|
||||
Expand-Archive -Path $zip -DestinationPath $tempDir -Force;
|
||||
|
||||
$probe = Get-ChildItem -Path $tempDir -Recurse -Filter "gow3-probe.exe" | Select-Object -First 1;
|
||||
if ($probe) {{
|
||||
$sourceBin = $probe.DirectoryName;
|
||||
$destBin = '{dest_bin}';
|
||||
if (!(Test-Path $destBin)) {{ New-Item -ItemType Directory -Path $destBin -Force | Out-Null }};
|
||||
Copy-Item "$sourceBin\*" -Destination $destBin -Recurse -Force;
|
||||
}} else {{
|
||||
throw "gow3-probe.exe extracted archive icinde bulunamadi!";
|
||||
}}
|
||||
|
||||
$base = '{base_dir}';
|
||||
$scripts = Get-ChildItem -Path $tempDir -Recurse -Directory -Filter "scripts" | Select-Object -First 1;
|
||||
if ($scripts -and !(Test-Path (Join-Path $base 'scripts'))) {{
|
||||
Copy-Item $scripts.FullName -Destination $base -Recurse -Force;
|
||||
}}
|
||||
$patches = Get-ChildItem -Path $tempDir -Recurse -Directory -Filter "patches" | Select-Object -First 1;
|
||||
if ($patches -and !(Test-Path (Join-Path $base 'patches'))) {{
|
||||
Copy-Item $patches.FullName -Destination $base -Recurse -Force;
|
||||
}}
|
||||
|
||||
Remove-Item $tempDir -Recurse -Force;
|
||||
Remove-Item $zip -Force;
|
||||
"#,
|
||||
dest_bin = dest_bin.to_string_lossy().replace('\'', "''"),
|
||||
base_dir = base_dir.to_string_lossy().replace('\'', "''")
|
||||
);
|
||||
|
||||
let status = Command::new("powershell")
|
||||
.args(["-NoProfile", "-ExecutionPolicy", "Bypass", "-Command", &ps_code])
|
||||
.status()
|
||||
.map_err(|e| format!("PowerShell Windows motoru indirme komutu çalıştırılamadı: {}", e))?;
|
||||
|
||||
if !status.success() {
|
||||
return Err("PowerShell üzerinden Windows motor paketi indirilemedi veya açılamadı.".to_string());
|
||||
}
|
||||
|
||||
if find_game_engine(base_dir).is_some() {
|
||||
return Ok("Windows oyun motoru başarıyla kuruldu!".to_string());
|
||||
}
|
||||
|
||||
Err("Windows oyun motoru ('bin/gow3-probe.exe') arşivden çıkarılamadı.".to_string())
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
{
|
||||
Err("Bu fonksiyon yalnızca Windows üzerinde çalışır.".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub fn download_linux_engine(base_dir: &Path) -> Result<String, String> {
|
||||
let dest_bin = base_dir.join("bin");
|
||||
let _ = fs::create_dir_all(&dest_bin);
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
{
|
||||
let url = "https://github.com/FelipePrado0/gow3_pc/releases/download/windows-v2.4.1/gow3-x86_64.AppImage";
|
||||
let temp_dir = std::env::temp_dir().join("gow3_linux_extracted");
|
||||
let _ = fs::remove_dir_all(&temp_dir);
|
||||
let _ = fs::create_dir_all(&temp_dir);
|
||||
let appimage_path = temp_dir.join("gow3-x86_64.AppImage");
|
||||
|
||||
let dl_status = Command::new("curl")
|
||||
.args(["-sL", url, "-o", &appimage_path.to_string_lossy()])
|
||||
.status();
|
||||
|
||||
let success = match dl_status {
|
||||
Ok(s) if s.success() => true,
|
||||
_ => {
|
||||
Command::new("wget")
|
||||
.args(["-q", url, "-O", &appimage_path.to_string_lossy()])
|
||||
.status()
|
||||
.map(|s| s.success())
|
||||
.unwrap_or(false)
|
||||
}
|
||||
};
|
||||
|
||||
if !success {
|
||||
let _ = fs::remove_dir_all(&temp_dir);
|
||||
return Err("Linux AppImage paketi indirilemedi (curl/wget başarısız oldu).".to_string());
|
||||
}
|
||||
|
||||
let _ = Command::new("chmod")
|
||||
.args(["+x", &appimage_path.to_string_lossy()])
|
||||
.status();
|
||||
|
||||
let ext_status = Command::new(&appimage_path)
|
||||
.arg("--appimage-extract")
|
||||
.current_dir(&temp_dir)
|
||||
.status();
|
||||
|
||||
if let Ok(st) = ext_status {
|
||||
if st.success() {
|
||||
let squash_bin = temp_dir.join("squashfs-root/bin");
|
||||
if squash_bin.is_dir() {
|
||||
let _ = Command::new("cp")
|
||||
.args(["-r", &format!("{}/.", squash_bin.to_string_lossy()), &dest_bin.to_string_lossy()])
|
||||
.status();
|
||||
let _ = Command::new("chmod")
|
||||
.args(["+x", &dest_bin.join("gow3-probe").to_string_lossy()])
|
||||
.status();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let _ = fs::remove_dir_all(&temp_dir);
|
||||
|
||||
if find_game_engine(base_dir).is_some() {
|
||||
return Ok("Linux oyun motoru başarıyla kuruldu!".to_string());
|
||||
}
|
||||
|
||||
Err("Linux oyun motoru paketten çıkarılamadı.".to_string())
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
Err("Bu fonksiyon yalnızca Linux üzerinde çalışır.".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn download_engine(base_dir: &Path) -> Result<String, String> {
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
download_windows_engine(base_dir)
|
||||
}
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
{
|
||||
download_linux_engine(base_dir)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn ensure_game_engine(base_dir: &Path) -> Result<PathBuf, String> {
|
||||
if let Some(p) = find_game_engine(base_dir) {
|
||||
return Ok(p);
|
||||
}
|
||||
|
||||
// Try automatic download if missing
|
||||
let _ = download_engine(base_dir);
|
||||
if let Some(p) = find_game_engine(base_dir) {
|
||||
return Ok(p);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
Err("Windows için oyun motoru ('bin/gow3-probe.exe') bulunamadı! Lütfen arayüzdeki '📥 Motoru İndir' butonuna basarak indirin.".to_string())
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
{
|
||||
Err("Linux için oyun motoru ('bin/gow3-probe') bulunamadı! Lütfen arayüzdeki '📥 Motoru İndir' butonuna basarak indirin.".to_string())
|
||||
}
|
||||
Err("Python 3 bulunamadı. Lütfen sisteminize 'python' kurun.".to_string())
|
||||
}
|
||||
|
||||
/// Executes the full God of War III preparation and probe execution natively from Rust.
|
||||
@@ -393,7 +93,17 @@ pub fn launch_gow3(
|
||||
return Err("Oyun klasöründe 'eboot.bin' bulunamadı!".to_string());
|
||||
}
|
||||
|
||||
let probe_bin = ensure_game_engine(base_dir)?;
|
||||
let probe_candidates = [
|
||||
base_dir.join("bin/gow3-probe"),
|
||||
base_dir.join("bin/gow3-probe.exe"),
|
||||
base_dir.join("out/gow3-probe"),
|
||||
base_dir.join("out/gow3-probe.exe"),
|
||||
base_dir.join("gow3-probe.exe"),
|
||||
];
|
||||
let probe_bin = probe_candidates
|
||||
.into_iter()
|
||||
.find(|p| p.is_file())
|
||||
.ok_or_else(|| "Oyun motoru ('gow3-probe' / 'gow3-probe.exe') bulunamadı!".to_string())?;
|
||||
|
||||
let out_dir = base_dir.join("out");
|
||||
fs::create_dir_all(&out_dir).map_err(|e| format!("'out' klasörü oluşturulamadı: {}", e))?;
|
||||
@@ -417,7 +127,7 @@ pub fn launch_gow3(
|
||||
.try_clone()
|
||||
.map_err(|e| format!("Log dosyası çoğaltılamadı: {}", e))?;
|
||||
|
||||
let python = ensure_python(base_dir)?;
|
||||
let python = find_python()?;
|
||||
|
||||
// 1. Run mods.py
|
||||
let _ = Command::new(&python)
|
||||
@@ -607,20 +317,6 @@ pub fn launch_gow3(
|
||||
cmd.env("GOW3_CONFIG", &config_ini);
|
||||
cmd.env("GOW3_GAME_DIR", game_dir);
|
||||
|
||||
// Prepend bin directory to PATH so Windows/Linux loaders find bundled libraries
|
||||
let bin_dir = base_dir.join("bin");
|
||||
if bin_dir.is_dir() {
|
||||
if let Some(existing_path) = std::env::var_os("PATH") {
|
||||
let mut paths = vec![bin_dir.clone()];
|
||||
paths.extend(std::env::split_paths(&existing_path));
|
||||
if let Ok(new_path) = std::env::join_paths(paths) {
|
||||
cmd.env("PATH", new_path);
|
||||
}
|
||||
} else {
|
||||
cmd.env("PATH", &bin_dir);
|
||||
}
|
||||
}
|
||||
|
||||
// Pipe stdout & stderr to gow3_log.txt
|
||||
cmd.stdout(Stdio::from(log_file));
|
||||
cmd.stderr(Stdio::from(log_file_err));
|
||||
@@ -637,7 +333,7 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_find_python() {
|
||||
let py = find_python(Path::new("."));
|
||||
let py = find_python();
|
||||
assert!(py.is_ok(), "Python 3 should be detected on the system");
|
||||
}
|
||||
|
||||
|
||||
+9
-23
@@ -15,13 +15,10 @@ pub fn is_valid_game_dir(path: &Path) -> bool {
|
||||
return false;
|
||||
}
|
||||
|
||||
let eboot = if path.join("eboot.bin").is_file() {
|
||||
path.join("eboot.bin")
|
||||
} else if path.join("EBOOT.BIN").is_file() {
|
||||
path.join("EBOOT.BIN")
|
||||
} else {
|
||||
let eboot = path.join("eboot.bin");
|
||||
if !eboot.is_file() {
|
||||
return false;
|
||||
};
|
||||
}
|
||||
|
||||
// 1. Verify eboot.bin size (genuine God of War III eboot is > 1MB, typically ~4.5MB)
|
||||
if let Ok(meta) = fs::metadata(&eboot) {
|
||||
@@ -33,17 +30,10 @@ pub fn is_valid_game_dir(path: &Path) -> bool {
|
||||
}
|
||||
|
||||
// 2. Verify sce_sys/param.sfo exists and has data
|
||||
let sfo = if path.join("sce_sys/param.sfo").is_file() {
|
||||
path.join("sce_sys/param.sfo")
|
||||
} else if path.join("sce_sys/PARAM.SFO").is_file() {
|
||||
path.join("sce_sys/PARAM.SFO")
|
||||
} else if path.join("SCE_SYS/param.sfo").is_file() {
|
||||
path.join("SCE_SYS/param.sfo")
|
||||
} else if path.join("SCE_SYS/PARAM.SFO").is_file() {
|
||||
path.join("SCE_SYS/PARAM.SFO")
|
||||
} else {
|
||||
let sfo = path.join("sce_sys/param.sfo");
|
||||
if !sfo.is_file() {
|
||||
return false;
|
||||
};
|
||||
}
|
||||
if let Ok(meta) = fs::metadata(&sfo) {
|
||||
if meta.len() < 100 {
|
||||
return false;
|
||||
@@ -53,13 +43,13 @@ pub fn is_valid_game_dir(path: &Path) -> bool {
|
||||
}
|
||||
|
||||
// 3. Verify at least one essential game directory exists (sce_module, EXEC, or language packs)
|
||||
let has_modules = path.join("sce_module").is_dir() || path.join("SCE_MODULE").is_dir();
|
||||
let has_exec = path.join("EXEC").is_dir() || path.join("exec").is_dir();
|
||||
let has_modules = path.join("sce_module").is_dir();
|
||||
let has_exec = path.join("EXEC").is_dir();
|
||||
let has_lang = [
|
||||
"ENGLISH", "DUTCH", "FRENCH", "GERMAN", "ITALIAN", "POLISH", "PORTUGUESE", "RUSSIAN", "SPANISH", "data",
|
||||
]
|
||||
.iter()
|
||||
.any(|lang| path.join(lang).is_dir() || path.join(lang.to_lowercase()).is_dir());
|
||||
.any(|lang| path.join(lang).is_dir());
|
||||
|
||||
has_modules || has_exec || has_lang
|
||||
}
|
||||
@@ -68,10 +58,6 @@ pub fn scan_for_game() -> Vec<GameCandidate> {
|
||||
let mut candidates = Vec::new();
|
||||
let mut scan_roots = Vec::new();
|
||||
|
||||
if let Ok(cur) = std::env::current_dir() {
|
||||
scan_roots.push(cur);
|
||||
}
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
if let Ok(userprofile) = std::env::var("USERPROFILE") {
|
||||
|
||||
+2
-54
@@ -179,68 +179,17 @@ fn detect_refresh_rate() -> u32 {
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
fn detect_gpu() -> (String, u64) {
|
||||
// 1. Try nvidia-smi first (exact VRAM for NVIDIA GPUs, e.g. RTX 4070 Laptop 8GB)
|
||||
if let Ok(output) = Command::new("nvidia-smi")
|
||||
.args(["--query-gpu=name,memory.total", "--format=csv,noheader,nounits"])
|
||||
.output()
|
||||
{
|
||||
if output.status.success() {
|
||||
let text = String::from_utf8_lossy(&output.stdout);
|
||||
if let Some(line) = text.lines().next() {
|
||||
let parts: Vec<&str> = line.split(',').collect();
|
||||
if parts.len() >= 2 {
|
||||
let name = parts[0].trim().to_string();
|
||||
let vram = parts[1].trim().parse::<u64>().unwrap_or(0);
|
||||
if vram > 0 {
|
||||
return (name, vram);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 2. Try Windows Registry for AMD / Intel / NVIDIA (64-bit QWORD qwMemorySize)
|
||||
let ps_script = r#"
|
||||
$g = Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Class\{4d36e968-e325-11ce-bfc1-08002be10318}\00*' -ErrorAction SilentlyContinue |
|
||||
Where-Object { $_.'HardwareInformation.qwMemorySize' -gt 0 } |
|
||||
Sort-Object 'HardwareInformation.qwMemorySize' -Descending |
|
||||
Select-Object -First 1;
|
||||
if ($g) {
|
||||
$name = if ($g.DriverDesc) { $g.DriverDesc } else { $g.'Device Description' };
|
||||
$vram = [int64]$g.'HardwareInformation.qwMemorySize';
|
||||
[PSCustomObject]@{ Name = $name; VRAM = $vram } | ConvertTo-Json -Compress
|
||||
}
|
||||
"#;
|
||||
if let Ok(output) = Command::new("powershell")
|
||||
.args(["-NoProfile", "-Command", ps_script])
|
||||
.output()
|
||||
{
|
||||
if output.status.success() {
|
||||
let text = String::from_utf8_lossy(&output.stdout);
|
||||
if let Ok(val) = serde_json::from_str::<serde_json::Value>(text.trim()) {
|
||||
let name = val["Name"].as_str().unwrap_or("Windows DirectX/Vulkan GPU").to_string();
|
||||
if let Some(vram_bytes) = val["VRAM"].as_u64() {
|
||||
let vram_mb = vram_bytes / (1024 * 1024);
|
||||
if vram_mb >= 1024 {
|
||||
return (name, vram_mb);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 3. Fallback to Win32_VideoController
|
||||
if let Ok(output) = Command::new("powershell")
|
||||
.args([
|
||||
"-NoProfile",
|
||||
"-Command",
|
||||
"Get-CimInstance Win32_VideoController | Sort-Object AdapterRAM -Descending | Select-Object -First 1 -Property Name,AdapterRAM | ConvertTo-Json -Compress",
|
||||
"Get-CimInstance Win32_VideoController | Select-Object -First 1 -Property Name,AdapterRAM | ConvertTo-Json",
|
||||
])
|
||||
.output()
|
||||
{
|
||||
if output.status.success() {
|
||||
let text = String::from_utf8_lossy(&output.stdout);
|
||||
if let Ok(val) = serde_json::from_str::<serde_json::Value>(text.trim()) {
|
||||
if let Ok(val) = serde_json::from_str::<serde_json::Value>(&text) {
|
||||
let name = val["Name"].as_str().unwrap_or("Windows DirectX/Vulkan GPU").to_string();
|
||||
let vram_bytes = val["AdapterRAM"].as_u64().unwrap_or(4 * 1024 * 1024 * 1024);
|
||||
let vram_mb = vram_bytes / (1024 * 1024);
|
||||
@@ -248,7 +197,6 @@ fn detect_gpu() -> (String, u64) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
("Windows DirectX/Vulkan GPU".to_string(), 4096)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"first_launch_done": true,
|
||||
"language": "tr",
|
||||
"game_dir": "/home/screamangel/İndirilenler/GOW3 Emu Linux/.CUSA01715",
|
||||
"game_dir": "/home/screamangel/İndirilenler/GOW3 Emu Linux/CUSA01623",
|
||||
"target_fps": 60,
|
||||
"patch_delta_time": true,
|
||||
"patch_readbacks": true,
|
||||
|
||||
Reference in new issue
Block a user