You've already forked AstralRinth
forked from didirus/AstralRinth
Debug pin macro (#118)
* debug pin macro * Added debug pinning macro * working on windows * removed remaining box pins
This commit is contained in:
@@ -54,6 +54,7 @@ pub async fn download_minecraft(
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all, fields(version = version.id.as_str(), loader = ?loader))]
|
||||
#[theseus_macros::debug_pin]
|
||||
pub async fn download_version_info(
|
||||
st: &State,
|
||||
version: &GameVersion,
|
||||
@@ -61,93 +62,84 @@ pub async fn download_version_info(
|
||||
force: Option<bool>,
|
||||
loading_bar: Option<&LoadingBarId>,
|
||||
) -> crate::Result<GameVersionInfo> {
|
||||
Box::pin(async move {
|
||||
let version_id = loader.map_or(version.id.clone(), |it| {
|
||||
format!("{}-{}", version.id, it.id)
|
||||
});
|
||||
tracing::debug!("Loading version info for Minecraft {version_id}");
|
||||
let path = st
|
||||
.directories
|
||||
.version_dir(&version_id)
|
||||
.join(format!("{version_id}.json"));
|
||||
let version_id = loader
|
||||
.map_or(version.id.clone(), |it| format!("{}-{}", version.id, it.id));
|
||||
tracing::debug!("Loading version info for Minecraft {version_id}");
|
||||
let path = st
|
||||
.directories
|
||||
.version_dir(&version_id)
|
||||
.join(format!("{version_id}.json"));
|
||||
|
||||
let res = if path.exists() && !force.unwrap_or(false) {
|
||||
fs::read(path)
|
||||
.err_into::<crate::Error>()
|
||||
.await
|
||||
.and_then(|ref it| Ok(serde_json::from_slice(it)?))
|
||||
} else {
|
||||
tracing::info!(
|
||||
"Downloading version info for version {}",
|
||||
&version.id
|
||||
);
|
||||
let mut info = d::minecraft::fetch_version_info(version).await?;
|
||||
let res = if path.exists() && !force.unwrap_or(false) {
|
||||
fs::read(path)
|
||||
.err_into::<crate::Error>()
|
||||
.await
|
||||
.and_then(|ref it| Ok(serde_json::from_slice(it)?))
|
||||
} else {
|
||||
tracing::info!("Downloading version info for version {}", &version.id);
|
||||
let mut info = d::minecraft::fetch_version_info(version).await?;
|
||||
|
||||
if let Some(loader) = loader {
|
||||
let partial =
|
||||
d::modded::fetch_partial_version(&loader.url).await?;
|
||||
info = d::modded::merge_partial_version(partial, info);
|
||||
}
|
||||
info.id = version_id.clone();
|
||||
|
||||
write(&path, &serde_json::to_vec(&info)?, &st.io_semaphore).await?;
|
||||
Ok(info)
|
||||
}?;
|
||||
|
||||
if let Some(loading_bar) = loading_bar {
|
||||
emit_loading(loading_bar, 5.0, None).await?;
|
||||
if let Some(loader) = loader {
|
||||
let partial = d::modded::fetch_partial_version(&loader.url).await?;
|
||||
info = d::modded::merge_partial_version(partial, info);
|
||||
}
|
||||
info.id = version_id.clone();
|
||||
|
||||
tracing::debug!("Loaded version info for Minecraft {version_id}");
|
||||
Ok(res)
|
||||
})
|
||||
.await
|
||||
write(&path, &serde_json::to_vec(&info)?, &st.io_semaphore).await?;
|
||||
Ok(info)
|
||||
}?;
|
||||
|
||||
if let Some(loading_bar) = loading_bar {
|
||||
emit_loading(loading_bar, 5.0, None).await?;
|
||||
}
|
||||
|
||||
tracing::debug!("Loaded version info for Minecraft {version_id}");
|
||||
Ok(res)
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
#[theseus_macros::debug_pin]
|
||||
pub async fn download_client(
|
||||
st: &State,
|
||||
version_info: &GameVersionInfo,
|
||||
loading_bar: Option<&LoadingBarId>,
|
||||
) -> crate::Result<()> {
|
||||
Box::pin(async move {
|
||||
let version = &version_info.id;
|
||||
tracing::debug!("Locating client for version {version}");
|
||||
let client_download = version_info
|
||||
.downloads
|
||||
.get(&d::minecraft::DownloadType::Client)
|
||||
.ok_or(
|
||||
crate::ErrorKind::LauncherError(format!(
|
||||
"No client downloads exist for version {version}"
|
||||
))
|
||||
.as_error(),
|
||||
)?;
|
||||
let path = st
|
||||
.directories
|
||||
.version_dir(version)
|
||||
.join(format!("{version}.jar"));
|
||||
let version = &version_info.id;
|
||||
tracing::debug!("Locating client for version {version}");
|
||||
let client_download = version_info
|
||||
.downloads
|
||||
.get(&d::minecraft::DownloadType::Client)
|
||||
.ok_or(
|
||||
crate::ErrorKind::LauncherError(format!(
|
||||
"No client downloads exist for version {version}"
|
||||
))
|
||||
.as_error(),
|
||||
)?;
|
||||
let path = st
|
||||
.directories
|
||||
.version_dir(version)
|
||||
.join(format!("{version}.jar"));
|
||||
|
||||
if !path.exists() {
|
||||
let bytes = fetch(
|
||||
&client_download.url,
|
||||
Some(&client_download.sha1),
|
||||
&st.fetch_semaphore,
|
||||
)
|
||||
.await?;
|
||||
write(&path, &bytes, &st.io_semaphore).await?;
|
||||
tracing::trace!("Fetched client version {version}");
|
||||
}
|
||||
if let Some(loading_bar) = loading_bar {
|
||||
emit_loading(loading_bar, 9.0, None).await?;
|
||||
}
|
||||
if !path.exists() {
|
||||
let bytes = fetch(
|
||||
&client_download.url,
|
||||
Some(&client_download.sha1),
|
||||
&st.fetch_semaphore,
|
||||
)
|
||||
.await?;
|
||||
write(&path, &bytes, &st.io_semaphore).await?;
|
||||
tracing::trace!("Fetched client version {version}");
|
||||
}
|
||||
if let Some(loading_bar) = loading_bar {
|
||||
emit_loading(loading_bar, 9.0, None).await?;
|
||||
}
|
||||
|
||||
tracing::debug!("Client loaded for version {version}!");
|
||||
Ok(())
|
||||
})
|
||||
.await
|
||||
tracing::debug!("Client loaded for version {version}!");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip_all)]
|
||||
#[theseus_macros::debug_pin]
|
||||
pub async fn download_assets_index(
|
||||
st: &State,
|
||||
version: &GameVersionInfo,
|
||||
@@ -179,6 +171,7 @@ pub async fn download_assets_index(
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(st, index))]
|
||||
#[theseus_macros::debug_pin]
|
||||
pub async fn download_assets(
|
||||
st: &State,
|
||||
with_legacy: bool,
|
||||
@@ -186,13 +179,12 @@ pub async fn download_assets(
|
||||
loading_bar: Option<&LoadingBarId>,
|
||||
loading_amount: f64,
|
||||
) -> crate::Result<()> {
|
||||
Box::pin(async move {
|
||||
tracing::debug!("Loading assets");
|
||||
let num_futs = index.objects.len();
|
||||
let assets = stream::iter(index.objects.iter())
|
||||
.map(Ok::<(&String, &Asset), crate::Error>);
|
||||
tracing::debug!("Loading assets");
|
||||
let num_futs = index.objects.len();
|
||||
let assets = stream::iter(index.objects.iter())
|
||||
.map(Ok::<(&String, &Asset), crate::Error>);
|
||||
|
||||
loading_try_for_each_concurrent(assets,
|
||||
loading_try_for_each_concurrent(assets,
|
||||
None,
|
||||
loading_bar,
|
||||
loading_amount,
|
||||
@@ -236,12 +228,12 @@ pub async fn download_assets(
|
||||
tracing::trace!("Loaded asset with hash {hash}");
|
||||
Ok(())
|
||||
}).await?;
|
||||
tracing::debug!("Done loading assets!");
|
||||
Ok(())
|
||||
}).await
|
||||
tracing::debug!("Done loading assets!");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(st, libraries))]
|
||||
#[theseus_macros::debug_pin]
|
||||
pub async fn download_libraries(
|
||||
st: &State,
|
||||
libraries: &[Library],
|
||||
@@ -250,15 +242,14 @@ pub async fn download_libraries(
|
||||
loading_amount: f64,
|
||||
java_arch: &str,
|
||||
) -> crate::Result<()> {
|
||||
Box::pin(async move {
|
||||
tracing::debug!("Loading libraries");
|
||||
tracing::debug!("Loading libraries");
|
||||
|
||||
tokio::try_join! {
|
||||
fs::create_dir_all(st.directories.libraries_dir()),
|
||||
fs::create_dir_all(st.directories.version_natives_dir(version))
|
||||
}?;
|
||||
let num_files = libraries.len();
|
||||
loading_try_for_each_concurrent(
|
||||
tokio::try_join! {
|
||||
fs::create_dir_all(st.directories.libraries_dir()),
|
||||
fs::create_dir_all(st.directories.version_natives_dir(version))
|
||||
}?;
|
||||
let num_files = libraries.len();
|
||||
loading_try_for_each_concurrent(
|
||||
stream::iter(libraries.iter())
|
||||
.map(Ok::<&Library, crate::Error>), None, loading_bar,loading_amount,num_files, None,|library| async move {
|
||||
if let Some(rules) = &library.rules {
|
||||
@@ -342,8 +333,6 @@ pub async fn download_libraries(
|
||||
}
|
||||
).await?;
|
||||
|
||||
tracing::debug!("Done loading libraries!");
|
||||
Ok(())
|
||||
|
||||
}).await
|
||||
tracing::debug!("Done loading libraries!");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -92,183 +92,186 @@ async fn get_java_version_from_profile(
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(profile))]
|
||||
#[theseus_macros::debug_pin]
|
||||
pub async fn install_minecraft(
|
||||
profile: &Profile,
|
||||
existing_loading_bar: Option<LoadingBarId>,
|
||||
) -> crate::Result<()> {
|
||||
Box::pin(async move {
|
||||
let loading_bar = init_or_edit_loading(
|
||||
existing_loading_bar,
|
||||
LoadingBarType::MinecraftDownload {
|
||||
// If we are downloading minecraft for a profile, provide its name and uuid
|
||||
profile_name: profile.metadata.name.clone(),
|
||||
profile_path: profile.path.clone(),
|
||||
},
|
||||
100.0,
|
||||
"Downloading Minecraft",
|
||||
)
|
||||
.await?;
|
||||
let loading_bar = init_or_edit_loading(
|
||||
existing_loading_bar,
|
||||
LoadingBarType::MinecraftDownload {
|
||||
// If we are downloading minecraft for a profile, provide its name and uuid
|
||||
profile_name: profile.metadata.name.clone(),
|
||||
profile_path: profile.path.clone(),
|
||||
},
|
||||
100.0,
|
||||
"Downloading Minecraft",
|
||||
)
|
||||
.await?;
|
||||
|
||||
crate::api::profile::edit(&profile.path, |prof| {
|
||||
prof.install_stage = ProfileInstallStage::Installing;
|
||||
crate::api::profile::edit(&profile.path, |prof| {
|
||||
prof.install_stage = ProfileInstallStage::Installing;
|
||||
|
||||
async { Ok(()) }
|
||||
})
|
||||
.await?;
|
||||
State::sync().await?;
|
||||
async { Ok(()) }
|
||||
})
|
||||
.await?;
|
||||
State::sync().await?;
|
||||
|
||||
let state = State::get().await?;
|
||||
let instance_path = &canonicalize(&profile.path)?;
|
||||
let metadata = state.metadata.read().await;
|
||||
let state = State::get().await?;
|
||||
let instance_path = &canonicalize(&profile.path)?;
|
||||
let metadata = state.metadata.read().await;
|
||||
|
||||
let version = metadata
|
||||
.minecraft
|
||||
.versions
|
||||
.iter()
|
||||
.find(|it| it.id == profile.metadata.game_version)
|
||||
.ok_or(crate::ErrorKind::LauncherError(format!(
|
||||
"Invalid game version: {}",
|
||||
profile.metadata.game_version
|
||||
)))?;
|
||||
let version = metadata
|
||||
.minecraft
|
||||
.versions
|
||||
.iter()
|
||||
.find(|it| it.id == profile.metadata.game_version)
|
||||
.ok_or(crate::ErrorKind::LauncherError(format!(
|
||||
"Invalid game version: {}",
|
||||
profile.metadata.game_version
|
||||
)))?;
|
||||
|
||||
let version_jar = profile
|
||||
.metadata
|
||||
.loader_version
|
||||
.as_ref()
|
||||
.map_or(version.id.clone(), |it| {
|
||||
format!("{}-{}", version.id.clone(), it.id.clone())
|
||||
});
|
||||
let version_jar = profile
|
||||
.metadata
|
||||
.loader_version
|
||||
.as_ref()
|
||||
.map_or(version.id.clone(), |it| {
|
||||
format!("{}-{}", version.id.clone(), it.id.clone())
|
||||
});
|
||||
|
||||
// Download version info (5)
|
||||
let mut version_info = download::download_version_info(
|
||||
&state,
|
||||
version,
|
||||
profile.metadata.loader_version.as_ref(),
|
||||
None,
|
||||
Some(&loading_bar),
|
||||
)
|
||||
.await?;
|
||||
// Download version info (5)
|
||||
let mut version_info = download::download_version_info(
|
||||
&state,
|
||||
version,
|
||||
profile.metadata.loader_version.as_ref(),
|
||||
None,
|
||||
Some(&loading_bar),
|
||||
)
|
||||
.await?;
|
||||
|
||||
let java_version = get_java_version_from_profile(profile, &version_info).await?;
|
||||
let java_version =
|
||||
get_java_version_from_profile(profile, &version_info).await?;
|
||||
|
||||
// Download minecraft (5-90)
|
||||
download::download_minecraft(&state, &version_info, &loading_bar, &java_version.architecture).await?;
|
||||
// Download minecraft (5-90)
|
||||
download::download_minecraft(
|
||||
&state,
|
||||
&version_info,
|
||||
&loading_bar,
|
||||
&java_version.architecture,
|
||||
)
|
||||
.await?;
|
||||
|
||||
if let Some(processors) = &version_info.processors {
|
||||
let client_path = state
|
||||
.directories
|
||||
.version_dir(&version_jar)
|
||||
.join(format!("{version_jar}.jar"));
|
||||
if let Some(processors) = &version_info.processors {
|
||||
let client_path = state
|
||||
.directories
|
||||
.version_dir(&version_jar)
|
||||
.join(format!("{version_jar}.jar"));
|
||||
|
||||
if let Some(ref mut data) = version_info.data {
|
||||
processor_rules! {
|
||||
data;
|
||||
"SIDE":
|
||||
client => "client",
|
||||
server => "";
|
||||
"MINECRAFT_JAR" :
|
||||
client => client_path.to_string_lossy(),
|
||||
server => "";
|
||||
"MINECRAFT_VERSION":
|
||||
client => profile.metadata.game_version.clone(),
|
||||
server => "";
|
||||
"ROOT":
|
||||
client => instance_path.to_string_lossy(),
|
||||
server => "";
|
||||
"LIBRARY_DIR":
|
||||
client => state.directories.libraries_dir().to_string_lossy(),
|
||||
server => "";
|
||||
if let Some(ref mut data) = version_info.data {
|
||||
processor_rules! {
|
||||
data;
|
||||
"SIDE":
|
||||
client => "client",
|
||||
server => "";
|
||||
"MINECRAFT_JAR" :
|
||||
client => client_path.to_string_lossy(),
|
||||
server => "";
|
||||
"MINECRAFT_VERSION":
|
||||
client => profile.metadata.game_version.clone(),
|
||||
server => "";
|
||||
"ROOT":
|
||||
client => instance_path.to_string_lossy(),
|
||||
server => "";
|
||||
"LIBRARY_DIR":
|
||||
client => state.directories.libraries_dir().to_string_lossy(),
|
||||
server => "";
|
||||
}
|
||||
|
||||
emit_loading(&loading_bar, 0.0, Some("Running forge processors"))
|
||||
.await?;
|
||||
let total_length = processors.len();
|
||||
|
||||
// Forge processors (90-100)
|
||||
for (index, processor) in processors.iter().enumerate() {
|
||||
if let Some(sides) = &processor.sides {
|
||||
if !sides.contains(&String::from("client")) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
emit_loading(&loading_bar, 0.0, Some("Running forge processors"))
|
||||
.await?;
|
||||
let total_length = processors.len();
|
||||
let cp = wrap_ref_builder!(cp = processor.classpath.clone() => {
|
||||
cp.push(processor.jar.clone())
|
||||
});
|
||||
|
||||
// Forge processors (90-100)
|
||||
for (index, processor) in processors.iter().enumerate() {
|
||||
if let Some(sides) = &processor.sides {
|
||||
if !sides.contains(&String::from("client")) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
let cp = wrap_ref_builder!(cp = processor.classpath.clone() => {
|
||||
cp.push(processor.jar.clone())
|
||||
});
|
||||
|
||||
let child = Command::new(&java_version.path)
|
||||
.arg("-cp")
|
||||
.arg(args::get_class_paths_jar(
|
||||
let child = Command::new(&java_version.path)
|
||||
.arg("-cp")
|
||||
.arg(args::get_class_paths_jar(
|
||||
&state.directories.libraries_dir(),
|
||||
&cp,
|
||||
&java_version.architecture,
|
||||
)?)
|
||||
.arg(
|
||||
args::get_processor_main_class(args::get_lib_path(
|
||||
&state.directories.libraries_dir(),
|
||||
&cp,
|
||||
&java_version.architecture
|
||||
&processor.jar,
|
||||
false,
|
||||
)?)
|
||||
.arg(
|
||||
args::get_processor_main_class(args::get_lib_path(
|
||||
&state.directories.libraries_dir(),
|
||||
&processor.jar,
|
||||
false,
|
||||
)?)
|
||||
.await?
|
||||
.ok_or_else(|| {
|
||||
crate::ErrorKind::LauncherError(format!(
|
||||
"Could not find processor main class for {}",
|
||||
processor.jar
|
||||
))
|
||||
})?,
|
||||
)
|
||||
.args(args::get_processor_arguments(
|
||||
&state.directories.libraries_dir(),
|
||||
&processor.args,
|
||||
data,
|
||||
)?)
|
||||
.output()
|
||||
.await
|
||||
.map_err(|err| {
|
||||
.await?
|
||||
.ok_or_else(|| {
|
||||
crate::ErrorKind::LauncherError(format!(
|
||||
"Error running processor: {err}",
|
||||
"Could not find processor main class for {}",
|
||||
processor.jar
|
||||
))
|
||||
})?;
|
||||
|
||||
if !child.status.success() {
|
||||
return Err(crate::ErrorKind::LauncherError(format!(
|
||||
"Processor error: {}",
|
||||
String::from_utf8_lossy(&child.stderr)
|
||||
))
|
||||
.as_error());
|
||||
}
|
||||
|
||||
emit_loading(
|
||||
&loading_bar,
|
||||
30.0 / total_length as f64,
|
||||
Some(&format!(
|
||||
"Running forge processor {}/{}",
|
||||
index, total_length
|
||||
)),
|
||||
})?,
|
||||
)
|
||||
.await?;
|
||||
.args(args::get_processor_arguments(
|
||||
&state.directories.libraries_dir(),
|
||||
&processor.args,
|
||||
data,
|
||||
)?)
|
||||
.output()
|
||||
.await
|
||||
.map_err(|err| {
|
||||
crate::ErrorKind::LauncherError(format!(
|
||||
"Error running processor: {err}",
|
||||
))
|
||||
})?;
|
||||
|
||||
if !child.status.success() {
|
||||
return Err(crate::ErrorKind::LauncherError(format!(
|
||||
"Processor error: {}",
|
||||
String::from_utf8_lossy(&child.stderr)
|
||||
))
|
||||
.as_error());
|
||||
}
|
||||
|
||||
emit_loading(
|
||||
&loading_bar,
|
||||
30.0 / total_length as f64,
|
||||
Some(&format!(
|
||||
"Running forge processor {}/{}",
|
||||
index, total_length
|
||||
)),
|
||||
)
|
||||
.await?;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
crate::api::profile::edit(&profile.path, |prof| {
|
||||
prof.install_stage = ProfileInstallStage::Installed;
|
||||
crate::api::profile::edit(&profile.path, |prof| {
|
||||
prof.install_stage = ProfileInstallStage::Installed;
|
||||
|
||||
async { Ok(()) }
|
||||
})
|
||||
.await?;
|
||||
State::sync().await?;
|
||||
emit_loading(
|
||||
&loading_bar,
|
||||
1.0,
|
||||
Some("Finished installing"),
|
||||
)
|
||||
.await?;
|
||||
async { Ok(()) }
|
||||
})
|
||||
.await?;
|
||||
State::sync().await?;
|
||||
emit_loading(&loading_bar, 1.0, Some("Finished installing")).await?;
|
||||
|
||||
Ok(())
|
||||
}).await
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument]
|
||||
#[theseus_macros::debug_pin]
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub async fn launch_minecraft(
|
||||
java_args: &[String],
|
||||
@@ -280,156 +283,155 @@ pub async fn launch_minecraft(
|
||||
post_exit_hook: Option<Command>,
|
||||
profile: &Profile,
|
||||
) -> crate::Result<Arc<tokio::sync::RwLock<MinecraftChild>>> {
|
||||
Box::pin(async move {
|
||||
if profile.install_stage == ProfileInstallStage::PackInstalling
|
||||
|| profile.install_stage == ProfileInstallStage::Installing
|
||||
{
|
||||
return Err(crate::ErrorKind::LauncherError(
|
||||
"Profile is still installing".to_string(),
|
||||
)
|
||||
.into());
|
||||
}
|
||||
|
||||
if profile.install_stage != ProfileInstallStage::Installed {
|
||||
install_minecraft(profile, None).await?;
|
||||
}
|
||||
|
||||
let state = State::get().await?;
|
||||
let metadata = state.metadata.read().await;
|
||||
let instance_path = &canonicalize(&profile.path)?;
|
||||
|
||||
let version = metadata
|
||||
.minecraft
|
||||
.versions
|
||||
.iter()
|
||||
.find(|it| it.id == profile.metadata.game_version)
|
||||
.ok_or(crate::ErrorKind::LauncherError(format!(
|
||||
"Invalid game version: {}",
|
||||
profile.metadata.game_version
|
||||
)))?;
|
||||
|
||||
let version_jar = profile
|
||||
.metadata
|
||||
.loader_version
|
||||
.as_ref()
|
||||
.map_or(version.id.clone(), |it| {
|
||||
format!("{}-{}", version.id.clone(), it.id.clone())
|
||||
});
|
||||
|
||||
let version_info = download::download_version_info(
|
||||
&state,
|
||||
version,
|
||||
profile.metadata.loader_version.as_ref(),
|
||||
None,
|
||||
None,
|
||||
if profile.install_stage == ProfileInstallStage::PackInstalling
|
||||
|| profile.install_stage == ProfileInstallStage::Installing
|
||||
{
|
||||
return Err(crate::ErrorKind::LauncherError(
|
||||
"Profile is still installing".to_string(),
|
||||
)
|
||||
.await?;
|
||||
.into());
|
||||
}
|
||||
|
||||
let java_version = get_java_version_from_profile(profile, &version_info).await?;
|
||||
if profile.install_stage != ProfileInstallStage::Installed {
|
||||
install_minecraft(profile, None).await?;
|
||||
}
|
||||
|
||||
let client_path = state
|
||||
.directories
|
||||
.version_dir(&version_jar)
|
||||
.join(format!("{version_jar}.jar"));
|
||||
let state = State::get().await?;
|
||||
let metadata = state.metadata.read().await;
|
||||
let instance_path = &canonicalize(&profile.path)?;
|
||||
|
||||
let args = version_info.arguments.clone().unwrap_or_default();
|
||||
let mut command = match wrapper {
|
||||
Some(hook) => {
|
||||
wrap_ref_builder!(it = Command::new(hook) => {it.arg(&java_version.path)})
|
||||
}
|
||||
None => Command::new(&java_version.path),
|
||||
};
|
||||
let version = metadata
|
||||
.minecraft
|
||||
.versions
|
||||
.iter()
|
||||
.find(|it| it.id == profile.metadata.game_version)
|
||||
.ok_or(crate::ErrorKind::LauncherError(format!(
|
||||
"Invalid game version: {}",
|
||||
profile.metadata.game_version
|
||||
)))?;
|
||||
|
||||
let env_args = Vec::from(env_args);
|
||||
let version_jar = profile
|
||||
.metadata
|
||||
.loader_version
|
||||
.as_ref()
|
||||
.map_or(version.id.clone(), |it| {
|
||||
format!("{}-{}", version.id.clone(), it.id.clone())
|
||||
});
|
||||
|
||||
// Check if profile has a running profile, and reject running the command if it does
|
||||
// Done late so a quick double call doesn't launch two instances
|
||||
let existing_processes =
|
||||
process::get_uuids_by_profile_path(instance_path).await?;
|
||||
if let Some(uuid) = existing_processes.first() {
|
||||
return Err(crate::ErrorKind::LauncherError(format!(
|
||||
"Profile {} is already running at UUID: {uuid}",
|
||||
instance_path.display()
|
||||
))
|
||||
.as_error());
|
||||
let version_info = download::download_version_info(
|
||||
&state,
|
||||
version,
|
||||
profile.metadata.loader_version.as_ref(),
|
||||
None,
|
||||
None,
|
||||
)
|
||||
.await?;
|
||||
|
||||
let java_version =
|
||||
get_java_version_from_profile(profile, &version_info).await?;
|
||||
|
||||
let client_path = state
|
||||
.directories
|
||||
.version_dir(&version_jar)
|
||||
.join(format!("{version_jar}.jar"));
|
||||
|
||||
let args = version_info.arguments.clone().unwrap_or_default();
|
||||
let mut command = match wrapper {
|
||||
Some(hook) => {
|
||||
wrap_ref_builder!(it = Command::new(hook) => {it.arg(&java_version.path)})
|
||||
}
|
||||
None => Command::new(&java_version.path),
|
||||
};
|
||||
|
||||
command
|
||||
.args(
|
||||
args::get_jvm_arguments(
|
||||
args.get(&d::minecraft::ArgumentType::Jvm)
|
||||
.map(|x| x.as_slice()),
|
||||
&state.directories.version_natives_dir(&version_jar),
|
||||
let env_args = Vec::from(env_args);
|
||||
|
||||
// Check if profile has a running profile, and reject running the command if it does
|
||||
// Done late so a quick double call doesn't launch two instances
|
||||
let existing_processes =
|
||||
process::get_uuids_by_profile_path(instance_path).await?;
|
||||
if let Some(uuid) = existing_processes.first() {
|
||||
return Err(crate::ErrorKind::LauncherError(format!(
|
||||
"Profile {} is already running at UUID: {uuid}",
|
||||
instance_path.display()
|
||||
))
|
||||
.as_error());
|
||||
}
|
||||
|
||||
command
|
||||
.args(
|
||||
args::get_jvm_arguments(
|
||||
args.get(&d::minecraft::ArgumentType::Jvm)
|
||||
.map(|x| x.as_slice()),
|
||||
&state.directories.version_natives_dir(&version_jar),
|
||||
&state.directories.libraries_dir(),
|
||||
&args::get_class_paths(
|
||||
&state.directories.libraries_dir(),
|
||||
&args::get_class_paths(
|
||||
&state.directories.libraries_dir(),
|
||||
version_info.libraries.as_slice(),
|
||||
&client_path,
|
||||
&java_version.architecture
|
||||
)?,
|
||||
&version_jar,
|
||||
*memory,
|
||||
Vec::from(java_args),
|
||||
&java_version.architecture
|
||||
)?
|
||||
.into_iter()
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
.arg(version_info.main_class.clone())
|
||||
.args(
|
||||
args::get_minecraft_arguments(
|
||||
args.get(&d::minecraft::ArgumentType::Game)
|
||||
.map(|x| x.as_slice()),
|
||||
version_info.minecraft_arguments.as_deref(),
|
||||
credentials,
|
||||
&version.id,
|
||||
&version_info.asset_index.id,
|
||||
instance_path,
|
||||
&state.directories.assets_dir(),
|
||||
&version.type_,
|
||||
*resolution,
|
||||
&java_version.architecture
|
||||
)?
|
||||
.into_iter()
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
.current_dir(instance_path.clone())
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped());
|
||||
version_info.libraries.as_slice(),
|
||||
&client_path,
|
||||
&java_version.architecture,
|
||||
)?,
|
||||
&version_jar,
|
||||
*memory,
|
||||
Vec::from(java_args),
|
||||
&java_version.architecture,
|
||||
)?
|
||||
.into_iter()
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
.arg(version_info.main_class.clone())
|
||||
.args(
|
||||
args::get_minecraft_arguments(
|
||||
args.get(&d::minecraft::ArgumentType::Game)
|
||||
.map(|x| x.as_slice()),
|
||||
version_info.minecraft_arguments.as_deref(),
|
||||
credentials,
|
||||
&version.id,
|
||||
&version_info.asset_index.id,
|
||||
instance_path,
|
||||
&state.directories.assets_dir(),
|
||||
&version.type_,
|
||||
*resolution,
|
||||
&java_version.architecture,
|
||||
)?
|
||||
.into_iter()
|
||||
.collect::<Vec<_>>(),
|
||||
)
|
||||
.current_dir(instance_path.clone())
|
||||
.stdout(Stdio::piped())
|
||||
.stderr(Stdio::piped());
|
||||
|
||||
// CARGO-set DYLD_LIBRARY_PATH breaks Minecraft on macOS during testing on playground
|
||||
#[cfg(target_os = "macos")]
|
||||
if std::env::var("CARGO").is_ok() {
|
||||
command.env_remove("DYLD_FALLBACK_LIBRARY_PATH");
|
||||
}
|
||||
command.envs(env_args);
|
||||
// CARGO-set DYLD_LIBRARY_PATH breaks Minecraft on macOS during testing on playground
|
||||
#[cfg(target_os = "macos")]
|
||||
if std::env::var("CARGO").is_ok() {
|
||||
command.env_remove("DYLD_FALLBACK_LIBRARY_PATH");
|
||||
}
|
||||
command.envs(env_args);
|
||||
|
||||
// Get Modrinth logs directories
|
||||
let datetime_string =
|
||||
chrono::Local::now().format("%Y%m%d_%H%M%S").to_string();
|
||||
let logs_dir = {
|
||||
let st = State::get().await?;
|
||||
st.directories
|
||||
.profile_logs_dir(profile.uuid)
|
||||
.join(&datetime_string)
|
||||
};
|
||||
fs::create_dir_all(&logs_dir)?;
|
||||
// Get Modrinth logs directories
|
||||
let datetime_string =
|
||||
chrono::Local::now().format("%Y%m%d_%H%M%S").to_string();
|
||||
let logs_dir = {
|
||||
let st = State::get().await?;
|
||||
st.directories
|
||||
.profile_logs_dir(profile.uuid)
|
||||
.join(&datetime_string)
|
||||
};
|
||||
fs::create_dir_all(&logs_dir)?;
|
||||
|
||||
let stdout_log_path = logs_dir.join("stdout.log");
|
||||
let stderr_log_path = logs_dir.join("stderr.log");
|
||||
let stdout_log_path = logs_dir.join("stdout.log");
|
||||
let stderr_log_path = logs_dir.join("stderr.log");
|
||||
|
||||
// Create Minecraft child by inserting it into the state
|
||||
// This also spawns the process and prepares the subsequent processes
|
||||
let mut state_children = state.children.write().await;
|
||||
state_children
|
||||
.insert_process(
|
||||
Uuid::new_v4(),
|
||||
instance_path.to_path_buf(),
|
||||
stdout_log_path,
|
||||
stderr_log_path,
|
||||
command,
|
||||
post_exit_hook,
|
||||
)
|
||||
.await
|
||||
}).await
|
||||
// Create Minecraft child by inserting it into the state
|
||||
// This also spawns the process and prepares the subsequent processes
|
||||
let mut state_children = state.children.write().await;
|
||||
state_children
|
||||
.insert_process(
|
||||
Uuid::new_v4(),
|
||||
instance_path.to_path_buf(),
|
||||
stdout_log_path,
|
||||
stderr_log_path,
|
||||
command,
|
||||
post_exit_hook,
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user