mirror of
https://github.com/Omni-guides/Jackify.git
synced 2026-01-17 19:47:00 +01:00
Sync from development - prepare for v0.2.0.10
This commit is contained in:
@@ -58,6 +58,8 @@ class ConfigHandler:
|
||||
"use_winetricks_for_components": True, # DEPRECATED: Migrated to component_installation_method. Kept for backward compatibility.
|
||||
"component_installation_method": "winetricks", # "winetricks" (default) or "system_protontricks"
|
||||
"game_proton_path": None, # Proton version for game shortcuts (can be any Proton 9+), separate from install proton
|
||||
"proton_path": None, # Install Proton path (for jackify-engine) - None means auto-detect
|
||||
"proton_version": None, # Install Proton version name - None means auto-detect
|
||||
"steam_restart_strategy": "jackify", # "jackify" (default) or "nak_simple"
|
||||
"window_width": None, # Saved window width (None = use dynamic sizing)
|
||||
"window_height": None # Saved window height (None = use dynamic sizing)
|
||||
@@ -757,16 +759,20 @@ class ConfigHandler:
|
||||
Always reads fresh from disk.
|
||||
|
||||
Returns:
|
||||
str: Saved Install Proton path or 'auto' if not saved
|
||||
str: Saved Install Proton path, or None if not set (indicates auto-detect mode)
|
||||
"""
|
||||
try:
|
||||
config = self._read_config_from_disk()
|
||||
proton_path = config.get("proton_path", "auto")
|
||||
proton_path = config.get("proton_path")
|
||||
# Return None if missing/None/empty string - don't default to "auto"
|
||||
if not proton_path:
|
||||
logger.debug("proton_path not set in config - will use auto-detection")
|
||||
return None
|
||||
logger.debug(f"Retrieved fresh install proton_path from config: {proton_path}")
|
||||
return proton_path
|
||||
except Exception as e:
|
||||
logger.error(f"Error retrieving install proton_path: {e}")
|
||||
return "auto"
|
||||
return None
|
||||
|
||||
def get_game_proton_path(self):
|
||||
"""
|
||||
@@ -775,7 +781,7 @@ class ConfigHandler:
|
||||
Always reads fresh from disk.
|
||||
|
||||
Returns:
|
||||
str: Saved Game Proton path, Install Proton path, or 'auto' if not saved
|
||||
str: Saved Game Proton path, Install Proton path, or None if not saved (indicates auto-detect mode)
|
||||
"""
|
||||
try:
|
||||
config = self._read_config_from_disk()
|
||||
@@ -783,8 +789,12 @@ class ConfigHandler:
|
||||
|
||||
# If game proton not set or set to same_as_install, use install proton
|
||||
if not game_proton_path or game_proton_path == "same_as_install":
|
||||
game_proton_path = config.get("proton_path", "auto")
|
||||
game_proton_path = config.get("proton_path") # Returns None if not set
|
||||
|
||||
# Return None if missing/None/empty string
|
||||
if not game_proton_path:
|
||||
logger.debug("game_proton_path not set in config - will use auto-detection")
|
||||
return None
|
||||
logger.debug(f"Retrieved fresh game proton_path from config: {game_proton_path}")
|
||||
return game_proton_path
|
||||
except Exception as e:
|
||||
@@ -821,15 +831,20 @@ class ConfigHandler:
|
||||
logger.info(f"Auto-detected Proton: {best_proton['name']} ({proton_type})")
|
||||
self.save_config()
|
||||
else:
|
||||
# Fallback to auto-detect mode
|
||||
self.settings["proton_path"] = "auto"
|
||||
self.settings["proton_version"] = "auto"
|
||||
logger.info("No compatible Proton versions found, using auto-detect mode")
|
||||
# Set proton_path to None (will appear as null in JSON) so jackify-engine doesn't get invalid path
|
||||
# Code will auto-detect on each run when proton_path is None
|
||||
self.settings["proton_path"] = None
|
||||
self.settings["proton_version"] = None
|
||||
logger.warning("No compatible Proton versions found - proton_path set to null in config.json")
|
||||
logger.info("Jackify will auto-detect Proton on each run until a valid version is found")
|
||||
self.save_config()
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"Failed to auto-detect Proton: {e}")
|
||||
self.settings["proton_path"] = "auto"
|
||||
self.settings["proton_version"] = "auto"
|
||||
# Set proton_path to None (will appear as null in JSON)
|
||||
self.settings["proton_path"] = None
|
||||
self.settings["proton_version"] = None
|
||||
logger.warning("proton_path set to null in config.json due to auto-detection failure")
|
||||
self.save_config()
|
||||
|
||||
|
||||
@@ -105,9 +105,9 @@ class ModlistHandler:
|
||||
verbose: Boolean indicating if verbose output is desired.
|
||||
filesystem_handler: Optional FileSystemHandler instance to use instead of creating a new one.
|
||||
"""
|
||||
# Use standard logging (no file handler)
|
||||
# Use standard logging (propagate to root logger so messages appear in logs)
|
||||
self.logger = logging.getLogger(__name__)
|
||||
self.logger.propagate = False
|
||||
self.logger.propagate = True
|
||||
self.steamdeck = steamdeck
|
||||
|
||||
# DEBUG: Log ModlistHandler instantiation details for SD card path debugging
|
||||
@@ -746,15 +746,20 @@ class ModlistHandler:
|
||||
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}")
|
||||
error_msg = f"CRITICAL: Registry fixes failed - modlist may have .NET compatibility issues: {e}"
|
||||
self.logger.error(error_msg)
|
||||
if status_callback:
|
||||
status_callback(f"{self._get_progress_timestamp()} ERROR: {error_msg}")
|
||||
registry_success = False
|
||||
|
||||
if not registry_success:
|
||||
failure_msg = "WARNING: Universal dotnet4.x registry fixes FAILED! This modlist may experience .NET Framework compatibility issues."
|
||||
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(failure_msg)
|
||||
self.logger.error("Consider manually setting mscoree=native in winecfg if problems occur.")
|
||||
self.logger.error("=" * 80)
|
||||
if status_callback:
|
||||
status_callback(f"{self._get_progress_timestamp()} {failure_msg}")
|
||||
# Continue but user should be aware of potential issues
|
||||
|
||||
# Step 4.6: Enable dotfiles visibility for Wine prefix
|
||||
@@ -1596,20 +1601,21 @@ class ModlistHandler:
|
||||
except Exception as e:
|
||||
self.logger.warning(f"Wineserver shutdown failed (non-critical): {e}")
|
||||
|
||||
# Registry fix 1: Set mscoree=native DLL override
|
||||
# Registry fix 1: Set *mscoree=native DLL override (asterisk for full override)
|
||||
# This tells Wine to use native .NET runtime instead of Wine's implementation
|
||||
self.logger.debug("Setting mscoree=native DLL override...")
|
||||
self.logger.debug("Setting *mscoree=native DLL override...")
|
||||
cmd1 = [
|
||||
wine_binary, 'reg', 'add',
|
||||
'HKEY_CURRENT_USER\\Software\\Wine\\DllOverrides',
|
||||
'/v', 'mscoree', '/t', 'REG_SZ', '/d', 'native', '/f'
|
||||
'/v', '*mscoree', '/t', 'REG_SZ', '/d', 'native', '/f'
|
||||
]
|
||||
|
||||
result1 = subprocess.run(cmd1, env=env, capture_output=True, text=True, errors='replace', timeout=30)
|
||||
self.logger.info(f"*mscoree registry command result: returncode={result1.returncode}, stdout={result1.stdout[:200]}, stderr={result1.stderr[:200]}")
|
||||
if result1.returncode == 0:
|
||||
self.logger.info("Successfully applied mscoree=native DLL override")
|
||||
self.logger.info("Successfully applied *mscoree=native DLL override")
|
||||
else:
|
||||
self.logger.warning(f"Failed to set mscoree DLL override: {result1.stderr}")
|
||||
self.logger.error(f"Failed to set *mscoree DLL override: returncode={result1.returncode}, stderr={result1.stderr}")
|
||||
|
||||
# Registry fix 2: Set OnlyUseLatestCLR=1
|
||||
# This prevents .NET version conflicts by using the latest CLR
|
||||
@@ -1621,10 +1627,11 @@ class ModlistHandler:
|
||||
]
|
||||
|
||||
result2 = subprocess.run(cmd2, env=env, capture_output=True, text=True, errors='replace', timeout=30)
|
||||
self.logger.info(f"OnlyUseLatestCLR registry command result: returncode={result2.returncode}, stdout={result2.stdout[:200]}, stderr={result2.stderr[:200]}")
|
||||
if result2.returncode == 0:
|
||||
self.logger.info("Successfully applied OnlyUseLatestCLR=1 registry entry")
|
||||
else:
|
||||
self.logger.warning(f"Failed to set OnlyUseLatestCLR: {result2.stderr}")
|
||||
self.logger.error(f"Failed to set OnlyUseLatestCLR: returncode={result2.returncode}, stderr={result2.stderr}")
|
||||
|
||||
# Force wineserver to flush registry changes to disk
|
||||
if wineserver_binary:
|
||||
@@ -1639,17 +1646,17 @@ class ModlistHandler:
|
||||
self.logger.info("Verifying registry entries were applied and persisted...")
|
||||
verification_passed = True
|
||||
|
||||
# Verify mscoree=native
|
||||
# Verify *mscoree=native
|
||||
verify_cmd1 = [
|
||||
wine_binary, 'reg', 'query',
|
||||
'HKEY_CURRENT_USER\\Software\\Wine\\DllOverrides',
|
||||
'/v', 'mscoree'
|
||||
'/v', '*mscoree'
|
||||
]
|
||||
verify_result1 = subprocess.run(verify_cmd1, env=env, capture_output=True, text=True, errors='replace', timeout=30)
|
||||
if verify_result1.returncode == 0 and 'native' in verify_result1.stdout:
|
||||
self.logger.info("VERIFIED: mscoree=native is set correctly")
|
||||
self.logger.info("VERIFIED: *mscoree=native is set correctly")
|
||||
else:
|
||||
self.logger.error(f"VERIFICATION FAILED: mscoree=native not found in registry. Query output: {verify_result1.stdout}")
|
||||
self.logger.error(f"VERIFICATION FAILED: *mscoree=native not found in registry. Query output: {verify_result1.stdout}")
|
||||
verification_passed = False
|
||||
|
||||
# Verify OnlyUseLatestCLR=1
|
||||
@@ -1696,10 +1703,17 @@ class ModlistHandler:
|
||||
]
|
||||
|
||||
for wine_path in wine_candidates:
|
||||
if wine_path.exists():
|
||||
if wine_path.exists() and wine_path.is_file():
|
||||
self.logger.info(f"Using Wine binary from user's configured Proton: {wine_path}")
|
||||
return str(wine_path)
|
||||
|
||||
# Wine binary not found at expected paths - search recursively in Proton directory
|
||||
self.logger.debug(f"Wine binary not found at expected paths in {proton_path}, searching recursively...")
|
||||
wine_binary = self._search_wine_in_proton_directory(proton_path)
|
||||
if wine_binary:
|
||||
self.logger.info(f"Found Wine binary via recursive search in Proton directory: {wine_binary}")
|
||||
return wine_binary
|
||||
|
||||
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
|
||||
@@ -1719,4 +1733,42 @@ class ModlistHandler:
|
||||
self.logger.error(f"Error finding Wine binary: {e}")
|
||||
return None
|
||||
|
||||
def _search_wine_in_proton_directory(self, proton_path: Path) -> Optional[str]:
|
||||
"""
|
||||
Recursively search for wine binary within a Proton directory.
|
||||
This handles cases where the directory structure might differ between Proton versions.
|
||||
|
||||
Args:
|
||||
proton_path: Path to the Proton directory to search
|
||||
|
||||
Returns:
|
||||
Path to wine binary if found, None otherwise
|
||||
"""
|
||||
try:
|
||||
if not proton_path.exists() or not proton_path.is_dir():
|
||||
return None
|
||||
|
||||
# Search for 'wine' executable (not 'wine64' or 'wine-preloader')
|
||||
# Limit search depth to avoid scanning entire filesystem
|
||||
max_depth = 5
|
||||
for root, dirs, files in os.walk(proton_path, followlinks=False):
|
||||
# Calculate depth relative to proton_path
|
||||
depth = len(Path(root).relative_to(proton_path).parts)
|
||||
if depth > max_depth:
|
||||
dirs.clear() # Don't descend further
|
||||
continue
|
||||
|
||||
# Check if 'wine' is in this directory
|
||||
if 'wine' in files:
|
||||
wine_path = Path(root) / 'wine'
|
||||
# Verify it's actually an executable file
|
||||
if wine_path.is_file() and os.access(wine_path, os.X_OK):
|
||||
self.logger.debug(f"Found wine binary at: {wine_path}")
|
||||
return str(wine_path)
|
||||
|
||||
return None
|
||||
except Exception as e:
|
||||
self.logger.debug(f"Error during recursive wine search in {proton_path}: {e}")
|
||||
return None
|
||||
|
||||
|
||||
@@ -427,10 +427,11 @@ class ModlistInstallCLI:
|
||||
print("\n" + "-" * 28)
|
||||
print(f"{COLOR_INFO}Nexus Authentication: Using API Key (Legacy){COLOR_RESET}")
|
||||
|
||||
# Get valid token/key
|
||||
api_key = auth_service.ensure_valid_auth()
|
||||
# Get valid token/key and OAuth state for engine auto-refresh
|
||||
api_key, oauth_info = auth_service.get_auth_for_engine()
|
||||
if api_key:
|
||||
self.context['nexus_api_key'] = api_key
|
||||
self.context['nexus_oauth_info'] = oauth_info # For engine auto-refresh
|
||||
else:
|
||||
# Auth expired or invalid - prompt to set up
|
||||
print(f"\n{COLOR_WARNING}Your authentication has expired or is invalid.{COLOR_RESET}")
|
||||
@@ -463,9 +464,10 @@ class ModlistInstallCLI:
|
||||
if username:
|
||||
print(f"{COLOR_INFO}Authorized as: {username}{COLOR_RESET}")
|
||||
|
||||
api_key = auth_service.ensure_valid_auth()
|
||||
api_key, oauth_info = auth_service.get_auth_for_engine()
|
||||
if api_key:
|
||||
self.context['nexus_api_key'] = api_key
|
||||
self.context['nexus_oauth_info'] = oauth_info # For engine auto-refresh
|
||||
else:
|
||||
print(f"{COLOR_ERROR}Failed to retrieve auth token after authorization.{COLOR_RESET}")
|
||||
return None
|
||||
@@ -616,6 +618,7 @@ class ModlistInstallCLI:
|
||||
modlist_arg = self.context.get('modlist_value') or self.context.get('machineid')
|
||||
machineid = self.context.get('machineid')
|
||||
api_key = self.context['nexus_api_key']
|
||||
oauth_info = self.context.get('nexus_oauth_info')
|
||||
|
||||
# Path to the engine binary
|
||||
engine_path = get_jackify_engine_path()
|
||||
@@ -675,24 +678,37 @@ class ModlistInstallCLI:
|
||||
# Store original environment values to restore later
|
||||
original_env_values = {
|
||||
'NEXUS_API_KEY': os.environ.get('NEXUS_API_KEY'),
|
||||
'NEXUS_OAUTH_INFO': os.environ.get('NEXUS_OAUTH_INFO'),
|
||||
'DOTNET_SYSTEM_GLOBALIZATION_INVARIANT': os.environ.get('DOTNET_SYSTEM_GLOBALIZATION_INVARIANT')
|
||||
}
|
||||
|
||||
try:
|
||||
# Temporarily modify current process's environment
|
||||
if api_key:
|
||||
# Prefer NEXUS_OAUTH_INFO (supports auto-refresh) over NEXUS_API_KEY (legacy)
|
||||
if oauth_info:
|
||||
os.environ['NEXUS_OAUTH_INFO'] = oauth_info
|
||||
self.logger.debug(f"Set NEXUS_OAUTH_INFO for engine (supports auto-refresh)")
|
||||
# Also set NEXUS_API_KEY for backward compatibility
|
||||
if api_key:
|
||||
os.environ['NEXUS_API_KEY'] = api_key
|
||||
elif api_key:
|
||||
# No OAuth info, use API key only (no auto-refresh support)
|
||||
os.environ['NEXUS_API_KEY'] = api_key
|
||||
self.logger.debug(f"Temporarily set os.environ['NEXUS_API_KEY'] for engine call using session-provided key.")
|
||||
elif 'NEXUS_API_KEY' in os.environ: # api_key is None/empty, but a system key might exist
|
||||
self.logger.debug(f"Session API key not provided. Temporarily removing inherited NEXUS_API_KEY ('{'[REDACTED]' if os.environ.get('NEXUS_API_KEY') else 'None'}') from os.environ for engine call to ensure it is not used.")
|
||||
del os.environ['NEXUS_API_KEY']
|
||||
# If api_key is None and NEXUS_API_KEY was not in os.environ, it remains unset, which is correct.
|
||||
self.logger.debug(f"Set NEXUS_API_KEY for engine (no auto-refresh)")
|
||||
else:
|
||||
# No auth available, clear any inherited values
|
||||
if 'NEXUS_API_KEY' in os.environ:
|
||||
del os.environ['NEXUS_API_KEY']
|
||||
if 'NEXUS_OAUTH_INFO' in os.environ:
|
||||
del os.environ['NEXUS_OAUTH_INFO']
|
||||
self.logger.debug(f"No Nexus auth available, cleared inherited env vars")
|
||||
|
||||
os.environ['DOTNET_SYSTEM_GLOBALIZATION_INVARIANT'] = "1"
|
||||
self.logger.debug(f"Temporarily set os.environ['DOTNET_SYSTEM_GLOBALIZATION_INVARIANT'] = '1' for engine call.")
|
||||
|
||||
|
||||
self.logger.info("Environment prepared for jackify-engine install process by modifying os.environ.")
|
||||
self.logger.debug(f"NEXUS_API_KEY in os.environ (pre-call): {'[SET]' if os.environ.get('NEXUS_API_KEY') else '[NOT SET]'}")
|
||||
self.logger.debug(f"NEXUS_OAUTH_INFO in os.environ (pre-call): {'[SET]' if os.environ.get('NEXUS_OAUTH_INFO') else '[NOT SET]'}")
|
||||
|
||||
pretty_cmd = ' '.join([f'"{arg}"' if ' ' in arg else arg for arg in cmd])
|
||||
print(f"{COLOR_INFO}Launching Jackify Install Engine with command:{COLOR_RESET} {pretty_cmd}")
|
||||
|
||||
@@ -596,19 +596,29 @@ class ProtontricksHandler:
|
||||
try:
|
||||
if user_reg_path.exists():
|
||||
content = user_reg_path.read_text(encoding='utf-8', errors='ignore')
|
||||
if "ShowDotFiles" not in content:
|
||||
# Check for CORRECT format with proper backslash escaping
|
||||
has_correct_format = '[Software\\\\Wine]' in content and '"ShowDotFiles"="Y"' in content
|
||||
has_broken_format = '[SoftwareWine]' in content and '"ShowDotFiles"="Y"' in content
|
||||
|
||||
if has_broken_format and not has_correct_format:
|
||||
# Fix the broken format by replacing the section header
|
||||
logger.debug(f"Found broken ShowDotFiles format in {user_reg_path}, fixing...")
|
||||
content = content.replace('[SoftwareWine]', '[Software\\\\Wine]')
|
||||
user_reg_path.write_text(content, encoding='utf-8')
|
||||
dotfiles_set_success = True
|
||||
elif not has_correct_format:
|
||||
logger.debug(f"Adding ShowDotFiles entry to {user_reg_path}")
|
||||
with open(user_reg_path, 'a', encoding='utf-8') as f:
|
||||
f.write('\n[Software\\Wine] 1603891765\n')
|
||||
f.write('\n[Software\\\\Wine] 1603891765\n')
|
||||
f.write('"ShowDotFiles"="Y"\n')
|
||||
dotfiles_set_success = True # Count file write as success too
|
||||
else:
|
||||
logger.debug("ShowDotFiles already present in user.reg")
|
||||
logger.debug("ShowDotFiles already present in correct format in user.reg")
|
||||
dotfiles_set_success = True # Already there counts as success
|
||||
else:
|
||||
logger.warning(f"user.reg not found at {user_reg_path}, creating it.")
|
||||
with open(user_reg_path, 'w', encoding='utf-8') as f:
|
||||
f.write('[Software\\Wine] 1603891765\n')
|
||||
f.write('[Software\\\\Wine] 1603891765\n')
|
||||
f.write('"ShowDotFiles"="Y"\n')
|
||||
dotfiles_set_success = True # Creating file counts as success
|
||||
except Exception as e:
|
||||
|
||||
@@ -41,8 +41,8 @@ def get_clean_subprocess_env(extra_env=None):
|
||||
"""
|
||||
Returns a copy of os.environ with bundled-runtime variables and other problematic entries removed.
|
||||
Optionally merges in extra_env dict.
|
||||
Also ensures bundled tools (lz4, unzip, etc.) are in PATH when running as AppImage.
|
||||
CRITICAL: Preserves system PATH to ensure system tools (like lz4) are available.
|
||||
Also ensures bundled tools (lz4, cabextract, winetricks) are in PATH when running as AppImage.
|
||||
CRITICAL: Preserves system PATH to ensure system utilities (wget, curl, unzip, xz, gzip, sha256sum) are available.
|
||||
"""
|
||||
from pathlib import Path
|
||||
|
||||
@@ -73,7 +73,8 @@ def get_clean_subprocess_env(extra_env=None):
|
||||
path_parts.append(sys_path)
|
||||
|
||||
# Add bundled tools directory to PATH if running as AppImage
|
||||
# This ensures lz4, unzip, xz, etc. are available to subprocesses
|
||||
# This ensures lz4, cabextract, and winetricks are available to subprocesses
|
||||
# System utilities (wget, curl, unzip, xz, gzip, sha256sum) come from system PATH
|
||||
# Note: appdir was saved before env cleanup above
|
||||
tools_dir = None
|
||||
|
||||
@@ -100,23 +101,23 @@ def get_clean_subprocess_env(extra_env=None):
|
||||
tools_dir = str(possible_dir)
|
||||
break
|
||||
|
||||
# Build final PATH: bundled tools first (if any), then original PATH with system paths
|
||||
# Build final PATH: system PATH first, then bundled tools (lz4, cabextract, winetricks)
|
||||
# System utilities (wget, curl, unzip, xz, gzip, sha256sum) are preferred from system
|
||||
final_path_parts = []
|
||||
if tools_dir and os.path.isdir(tools_dir):
|
||||
# Prepend tools directory so bundled tools take precedence
|
||||
# This is critical - bundled lz4 must come before system lz4
|
||||
final_path_parts.append(tools_dir)
|
||||
|
||||
# Add all other paths (preserving order, removing duplicates)
|
||||
# Note: AppRun already sets PATH with tools directory, but we ensure it's first
|
||||
# Add all other paths first (system utilities take precedence)
|
||||
seen = set()
|
||||
if tools_dir:
|
||||
seen.add(tools_dir) # Already added, don't add again
|
||||
for path_part in path_parts:
|
||||
if path_part and path_part not in seen:
|
||||
final_path_parts.append(path_part)
|
||||
seen.add(path_part)
|
||||
|
||||
# Then add bundled tools directory (for lz4, cabextract, winetricks)
|
||||
if tools_dir and os.path.isdir(tools_dir) and tools_dir not in seen:
|
||||
final_path_parts.append(tools_dir)
|
||||
seen.add(tools_dir)
|
||||
|
||||
|
||||
env['PATH'] = ':'.join(final_path_parts)
|
||||
|
||||
# Optionally restore LD_LIBRARY_PATH to system default if needed
|
||||
|
||||
@@ -149,7 +149,7 @@ class WinetricksHandler:
|
||||
|
||||
# If user selected a specific Proton, try that first
|
||||
wine_binary = None
|
||||
if user_proton_path != 'auto':
|
||||
if user_proton_path and user_proton_path != 'auto':
|
||||
# Check if user-selected Proton still exists
|
||||
if os.path.exists(user_proton_path):
|
||||
# Resolve symlinks to handle ~/.steam/steam -> ~/.local/share/Steam
|
||||
@@ -582,7 +582,7 @@ class WinetricksHandler:
|
||||
user_proton_path = config.get_proton_path()
|
||||
|
||||
wine_binary = None
|
||||
if user_proton_path != 'auto':
|
||||
if user_proton_path and user_proton_path != 'auto':
|
||||
if os.path.exists(user_proton_path):
|
||||
resolved_proton_path = os.path.realpath(user_proton_path)
|
||||
valve_proton_wine = os.path.join(resolved_proton_path, 'dist', 'bin', 'wine')
|
||||
@@ -594,8 +594,8 @@ class WinetricksHandler:
|
||||
wine_binary = ge_proton_wine
|
||||
|
||||
if not wine_binary:
|
||||
if user_proton_path == 'auto':
|
||||
self.logger.info("Auto-detecting Proton (user selected 'auto')")
|
||||
if not user_proton_path or user_proton_path == 'auto':
|
||||
self.logger.info("Auto-detecting Proton (user selected 'auto' or path not set)")
|
||||
best_proton = WineUtils.select_best_proton()
|
||||
if best_proton:
|
||||
wine_binary = WineUtils.find_proton_binary(best_proton['name'])
|
||||
@@ -811,7 +811,7 @@ class WinetricksHandler:
|
||||
|
||||
# If user selected a specific Proton, try that first
|
||||
wine_binary = None
|
||||
if user_proton_path != 'auto':
|
||||
if user_proton_path and user_proton_path != 'auto':
|
||||
if os.path.exists(user_proton_path):
|
||||
resolved_proton_path = os.path.realpath(user_proton_path)
|
||||
valve_proton_wine = os.path.join(resolved_proton_path, 'dist', 'bin', 'wine')
|
||||
@@ -822,10 +822,10 @@ class WinetricksHandler:
|
||||
elif os.path.exists(ge_proton_wine):
|
||||
wine_binary = ge_proton_wine
|
||||
|
||||
# Only auto-detect if user explicitly chose 'auto'
|
||||
# Only auto-detect if user explicitly chose 'auto' or path is not set
|
||||
if not wine_binary:
|
||||
if user_proton_path == 'auto':
|
||||
self.logger.info("Auto-detecting Proton (user selected 'auto')")
|
||||
if not user_proton_path or user_proton_path == 'auto':
|
||||
self.logger.info("Auto-detecting Proton (user selected 'auto' or path not set)")
|
||||
best_proton = WineUtils.select_best_proton()
|
||||
if best_proton:
|
||||
wine_binary = WineUtils.find_proton_binary(best_proton['name'])
|
||||
|
||||
Reference in New Issue
Block a user