cobble_core/instance/fabric/
launch.rs

1use crate::error::{CobbleError, CobbleResult};
2use crate::instance::Instance;
3use crate::minecraft::{
4    build_fabric_launch_command, build_launch_command, GameProcess, GameProcessHandle,
5    LaunchOptions,
6};
7use std::process::{Command, Stdio};
8use tokio::process::Child;
9
10impl Instance {
11    /// Builds the launch command for this instance.
12    /// Uses fabric when enabled.
13    /// The instance needs to be properly installed.
14    pub async fn launch_command(&self, options: &LaunchOptions) -> CobbleResult<Command> {
15        trace!("Check if instance is installed");
16        if !self.installed {
17            return Err(CobbleError::NotInstalled);
18        }
19
20        trace!("Read version data from disk");
21        let version_data = self.read_version_data().await?;
22
23        let command = match &self.fabric_version {
24            Some(_) => {
25                trace!("Read fabric version data from disk");
26                let fabric_version_data = self.read_fabric_version_data().await?;
27
28                build_fabric_launch_command(
29                    &version_data,
30                    &fabric_version_data,
31                    options,
32                    self.dot_minecraft_path(),
33                    self.libraries_path(),
34                    self.assets_path(),
35                    self.natives_path(),
36                    self.log_configs_path(),
37                )
38            }
39            None => build_launch_command(
40                &version_data,
41                options,
42                self.dot_minecraft_path(),
43                self.libraries_path(),
44                self.assets_path(),
45                self.natives_path(),
46                self.log_configs_path(),
47            ),
48        };
49
50        Ok(command)
51    }
52
53    /// Launches the instance as a child process.
54    /// Uses fabric when enabled.
55    /// Game process exits if parent exits.
56    pub async fn launch<I, O, E>(
57        &self,
58        options: &LaunchOptions,
59        stdin: I,
60        stdout: O,
61        stderr: E,
62    ) -> CobbleResult<Child>
63    where
64        I: Into<Stdio>,
65        O: Into<Stdio>,
66        E: Into<Stdio>,
67    {
68        let mut command = self.launch_command(options).await?;
69
70        command.stdin(stdin).stdout(stdout).stderr(stderr);
71
72        let mut command = tokio::process::Command::from(command);
73
74        Ok(command.spawn()?)
75    }
76
77    /// Launches the instance as a detached process.
78    /// Uses fabric when enabled.
79    /// Game process does not exit if parent exits.
80    ///
81    /// On unix platforms it is done by forking the process.
82    ///
83    /// On windows it is done using the
84    /// [DETACHED_PROCESS and CREATE_NEW_PROCESS_GROUP flags](https://docs.microsoft.com/en-us/windows/win32/procthread/process-creation-flags).
85    pub async fn detached_launch<I, O, E>(
86        &self,
87        options: &LaunchOptions,
88        stdin: I,
89        stdout: O,
90        stderr: E,
91    ) -> CobbleResult<GameProcessHandle>
92    where
93        I: Into<Stdio>,
94        O: Into<Stdio>,
95        E: Into<Stdio>,
96    {
97        let mut command = self.launch_command(options).await?;
98
99        command.stdin(stdin).stdout(stdout).stderr(stderr);
100
101        Ok(GameProcessHandle::launch(command)?)
102    }
103}