// SPDX-License-Identifier: GPL-3.0-or-later use crate::error::MolotovError; use crate::fflags::{FastFlagManager, FlagValue, PresetProfile}; use crate::region::ServerRegion; use crate::sandbox::SandboxConfig; use crate::watchdog::{LaunchStatus, LaunchWatchdog}; use std::path::PathBuf; #[derive(Debug, Clone)] pub struct LaunchOptions { pub place_id: Option, pub safe_mode: bool, pub region: ServerRegion, pub instance_id: String, pub fps_cap: Option, pub vram_skip_mips: bool, } pub struct LaunchPlan { pub place_id: Option, pub fflags_path: PathBuf, pub sandbox_config: SandboxConfig, pub is_safe_mode: bool, } pub struct Launcher { base_dir: PathBuf, } impl Launcher { pub fn new(base_dir: PathBuf) -> Self { Self { base_dir } } pub fn prepare_launch(&self, options: LaunchOptions) -> Result { let state_file = self.base_dir.join("launch_state.json"); let watchdog = LaunchWatchdog::new(state_file); // Check if Safe Mode is required without modifying state let activate_safe_mode = options.safe_mode || watchdog.status() == LaunchStatus::RequiresSafeMode; let mut fflag_mgr = FastFlagManager::new(); if activate_safe_mode { tracing::warn!("Launcher: launching in SAFE MODE with minimal default flags"); fflag_mgr.apply_preset(PresetProfile::Default); } else { fflag_mgr.apply_preset(PresetProfile::LowVram); options.region.apply_to_fflags(&mut fflag_mgr); // Apply custom user settings if let Some(fps) = options.fps_cap { fflag_mgr.set_flag("DFIntTaskSchedulerTargetFps", FlagValue::Integer(fps)); } if options.vram_skip_mips { fflag_mgr.set_flag("FIntDebugTextureManagerSkipMips", FlagValue::Integer(1)); } } let fflags_path = self.base_dir.join("ClientAppSettings.json"); fflag_mgr.export_client_app_settings(&fflags_path)?; let sandbox_config = SandboxConfig { instance_id: options.instance_id.clone(), data_dir: self.base_dir.join("instances").join(&options.instance_id).join("data"), config_dir: self.base_dir.join("instances").join(&options.instance_id).join("config"), nice_priority: -5, }; Ok(LaunchPlan { place_id: options.place_id, fflags_path, sandbox_config, is_safe_mode: activate_safe_mode, }) } pub fn record_launch_start(&self) -> Result<(), MolotovError> { let state_file = self.base_dir.join("launch_state.json"); let mut watchdog = LaunchWatchdog::new(state_file); watchdog.record_start() } pub fn record_launch_success(&self) -> Result<(), MolotovError> { let state_file = self.base_dir.join("launch_state.json"); let mut watchdog = LaunchWatchdog::new(state_file); watchdog.record_success() } }