hexomc_lib/install/
loader.rs1use async_trait::async_trait;
2use std::{path::{Path, PathBuf}, sync::Arc};
3
4use crate::error::Result;
5use crate::install::vanilla::LoaderType;
6
7pub type ProgressFn = Arc<dyn Fn(usize, usize, &str) + Send + Sync + 'static>;
10
11pub fn no_progress() -> ProgressFn {
12 Arc::new(|_, _, _| {})
13}
14
15#[async_trait]
23pub trait LoaderInstaller: Send + Sync {
24 fn loader_type(&self) -> LoaderType;
25
26 async fn available_versions(&self, mc_version: &str) -> Result<Vec<String>>;
29
30 async fn install(
34 &self,
35 mc_version: &str,
36 instance_name: &str,
37 base_dir: &Path,
38 progress: ProgressFn,
39 ) -> Result<()>;
40}
41
42pub struct VanillaInstaller;
43
44#[async_trait]
45impl LoaderInstaller for VanillaInstaller {
46 fn loader_type(&self) -> LoaderType {
47 LoaderType::Vanilla
48 }
49
50 async fn available_versions(&self, _mc_version: &str) -> Result<Vec<String>> {
51 Ok(vec![])
52 }
53
54 async fn install(
55 &self,
56 mc_version: &str,
57 instance_name: &str,
58 base_dir: &Path,
59 progress: ProgressFn,
60 ) -> Result<()> {
61 crate::install::vanilla::install_vanilla(mc_version, instance_name, base_dir, move |d, t, s| {
62 progress(d, t, s)
63 })
64 .await?;
65 Ok(())
66 }
67}
68
69pub struct FabricInstaller {
70 pub loader_version: Option<String>,
72}
73
74impl FabricInstaller {
75 pub fn new(loader_version: impl Into<String>) -> Self {
76 Self { loader_version: Some(loader_version.into()) }
77 }
78
79 pub fn latest() -> Self {
80 Self { loader_version: None }
81 }
82}
83
84#[async_trait]
85impl LoaderInstaller for FabricInstaller {
86 fn loader_type(&self) -> LoaderType {
87 LoaderType::Fabric
88 }
89
90 async fn available_versions(&self, mc_version: &str) -> Result<Vec<String>> {
91 let versions = crate::install::fabric::get_fabric_loader_versions(mc_version).await?;
92 Ok(versions.into_iter().map(|v| v.version).collect())
93 }
94
95 async fn install(
96 &self,
97 mc_version: &str,
98 instance_name: &str,
99 base_dir: &Path,
100 _progress: ProgressFn,
101 ) -> Result<()> {
102 let loader_ver = match &self.loader_version {
103 Some(v) => v.clone(),
104 None => {
105 let versions =
106 crate::install::fabric::get_fabric_loader_versions(mc_version).await?;
107 versions
108 .into_iter()
109 .find(|v| v.stable)
110 .map(|v| v.version)
111 .unwrap_or_default()
112 }
113 };
114 crate::install::fabric::install_fabric(mc_version, &loader_ver, instance_name, base_dir).await
115 }
116}
117
118pub struct ForgeInstaller {
119 pub forge_version: Option<String>,
121 pub java_path: PathBuf,
122}
123
124impl ForgeInstaller {
125 pub fn new(java_path: impl Into<PathBuf>) -> Self {
126 Self { forge_version: None, java_path: java_path.into() }
127 }
128
129 pub fn with_version(java_path: impl Into<PathBuf>, version: impl Into<String>) -> Self {
130 Self { forge_version: Some(version.into()), java_path: java_path.into() }
131 }
132}
133
134#[async_trait]
135impl LoaderInstaller for ForgeInstaller {
136 fn loader_type(&self) -> LoaderType {
137 LoaderType::Forge
138 }
139
140 async fn available_versions(&self, mc_version: &str) -> Result<Vec<String>> {
141 crate::install::forge::get_forge_versions(mc_version).await
142 }
143
144 async fn install(
145 &self,
146 mc_version: &str,
147 instance_name: &str,
148 base_dir: &Path,
149 _progress: ProgressFn,
150 ) -> Result<()> {
151 crate::install::forge::install_forge(
152 mc_version,
153 self.forge_version.as_deref(),
154 instance_name,
155 &self.java_path,
156 base_dir,
157 )
158 .await
159 }
160}
161
162pub struct NeoForgeInstaller {
163 pub neoforge_version: Option<String>,
165 pub java_path: PathBuf,
166}
167
168impl NeoForgeInstaller {
169 pub fn new(java_path: impl Into<PathBuf>) -> Self {
170 Self { neoforge_version: None, java_path: java_path.into() }
171 }
172
173 pub fn with_version(java_path: impl Into<PathBuf>, version: impl Into<String>) -> Self {
174 Self { neoforge_version: Some(version.into()), java_path: java_path.into() }
175 }
176}
177
178#[async_trait]
179impl LoaderInstaller for NeoForgeInstaller {
180 fn loader_type(&self) -> LoaderType {
181 LoaderType::NeoForge
182 }
183
184 async fn available_versions(&self, mc_version: &str) -> Result<Vec<String>> {
185 crate::install::neoforge::get_neoforge_versions(mc_version).await
186 }
187
188 async fn install(
189 &self,
190 mc_version: &str,
191 instance_name: &str,
192 base_dir: &Path,
193 _progress: ProgressFn,
194 ) -> Result<()> {
195 crate::install::neoforge::install_neoforge(
196 mc_version,
197 self.neoforge_version.as_deref(),
198 instance_name,
199 &self.java_path,
200 base_dir,
201 )
202 .await
203 }
204}
205
206pub fn create_loader(
208 loader_type: LoaderType,
209 java_path: Option<PathBuf>,
210) -> Box<dyn LoaderInstaller> {
211 match loader_type {
212 LoaderType::Vanilla => Box::new(VanillaInstaller),
213 LoaderType::Fabric => Box::new(FabricInstaller::latest()),
214 LoaderType::Forge => Box::new(ForgeInstaller::new(java_path.unwrap_or_default())),
215 LoaderType::NeoForge => Box::new(NeoForgeInstaller::new(java_path.unwrap_or_default())),
216 }
217}
218
219pub async fn install_with_loader(
232 mc_version: &str,
233 instance_name: &str,
234 base_dir: &Path,
235 loader: &dyn LoaderInstaller,
236 progress: ProgressFn,
237) -> Result<()> {
238 if loader.loader_type() != LoaderType::Vanilla {
240 VanillaInstaller
241 .install(mc_version, instance_name, base_dir, progress.clone())
242 .await?;
243 }
244
245 loader.install(mc_version, instance_name, base_dir, progress).await
247}