mirror of
https://github.com/Omni-guides/Jackify.git
synced 2026-06-07 22:57:45 +02:00
199 lines
7.1 KiB
Python
199 lines
7.1 KiB
Python
"""
|
|
VNV Integration Helper
|
|
|
|
Helper functions to integrate VNV post-install automation into modlist workflows.
|
|
Handles detection, confirmation, and execution for:
|
|
- Install Modlist
|
|
- Configure New Modlist
|
|
- Configure Existing Modlist
|
|
"""
|
|
|
|
import logging
|
|
import configparser
|
|
import re
|
|
from pathlib import Path
|
|
from typing import Optional, Callable, Tuple
|
|
|
|
from .vnv_post_install_service import VNVPostInstallService
|
|
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
def _parse_bytearray_value(value: str) -> str:
|
|
"""
|
|
Parse Qt @ByteArray format to extract the actual string value.
|
|
|
|
Format: @ByteArray(Viva New Vegas Extended)
|
|
Returns: Viva New Vegas Extended
|
|
"""
|
|
match = re.match(r'@ByteArray\((.*)\)', value)
|
|
if match:
|
|
return match.group(1)
|
|
return value
|
|
|
|
|
|
def _check_modorganizer_ini_profile(modlist_install_location: Path) -> bool:
|
|
"""
|
|
Check ModOrganizer.ini for VNV profile names.
|
|
|
|
Args:
|
|
modlist_install_location: Path to modlist installation directory
|
|
|
|
Returns:
|
|
True if selected_profile is "Viva New Vegas" or "Viva New Vegas Extended"
|
|
"""
|
|
try:
|
|
mo_ini_path = modlist_install_location / "ModOrganizer.ini"
|
|
if not mo_ini_path.exists():
|
|
logger.debug(f"ModOrganizer.ini not found at {mo_ini_path}")
|
|
return False
|
|
|
|
config = configparser.ConfigParser()
|
|
# Read with UTF-8-sig to handle BOM
|
|
config.read(mo_ini_path, encoding='utf-8-sig')
|
|
|
|
if 'General' not in config:
|
|
logger.debug("No [General] section in ModOrganizer.ini")
|
|
return False
|
|
|
|
selected_profile_raw = config.get('General', 'selected_profile', fallback='')
|
|
if not selected_profile_raw:
|
|
logger.debug("No selected_profile in ModOrganizer.ini")
|
|
return False
|
|
|
|
# Parse @ByteArray format
|
|
selected_profile = _parse_bytearray_value(selected_profile_raw)
|
|
logger.debug(f"Found selected_profile: {selected_profile}")
|
|
|
|
# Check if it's one of the VNV profiles
|
|
vnv_profiles = ["Viva New Vegas", "Viva New Vegas Extended"]
|
|
return selected_profile in vnv_profiles
|
|
|
|
except Exception as e:
|
|
logger.debug(f"Error checking ModOrganizer.ini for VNV profile: {e}")
|
|
return False
|
|
|
|
|
|
def should_offer_vnv_automation(modlist_name: str, modlist_install_location: Optional[Path] = None) -> bool:
|
|
"""
|
|
Check if VNV automation should be offered for this modlist.
|
|
|
|
Detection methods (in order of reliability):
|
|
1. Check ModOrganizer.ini selected_profile (most reliable)
|
|
2. Check modlist name for VNV patterns
|
|
|
|
Args:
|
|
modlist_name: Name of the modlist
|
|
modlist_install_location: Optional path to modlist installation directory
|
|
|
|
Returns:
|
|
True if VNV automation should be offered
|
|
"""
|
|
# Method 1: Check ModOrganizer.ini profile (most reliable)
|
|
if modlist_install_location:
|
|
if _check_modorganizer_ini_profile(modlist_install_location):
|
|
logger.info(f"VNV detected via ModOrganizer.ini profile in {modlist_install_location}")
|
|
return True
|
|
|
|
# Method 2: Check modlist name patterns
|
|
modlist_name_lower = modlist_name.lower()
|
|
vnv_patterns = [
|
|
"viva new vegas",
|
|
"vnv", # Common abbreviation
|
|
"viva new vegas extended"
|
|
]
|
|
|
|
for pattern in vnv_patterns:
|
|
if pattern in modlist_name_lower:
|
|
logger.info(f"VNV detected via name pattern '{pattern}' in '{modlist_name}'")
|
|
return True
|
|
|
|
return False
|
|
|
|
|
|
def run_vnv_automation_if_applicable(
|
|
modlist_name: str,
|
|
modlist_install_location: Path,
|
|
game_root: Path,
|
|
ttw_installer_path: Optional[Path] = None,
|
|
progress_callback: Optional[Callable[[str], None]] = None,
|
|
manual_file_callback: Optional[Callable[[str, str], Optional[Path]]] = None,
|
|
confirmation_callback: Optional[Callable[[str], bool]] = None
|
|
) -> Tuple[bool, Optional[str]]:
|
|
"""
|
|
Check if VNV automation should run, get user confirmation, and execute if confirmed.
|
|
|
|
Args:
|
|
modlist_name: Name of the installed modlist
|
|
modlist_install_location: Path to modlist installation
|
|
game_root: Path to game root directory
|
|
ttw_installer_path: Optional path to TTW_Linux_Installer (for BSA decompression)
|
|
progress_callback: Optional callback for progress updates
|
|
manual_file_callback: Optional callback for manual file selection (non-Premium)
|
|
confirmation_callback: Optional callback for user confirmation
|
|
Takes description string, returns True if user confirms
|
|
|
|
Returns:
|
|
Tuple of (automation_was_run: bool, error_message: Optional[str])
|
|
"""
|
|
try:
|
|
# Check if this is VNV (pass install location for ModOrganizer.ini check)
|
|
if not should_offer_vnv_automation(modlist_name, modlist_install_location):
|
|
logger.debug(f"Modlist '{modlist_name}' does not require VNV automation")
|
|
return False, None
|
|
|
|
logger.info(f"VNV detected: {modlist_name}")
|
|
|
|
# Initialize service
|
|
vnv_service = VNVPostInstallService(
|
|
modlist_install_location=modlist_install_location,
|
|
game_root=game_root,
|
|
ttw_installer_path=ttw_installer_path
|
|
)
|
|
|
|
# Check what's already done
|
|
completed = vnv_service.check_already_completed()
|
|
# Only skip if ALL three steps are completed
|
|
if completed['root_mods'] and completed['4gb_patch'] and completed['bsa_decompressed']:
|
|
logger.info("VNV automation steps already completed")
|
|
if progress_callback:
|
|
progress_callback("VNV post-install steps already completed")
|
|
return False, None
|
|
|
|
# Get confirmation from user (required)
|
|
if not confirmation_callback:
|
|
logger.error("VNV automation requires confirmation_callback")
|
|
return False, "VNV automation requires user confirmation"
|
|
|
|
if confirmation_callback:
|
|
description = vnv_service.get_automation_description()
|
|
if not confirmation_callback(description):
|
|
logger.info("User declined VNV automation")
|
|
if progress_callback:
|
|
progress_callback("VNV automation skipped by user")
|
|
return False, None
|
|
|
|
# Run automation
|
|
logger.info("Starting VNV post-install automation")
|
|
if progress_callback:
|
|
progress_callback("Running VNV post-install automation...")
|
|
|
|
success, message = vnv_service.run_all_steps(
|
|
progress_callback=progress_callback,
|
|
manual_file_callback=manual_file_callback
|
|
)
|
|
|
|
if success:
|
|
logger.info(f"VNV automation completed: {message}")
|
|
if progress_callback:
|
|
progress_callback(f"VNV automation: {message}")
|
|
return True, None
|
|
else:
|
|
logger.error(f"VNV automation failed: {message}")
|
|
return True, message
|
|
|
|
except Exception as e:
|
|
error_msg = f"VNV automation error: {str(e)}"
|
|
logger.error(error_msg, exc_info=True)
|
|
return True, error_msg
|