From 956ea24465f5448ad4fc6a524f37c5973a6df223 Mon Sep 17 00:00:00 2001 From: Omni Date: Thu, 23 Oct 2025 23:53:18 +0100 Subject: [PATCH] Sync from development - prepare for v0.1.6.3 --- CHANGELOG.md | 10 +++ jackify/__init__.py | 2 +- jackify/backend/handlers/modlist_handler.py | 71 ++++++++++++------- jackify/backend/handlers/wine_utils.py | 35 ++++++--- .../backend/handlers/winetricks_handler.py | 9 +++ 5 files changed, 89 insertions(+), 38 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index b946dbc..9f65709 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,15 @@ # Jackify Changelog +## v0.1.6.3 - Emergency Hotfix +**Release Date:** October 23, 2025 + +### Critical Bug Fixes +- **FIXED: Proton Detection for Custom Steam Libraries**: Now properly reads all Steam libraries from libraryfolders.vdf +- **IMPROVED: Registry Wine Binary Detection**: Uses user's configured Proton for better compatibility +- **IMPROVED: Error Handling**: Registry fixes now provide clear warnings if they fail instead of breaking entire workflow + +--- + ## v0.1.6.2 - Minor Bug Fixes **Release Date:** October 23, 2025 diff --git a/jackify/__init__.py b/jackify/__init__.py index 394fb26..17afcea 100644 --- a/jackify/__init__.py +++ b/jackify/__init__.py @@ -5,4 +5,4 @@ This package provides both CLI and GUI interfaces for managing Wabbajack modlists natively on Linux systems. """ -__version__ = "0.1.6.2" +__version__ = "0.1.6.3" diff --git a/jackify/backend/handlers/modlist_handler.py b/jackify/backend/handlers/modlist_handler.py index 9ad60a1..30a39e8 100644 --- a/jackify/backend/handlers/modlist_handler.py +++ b/jackify/backend/handlers/modlist_handler.py @@ -676,7 +676,20 @@ class ModlistHandler: if status_callback: status_callback(f"{self._get_progress_timestamp()} Applying universal dotnet4.x compatibility fixes") self.logger.info("Step 3.5: Applying universal dotnet4.x compatibility registry fixes...") - self._apply_universal_dotnet_fixes() + registry_success = False + try: + registry_success = self._apply_universal_dotnet_fixes() + except Exception as e: + self.logger.error(f"CRITICAL: Registry fixes failed - modlist may have .NET compatibility issues: {e}") + registry_success = False + + if not registry_success: + self.logger.error("=" * 80) + self.logger.error("WARNING: Universal dotnet4.x registry fixes FAILED!") + self.logger.error("This modlist may experience .NET Framework compatibility issues.") + self.logger.error("Consider manually setting mscoree=native in winecfg if problems occur.") + self.logger.error("=" * 80) + # Continue but user should be aware of potential issues # Step 4: Install Wine Components if status_callback: @@ -1551,35 +1564,41 @@ class ModlistHandler: return False def _find_wine_binary_for_registry(self) -> Optional[str]: - """Find the appropriate Wine binary for registry operations""" + """Find the appropriate Wine binary for registry operations using user's configured Proton""" try: - # Method 1: Try to detect from Steam's config or use Proton from compat data - # Look for wine binary in common Proton locations - proton_paths = [ - os.path.expanduser("~/.local/share/Steam/compatibilitytools.d"), - os.path.expanduser("~/.steam/steam/steamapps/common") - ] + # Use the user's configured Proton version from settings + from ..handlers.config_handler import ConfigHandler + config_handler = ConfigHandler() + user_proton_path = config_handler.get_game_proton_path() - for base_path in proton_paths: - if os.path.exists(base_path): - for item in os.listdir(base_path): - if 'proton' in item.lower(): - wine_path = os.path.join(base_path, item, 'files', 'bin', 'wine') - if os.path.exists(wine_path): - self.logger.debug(f"Found Wine binary: {wine_path}") - return wine_path + if user_proton_path and user_proton_path != 'auto': + # User has selected a specific Proton version + proton_path = Path(user_proton_path).expanduser() - # Method 2: Fallback to system wine if available - try: - result = subprocess.run(['which', 'wine'], capture_output=True, text=True) - if result.returncode == 0: - wine_path = result.stdout.strip() - self.logger.debug(f"Using system Wine binary: {wine_path}") - return wine_path - except Exception: - pass + # Check for wine binary in both GE-Proton and Valve Proton structures + wine_candidates = [ + proton_path / "files" / "bin" / "wine", # GE-Proton structure + proton_path / "dist" / "bin" / "wine" # Valve Proton structure + ] - self.logger.error("No suitable Wine binary found for registry operations") + for wine_path in wine_candidates: + if wine_path.exists(): + self.logger.info(f"Using Wine binary from user's configured Proton: {wine_path}") + return str(wine_path) + + self.logger.warning(f"User's configured Proton path has no wine binary: {user_proton_path}") + + # Fallback: Try to use same Steam library detection as main Proton detection + from ..handlers.wine_utils import WineUtils + best_proton = WineUtils.select_best_proton() + if best_proton: + wine_binary = WineUtils.find_proton_binary(best_proton['name']) + if wine_binary: + self.logger.info(f"Using Wine binary from detected Proton: {wine_binary}") + return wine_binary + + # NEVER fall back to system wine - it will break Proton prefixes with architecture mismatches + self.logger.error("No suitable Proton Wine binary found for registry operations") return None except Exception as e: diff --git a/jackify/backend/handlers/wine_utils.py b/jackify/backend/handlers/wine_utils.py index 0413147..6632604 100644 --- a/jackify/backend/handlers/wine_utils.py +++ b/jackify/backend/handlers/wine_utils.py @@ -777,27 +777,40 @@ class WineUtils: Returns: List of Path objects for Steam library directories """ + steam_common_paths = [] + try: from .path_handler import PathHandler # Use existing PathHandler that reads libraryfolders.vdf library_paths = PathHandler.get_all_steam_library_paths() + logger.info(f"PathHandler found Steam libraries: {library_paths}") + # Convert to steamapps/common paths for Proton scanning - steam_common_paths = [] for lib_path in library_paths: common_path = lib_path / "steamapps" / "common" if common_path.exists(): steam_common_paths.append(common_path) - logger.debug(f"Found Steam library paths: {steam_common_paths}") - return steam_common_paths + logger.debug(f"Added Steam library: {common_path}") + else: + logger.debug(f"Steam library path doesn't exist: {common_path}") + except Exception as e: - logger.warning(f"Failed to get Steam library paths from libraryfolders.vdf: {e}") - # Fallback to hardcoded paths if PathHandler fails - fallback_paths = [ - Path.home() / ".steam/steam/steamapps/common", - Path.home() / ".local/share/Steam/steamapps/common", - Path.home() / ".steam/root/steamapps/common" - ] - return [path for path in fallback_paths if path.exists()] + logger.error(f"PathHandler failed to read libraryfolders.vdf: {e}") + + # Always add fallback paths in case PathHandler missed something + fallback_paths = [ + Path.home() / ".steam/steam/steamapps/common", + Path.home() / ".local/share/Steam/steamapps/common", + Path.home() / ".steam/root/steamapps/common" + ] + + for fallback_path in fallback_paths: + if fallback_path.exists() and fallback_path not in steam_common_paths: + steam_common_paths.append(fallback_path) + logger.debug(f"Added fallback Steam library: {fallback_path}") + + logger.info(f"Final Steam library paths for Proton scanning: {steam_common_paths}") + return steam_common_paths @staticmethod def get_compatibility_tool_paths() -> List[Path]: diff --git a/jackify/backend/handlers/winetricks_handler.py b/jackify/backend/handlers/winetricks_handler.py index 0400140..36ff58e 100644 --- a/jackify/backend/handlers/winetricks_handler.py +++ b/jackify/backend/handlers/winetricks_handler.py @@ -169,9 +169,18 @@ class WinetricksHandler: if best_proton: wine_binary = WineUtils.find_proton_binary(best_proton['name']) self.logger.info(f"Auto-selected Proton: {best_proton['name']} at {best_proton['path']}") + else: + # Enhanced debugging for Proton detection failure + self.logger.error("Auto-detection failed - no Proton versions found") + available_versions = WineUtils.scan_all_proton_versions() + if available_versions: + self.logger.error(f"Available Proton versions: {[v['name'] for v in available_versions]}") + else: + self.logger.error("No Proton versions detected in standard Steam locations") if not wine_binary: self.logger.error("Cannot run winetricks: No compatible Proton version found") + self.logger.error("Please ensure you have Proton 9+ or GE-Proton installed through Steam") return False if not (os.path.exists(wine_binary) and os.access(wine_binary, os.X_OK)):