Sync from development - prepare for v0.1.6

This commit is contained in:
Omni
2025-10-16 14:44:49 +01:00
parent 7212a58480
commit 430d085287
59 changed files with 939 additions and 452 deletions

View File

@@ -156,7 +156,7 @@ class ModlistInstallCLI:
from ..models.configuration import SystemInfo
self.system_info = SystemInfo(is_steamdeck=steamdeck)
self.protontricks_handler = ProtontricksHandler(steamdeck=self.steamdeck)
self.protontricks_handler = ProtontricksHandler(self.steamdeck)
self.shortcut_handler = ShortcutHandler(steamdeck=self.steamdeck)
self.context = {}
# Use standard logging (no file handler)

View File

@@ -38,7 +38,9 @@ class ConfigHandler:
"default_download_parent_dir": None, # Parent directory for downloads
"modlist_install_base_dir": os.path.expanduser("~/Games"), # Configurable base directory for modlist installations
"modlist_downloads_base_dir": os.path.expanduser("~/Games/Modlist_Downloads"), # Configurable base directory for downloads
"jackify_data_dir": None # Configurable Jackify data directory (default: ~/Jackify)
"jackify_data_dir": None, # Configurable Jackify data directory (default: ~/Jackify)
"use_winetricks_for_components": True, # True = use winetricks (faster), False = use protontricks for all (legacy)
"game_proton_path": None # Proton version for game shortcuts (can be any Proton 9+), separate from install proton
}
# Load configuration if exists
@@ -498,20 +500,44 @@ class ConfigHandler:
def get_proton_path(self):
"""
Retrieve the saved Proton path from configuration
Retrieve the saved Install Proton path from configuration (for jackify-engine)
Always reads fresh from disk to pick up changes from Settings dialog
Returns:
str: Saved Proton path or 'auto' if not saved
str: Saved Install Proton path or 'auto' if not saved
"""
try:
# Reload config from disk to pick up changes from Settings dialog
self._load_config()
proton_path = self.settings.get("proton_path", "auto")
logger.debug(f"Retrieved fresh proton_path from config: {proton_path}")
logger.debug(f"Retrieved fresh install proton_path from config: {proton_path}")
return proton_path
except Exception as e:
logger.error(f"Error retrieving proton_path: {e}")
logger.error(f"Error retrieving install proton_path: {e}")
return "auto"
def get_game_proton_path(self):
"""
Retrieve the saved Game Proton path from configuration (for game shortcuts)
Falls back to install Proton path if game Proton not set
Always reads fresh from disk to pick up changes from Settings dialog
Returns:
str: Saved Game Proton path, Install Proton path, or 'auto' if not saved
"""
try:
# Reload config from disk to pick up changes from Settings dialog
self._load_config()
game_proton_path = self.settings.get("game_proton_path")
# 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 = self.settings.get("proton_path", "auto")
logger.debug(f"Retrieved fresh game proton_path from config: {game_proton_path}")
return game_proton_path
except Exception as e:
logger.error(f"Error retrieving game proton_path: {e}")
return "auto"
def get_proton_version(self):

View File

@@ -79,6 +79,7 @@ class ModlistHandler:
"livingskyrim": ["dotnet40"],
"lsiv": ["dotnet40"],
"ls4": ["dotnet40"],
"lorerim": ["dotnet40"],
"lostlegacy": ["dotnet48"],
}
@@ -158,7 +159,7 @@ class ModlistHandler:
self.stock_game_path = None
# Initialize Handlers (should happen regardless of how paths were provided)
self.protontricks_handler = ProtontricksHandler(steamdeck=self.steamdeck, logger=self.logger)
self.protontricks_handler = ProtontricksHandler(self.steamdeck, logger=self.logger)
# Initialize winetricks handler for wine component installation
from .winetricks_handler import WinetricksHandler
self.winetricks_handler = WinetricksHandler(logger=self.logger)
@@ -347,7 +348,8 @@ class ModlistHandler:
# Store engine_installed flag for conditional path manipulation
self.engine_installed = modlist_info.get('engine_installed', False)
self.logger.debug(f" Engine Installed: {self.engine_installed}")
# Call internal detection methods to populate more state
if not self._detect_game_variables():
self.logger.warning("Failed to auto-detect game type after setting context.")
@@ -687,39 +689,27 @@ class ModlistHandler:
# All modlists now use their own AppID for wine components
target_appid = self.appid
# Use winetricks for wine component installation (faster than protontricks)
# Use user's preferred component installation method (respects settings toggle)
wineprefix = self.protontricks_handler.get_wine_prefix_path(target_appid)
if not wineprefix:
self.logger.error("Failed to get WINEPREFIX path for winetricks.")
self.logger.error("Failed to get WINEPREFIX path for component installation.")
print("Error: Could not determine wine prefix location.")
return False
# Try winetricks first (preferred method with current fix)
winetricks_success = False
# Use the winetricks handler which respects the user's toggle setting
try:
self.logger.info("Attempting Wine component installation using winetricks...")
winetricks_success = self.winetricks_handler.install_wine_components(wineprefix, self.game_var_full, specific_components=components)
if winetricks_success:
self.logger.info("Winetricks installation completed successfully")
except Exception as e:
self.logger.warning(f"Winetricks installation failed with exception: {e}")
winetricks_success = False
# Fallback to protontricks if winetricks failed
if not winetricks_success:
self.logger.warning("Winetricks failed, falling back to protontricks for Wine component installation...")
try:
protontricks_success = self.protontricks_handler.install_wine_components(target_appid, self.game_var_full, specific_components=components)
if protontricks_success:
self.logger.info("Protontricks fallback installation completed successfully")
else:
self.logger.error("Both winetricks and protontricks failed to install Wine components.")
print("Error: Failed to install necessary Wine components using both winetricks and protontricks.")
return False
except Exception as e:
self.logger.error(f"Protontricks fallback also failed with exception: {e}")
print("Error: Failed to install necessary Wine components using both winetricks and protontricks.")
self.logger.info("Installing Wine components using user's preferred method...")
success = self.winetricks_handler.install_wine_components(wineprefix, self.game_var_full, specific_components=components)
if success:
self.logger.info("Wine component installation completed successfully")
else:
self.logger.error("Wine component installation failed")
print("Error: Failed to install necessary Wine components.")
return False
except Exception as e:
self.logger.error(f"Wine component installation failed with exception: {e}")
print("Error: Failed to install necessary Wine components.")
return False
self.logger.info("Step 4: Installing Wine components... Done")
# Step 5: Ensure permissions of Modlist directory
@@ -824,10 +814,10 @@ class ModlistHandler:
vanilla_game_dir = None
if self.steam_library and self.game_var_full:
vanilla_game_dir = str(Path(self.steam_library) / "steamapps" / "common" / self.game_var_full)
if not self.resolution_handler.update_ini_resolution(
modlist_dir=self.modlist_dir,
game_var=self.game_var_full,
if not ResolutionHandler.update_ini_resolution(
modlist_dir=self.modlist_dir,
game_var=self.game_var_full,
set_res=self.selected_resolution,
vanilla_game_dir=vanilla_game_dir
):
@@ -930,6 +920,10 @@ class ModlistHandler:
# status_callback("Configuration completed successfully!")
self.logger.info("Configuration steps completed successfully.")
# Step 14: Re-enforce Windows 10 mode after modlist-specific configurations (matches legacy script line 1333)
self._re_enforce_windows_10_mode()
return True # Return True on success
def _detect_steam_library_info(self) -> bool:
@@ -1332,4 +1326,39 @@ class ModlistHandler:
self.logger.debug("No special game type detected - standard workflow will be used")
return None
def _re_enforce_windows_10_mode(self):
"""
Re-enforce Windows 10 mode after modlist-specific configurations.
This matches the legacy script behavior (line 1333) where Windows 10 mode
is re-applied after modlist-specific steps to ensure consistency.
"""
try:
if not hasattr(self, 'appid') or not self.appid:
self.logger.warning("Cannot re-enforce Windows 10 mode - no AppID available")
return
from ..handlers.winetricks_handler import WinetricksHandler
from ..handlers.path_handler import PathHandler
# Get prefix path for the AppID
prefix_path = PathHandler.find_compat_data(str(self.appid))
if not prefix_path:
self.logger.warning("Cannot re-enforce Windows 10 mode - prefix path not found")
return
# Get wine binary path
wine_binary = PathHandler.get_wine_binary_for_appid(str(self.appid))
if not wine_binary:
self.logger.warning("Cannot re-enforce Windows 10 mode - wine binary not found")
return
# Use winetricks handler to set Windows 10 mode
winetricks_handler = WinetricksHandler()
winetricks_handler._set_windows_10_mode(str(prefix_path), wine_binary)
self.logger.info("✓ Windows 10 mode re-enforced after modlist-specific configurations")
except Exception as e:
self.logger.warning(f"Error re-enforcing Windows 10 mode: {e}")
# (Ensure EOF is clean and no extra incorrect methods exist below)

View File

@@ -68,7 +68,7 @@ class ModlistInstallCLI:
def __init__(self, menu_handler: MenuHandler, steamdeck: bool = False):
self.menu_handler = menu_handler
self.steamdeck = steamdeck
self.protontricks_handler = ProtontricksHandler(steamdeck=steamdeck)
self.protontricks_handler = ProtontricksHandler(steamdeck)
self.shortcut_handler = ShortcutHandler(steamdeck=steamdeck)
self.context = {}
# Use standard logging (no file handler)

View File

@@ -41,7 +41,7 @@ class ShortcutHandler:
self._last_shortcuts_backup = None # Track the last backup path
self._safe_shortcuts_backup = None # Track backup made just before restart
# Initialize ProtontricksHandler here, passing steamdeck status
self.protontricks_handler = ProtontricksHandler(steamdeck=self.steamdeck)
self.protontricks_handler = ProtontricksHandler(self.steamdeck)
def _enable_tab_completion(self):
"""Enable tab completion for file paths using the shared completer"""
@@ -964,7 +964,7 @@ class ShortcutHandler:
self.logger.info(f"Attempting to find current AppID for shortcut: '{shortcut_name}' (exe_path: '{exe_path}')")
try:
from .protontricks_handler import ProtontricksHandler # Local import
pt_handler = ProtontricksHandler(steamdeck=self.steamdeck)
pt_handler = ProtontricksHandler(self.steamdeck)
if not pt_handler.detect_protontricks():
self.logger.error("Protontricks not detected")
return None

View File

@@ -257,10 +257,18 @@ class WinetricksHandler:
components_to_install = self._reorder_components_for_installation(all_components)
self.logger.info(f"WINEPREFIX: {wineprefix}, Game: {game_var}, Ordered Components: {components_to_install}")
# Hybrid approach: Use protontricks for dotnet40 only, winetricks for everything else
if "dotnet40" in components_to_install:
self.logger.info("dotnet40 detected - using hybrid approach: protontricks for dotnet40, winetricks for others")
# Check user preference for component installation method
from ..handlers.config_handler import ConfigHandler
config_handler = ConfigHandler()
use_winetricks = config_handler.get('use_winetricks_for_components', True)
# Choose installation method based on user preference and components
if use_winetricks and "dotnet40" in components_to_install:
self.logger.info("Using optimized approach: protontricks for dotnet40 (reliable), winetricks for other components (fast)")
return self._install_components_hybrid_approach(components_to_install, wineprefix, game_var)
elif not use_winetricks:
self.logger.info("Using legacy approach: protontricks for all components")
return self._install_components_protontricks_only(components_to_install, wineprefix, game_var)
# For non-dotnet40 installations, install all components together (faster)
max_attempts = 3
@@ -289,6 +297,8 @@ class WinetricksHandler:
self.logger.debug(f"Winetricks output: {result.stdout}")
if result.returncode == 0:
self.logger.info("Wine Component installation command completed successfully.")
# Set Windows 10 mode after component installation (matches legacy script timing)
self._set_windows_10_mode(wineprefix, env.get('WINE', ''))
return True
else:
# Special handling for dotnet40 verification issue (mimics protontricks behavior)
@@ -415,14 +425,8 @@ class WinetricksHandler:
self.logger.error("Failed to prepare prefix for dotnet40")
return False
else:
# For non-dotnet40 components, ensure we're in Windows 10 mode
# For non-dotnet40 components, install in standard mode (Windows 10 will be set after all components)
self.logger.debug(f"Installing {component} in standard mode")
try:
subprocess.run([
self.winetricks_path, '-q', 'win10'
], env=env, capture_output=True, text=True, timeout=300)
except Exception as e:
self.logger.warning(f"Could not set win10 mode for {component}: {e}")
# Install this component
max_attempts = 3
@@ -480,6 +484,8 @@ class WinetricksHandler:
return False
self.logger.info("✓ All components installed successfully using separate sessions")
# Set Windows 10 mode after all component installation (matches legacy script timing)
self._set_windows_10_mode(wineprefix, env.get('WINE', ''))
return True
def _install_components_hybrid_approach(self, components: list, wineprefix: str, game_var: str) -> bool:
@@ -524,6 +530,9 @@ class WinetricksHandler:
return self._install_components_with_winetricks(other_components, wineprefix, env)
self.logger.info("✓ Hybrid component installation completed successfully")
# Set Windows 10 mode after all component installation (matches legacy script timing)
wine_binary = self._get_wine_binary_for_prefix(wineprefix)
self._set_windows_10_mode(wineprefix, wine_binary)
return True
def _install_dotnet40_with_protontricks(self, wineprefix: str, game_var: str) -> bool:
@@ -562,7 +571,7 @@ class WinetricksHandler:
# Determine if we're on Steam Deck (for protontricks handler)
steamdeck = os.path.exists('/home/deck')
protontricks_handler = ProtontricksHandler(steamdeck=steamdeck, logger=self.logger)
protontricks_handler = ProtontricksHandler(steamdeck, logger=self.logger)
# Detect protontricks availability
if not protontricks_handler.detect_protontricks():
@@ -691,6 +700,9 @@ class WinetricksHandler:
if result.returncode == 0:
self.logger.info(f"✓ Winetricks components installed successfully: {components}")
# Set Windows 10 mode after component installation (matches legacy script timing)
wine_binary = env.get('WINE', '')
self._set_windows_10_mode(env.get('WINEPREFIX', ''), wine_binary)
return True
else:
self.logger.error(f"✗ Winetricks failed (attempt {attempt}): {result.stderr.strip()}")
@@ -701,6 +713,140 @@ class WinetricksHandler:
self.logger.error(f"Failed to install components with winetricks after {max_attempts} attempts")
return False
def _set_windows_10_mode(self, wineprefix: str, wine_binary: str):
"""
Set Windows 10 mode for the prefix after component installation (matches legacy script timing).
This should be called AFTER all Wine components are installed, not before.
"""
try:
env = os.environ.copy()
env['WINEPREFIX'] = wineprefix
env['WINE'] = wine_binary
self.logger.info("Setting Windows 10 mode after component installation (matching legacy script)")
result = subprocess.run([
self.winetricks_path, '-q', 'win10'
], env=env, capture_output=True, text=True, timeout=300)
if result.returncode == 0:
self.logger.info("✓ Windows 10 mode set successfully")
else:
self.logger.warning(f"Could not set Windows 10 mode: {result.stderr}")
except Exception as e:
self.logger.warning(f"Error setting Windows 10 mode: {e}")
def _install_components_protontricks_only(self, components: list, wineprefix: str, game_var: str) -> bool:
"""
Legacy approach: Install all components using protontricks only.
This matches the behavior of the original bash script.
"""
try:
self.logger.info(f"Installing all components with protontricks (legacy method): {components}")
# Import protontricks handler
from ..handlers.protontricks_handler import ProtontricksHandler
# Determine if we're on Steam Deck (for protontricks handler)
steamdeck = os.path.exists('/home/deck')
protontricks_handler = ProtontricksHandler(steamdeck, logger=self.logger)
# Get AppID from wineprefix
appid = self._extract_appid_from_wineprefix(wineprefix)
if not appid:
self.logger.error("Could not extract AppID from wineprefix for protontricks installation")
return False
self.logger.info(f"Using AppID {appid} for protontricks installation")
# Detect protontricks availability
if not protontricks_handler.detect_protontricks():
self.logger.error("Protontricks not available for component installation")
return False
# Install all components using protontricks
success = protontricks_handler.install_wine_components(appid, game_var, components)
if success:
self.logger.info("✓ All components installed successfully with protontricks")
# Set Windows 10 mode after component installation
wine_binary = self._get_wine_binary_for_prefix(wineprefix)
self._set_windows_10_mode(wineprefix, wine_binary)
return True
else:
self.logger.error("✗ Component installation failed with protontricks")
return False
except Exception as e:
self.logger.error(f"Error installing components with protontricks: {e}", exc_info=True)
return False
def _extract_appid_from_wineprefix(self, wineprefix: str) -> Optional[str]:
"""
Extract AppID from wineprefix path.
Args:
wineprefix: Wine prefix path
Returns:
AppID as string, or None if extraction fails
"""
try:
if 'compatdata' in wineprefix:
# Standard Steam compatdata structure
path_parts = Path(wineprefix).parts
for i, part in enumerate(path_parts):
if part == 'compatdata' and i + 1 < len(path_parts):
potential_appid = path_parts[i + 1]
if potential_appid.isdigit():
return potential_appid
self.logger.error(f"Could not extract AppID from wineprefix path: {wineprefix}")
return None
except Exception as e:
self.logger.error(f"Error extracting AppID from wineprefix: {e}")
return None
def _get_wine_binary_for_prefix(self, wineprefix: str) -> str:
"""
Get the wine binary path for a given prefix.
Args:
wineprefix: Wine prefix path
Returns:
Wine binary path as string
"""
try:
from ..handlers.config_handler import ConfigHandler
from ..handlers.wine_utils import WineUtils
config = ConfigHandler()
user_proton_path = config.get_proton_path()
# If user selected a specific Proton, try that first
wine_binary = None
if 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')
ge_proton_wine = os.path.join(resolved_proton_path, 'files', 'bin', 'wine')
if os.path.exists(valve_proton_wine):
wine_binary = valve_proton_wine
elif os.path.exists(ge_proton_wine):
wine_binary = ge_proton_wine
# Fall back to auto-detection if user selection failed or is 'auto'
if not wine_binary:
best_proton = WineUtils.select_best_proton()
if best_proton:
wine_binary = WineUtils.find_proton_binary(best_proton['name'])
return wine_binary if wine_binary else ""
except Exception as e:
self.logger.error(f"Error getting wine binary for prefix: {e}")
return ""
def _cleanup_wine_processes(self):
"""
Internal method to clean up wine processes during component installation

View File

@@ -39,14 +39,26 @@ class AutomatedPrefixService:
from jackify.shared.timing import get_timestamp
return get_timestamp()
def _get_user_proton_version(self):
"""Get user's preferred Proton version from config, with fallback to auto-detection"""
def _get_user_proton_version(self, modlist_name: str = None):
"""Get user's preferred Proton version from config, with fallback to auto-detection
Args:
modlist_name: Optional modlist name for special handling (e.g., Lorerim)
"""
try:
from jackify.backend.handlers.config_handler import ConfigHandler
from jackify.backend.handlers.wine_utils import WineUtils
# Check for Lorerim-specific Proton override first
if modlist_name and modlist_name.lower() == 'lorerim':
lorerim_proton = self._get_lorerim_preferred_proton()
if lorerim_proton:
logger.info(f"Lorerim detected: Using {lorerim_proton} instead of user settings")
self._store_proton_override_notification("Lorerim", lorerim_proton)
return lorerim_proton
config_handler = ConfigHandler()
user_proton_path = config_handler.get_proton_path()
user_proton_path = config_handler.get_game_proton_path()
if user_proton_path == 'auto':
# Use enhanced fallback logic with GE-Proton preference
@@ -125,8 +137,8 @@ class AutomatedPrefixService:
logger.warning(f"Could not generate STEAM_COMPAT_MOUNTS, using default: {e}")
launch_options = "%command%"
# Get user's preferred Proton version
proton_version = self._get_user_proton_version()
# Get user's preferred Proton version (with Lorerim-specific override)
proton_version = self._get_user_proton_version(shortcut_name)
# Create shortcut with Proton using native service
success, app_id = steam_service.create_shortcut_with_proton(
@@ -487,7 +499,7 @@ exit"""
try:
# Use the existing protontricks handler
from jackify.backend.handlers.protontricks_handler import ProtontricksHandler
protontricks_handler = ProtontricksHandler(steamdeck=steamdeck or False)
protontricks_handler = ProtontricksHandler(steamdeck or False)
result = protontricks_handler.run_protontricks('-l')
if result.returncode == 0:
@@ -1556,6 +1568,9 @@ echo Prefix creation complete.
if progress_callback:
progress_callback(f"{self._get_progress_timestamp()} Steam Configuration complete!")
# Show Proton override notification if applicable
self._show_proton_override_notification(progress_callback)
logger.info(" Simple automated prefix creation workflow completed successfully")
return True, prefix_path, actual_appid
@@ -1869,6 +1884,11 @@ echo Prefix creation complete.
if progress_callback:
progress_callback(f"{last_timestamp} Steam integration complete")
progress_callback("") # Blank line after Steam integration complete
# Show Proton override notification if applicable
self._show_proton_override_notification(progress_callback)
if progress_callback:
progress_callback("") # Extra blank line to span across Configuration Summary
progress_callback("") # And one more to create space before Prefix Configuration
@@ -2705,7 +2725,7 @@ echo Prefix creation complete.
from jackify.backend.handlers.wine_utils import WineUtils
config = ConfigHandler()
user_proton_path = config.get_proton_path()
user_proton_path = config.get_game_proton_path()
# If user selected a specific Proton, try that first
if user_proton_path != 'auto':
@@ -3005,4 +3025,92 @@ echo Prefix creation complete.
logger.debug(f"{config['name']} not found in Steam libraries")
logger.info("Game registry injection completed")
def _get_lorerim_preferred_proton(self):
"""Get Lorerim's preferred Proton 9 version with specific priority order"""
try:
from jackify.backend.handlers.wine_utils import WineUtils
# Get all available Proton versions
available_versions = WineUtils.scan_all_proton_versions()
if not available_versions:
logger.warning("No Proton versions found for Lorerim override")
return None
# Priority order for Lorerim:
# 1. GEProton9-27 (specific version)
# 2. Other GEProton-9 versions (latest first)
# 3. Valve Proton 9 (any version)
preferred_candidates = []
for version in available_versions:
version_name = version['name']
# Priority 1: GEProton9-27 specifically
if version_name == 'GE-Proton9-27':
logger.info(f"Lorerim: Found preferred GE-Proton9-27")
return version_name
# Priority 2: Other GE-Proton 9 versions
elif version_name.startswith('GE-Proton9-'):
preferred_candidates.append(('ge_proton_9', version_name, version))
# Priority 3: Valve Proton 9
elif 'Proton 9' in version_name:
preferred_candidates.append(('valve_proton_9', version_name, version))
# Return best candidate if any found
if preferred_candidates:
# Sort by priority (GE-Proton first, then by name for latest)
preferred_candidates.sort(key=lambda x: (x[0], x[1]), reverse=True)
best_candidate = preferred_candidates[0]
logger.info(f"Lorerim: Selected {best_candidate[1]} as best Proton 9 option")
return best_candidate[1]
logger.warning("Lorerim: No suitable Proton 9 versions found, will use user settings")
return None
except Exception as e:
logger.error(f"Error detecting Lorerim Proton preference: {e}")
return None
def _store_proton_override_notification(self, modlist_name: str, proton_version: str):
"""Store Proton override information for end-of-install notification"""
try:
# Store override info for later display
if not hasattr(self, '_proton_overrides'):
self._proton_overrides = []
self._proton_overrides.append({
'modlist': modlist_name,
'proton_version': proton_version,
'reason': f'{modlist_name} requires Proton 9 for optimal compatibility'
})
logger.debug(f"Stored Proton override notification: {modlist_name}{proton_version}")
except Exception as e:
logger.error(f"Failed to store Proton override notification: {e}")
def _show_proton_override_notification(self, progress_callback=None):
"""Display any Proton override notifications to the user"""
try:
if hasattr(self, '_proton_overrides') and self._proton_overrides:
for override in self._proton_overrides:
notification_msg = f"PROTON OVERRIDE: {override['modlist']} configured to use {override['proton_version']} for optimal compatibility"
if progress_callback:
progress_callback("")
progress_callback(f"{self._get_progress_timestamp()} {notification_msg}")
logger.info(notification_msg)
# Clear notifications after display
self._proton_overrides = []
except Exception as e:
logger.error(f"Failed to show Proton override notification: {e}")

View File

@@ -631,6 +631,10 @@ class ModlistService:
'skip_confirmation': True, # Service layer should be non-interactive
'manual_steps_completed': False
}
# DEBUG: Log what resolution we're passing
logger.info(f"DEBUG: config_context resolution = {config_context['resolution']}")
logger.info(f"DEBUG: context.resolution = {getattr(context, 'resolution', 'NOT_SET')}")
# Run the complete configuration phase
success = modlist_menu.run_modlist_configuration_phase(config_context)

View File

@@ -345,16 +345,22 @@ class NativeSteamService:
def set_proton_version(self, app_id: int, proton_version: str = "proton_experimental") -> bool:
"""
Set the Proton version for a specific app using ONLY config.vdf like steam-conductor does.
Args:
app_id: The unsigned AppID
app_id: The unsigned AppID
proton_version: The Proton version to set
Returns:
True if successful
"""
# Ensure Steam user detection is completed first
if not self.steam_path:
if not self.find_steam_user():
logger.error("Cannot set Proton version: Steam user detection failed")
return False
logger.info(f"Setting Proton version '{proton_version}' for AppID {app_id} using STL-compatible format")
try:
# Step 1: Write to the main config.vdf for CompatToolMapping
config_path = self.steam_path / "config" / "config.vdf"

View File

@@ -39,7 +39,7 @@ class ProtontricksDetectionService:
def _get_protontricks_handler(self) -> ProtontricksHandler:
"""Get or create ProtontricksHandler instance"""
if self._protontricks_handler is None:
self._protontricks_handler = ProtontricksHandler(steamdeck=self.steamdeck)
self._protontricks_handler = ProtontricksHandler(self.steamdeck)
return self._protontricks_handler
def detect_protontricks(self, use_cache: bool = True) -> Tuple[bool, str, str]: