From 984c10b6b606421d23f2a7ab8e43c3820d12d03a Mon Sep 17 00:00:00 2001 From: BrettMayson Date: Thu, 2 Nov 2023 05:30:06 -0600 Subject: [PATCH] Launch: support for presets (#594) --- Cargo.lock | 1 + bin/Cargo.toml | 1 + bin/src/commands/launch.rs | 52 +++++++++++++++++++++++++++----- bin/src/error.rs | 3 ++ book/commands/launch.md | 9 +++++- libs/common/src/project/hemtt.rs | 10 ++++++ 6 files changed, 68 insertions(+), 8 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7295d7de..1f29e2c7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -797,6 +797,7 @@ dependencies = [ "hemtt-signing", "num_cpus", "rayon", + "regex", "reqwest", "rhai", "rust-embed", diff --git a/bin/Cargo.toml b/bin/Cargo.toml index e8db9c8d..8720ec27 100644 --- a/bin/Cargo.toml +++ b/bin/Cargo.toml @@ -29,6 +29,7 @@ git2 = { workspace = true } glob = "0.3.1" num_cpus = "1.16.0" rayon = "1.8.0" +regex = "1.10.2" reqwest = { version = "0.11.22", features = ["blocking", "json"] } rhai = "1.16.3" rust-embed = "8.0.0" diff --git a/bin/src/commands/launch.rs b/bin/src/commands/launch.rs index a709b6a9..116a0f2f 100644 --- a/bin/src/commands/launch.rs +++ b/bin/src/commands/launch.rs @@ -5,6 +5,7 @@ use std::{ use clap::{ArgMatches, Command}; use hemtt_common::project::{hemtt::LaunchOptions, ProjectConfig}; +use regex::Regex; use steamlocate::SteamDir; use crate::{error::Error, link::create_link}; @@ -77,6 +78,38 @@ pub fn execute(matches: &ArgMatches) -> Result<(), Error> { path.display().to_string() }); + let mut meta = None; + let meta_path = std::env::current_dir()?.join("meta.cpp"); + if meta_path.exists() { + let content = std::fs::read_to_string(meta_path)?; + let regex = Regex::new(r"publishedid\s*=\s*(\d+);").unwrap(); + if let Some(id) = regex.captures(&content).map(|c| c[1].to_string()) { + meta = Some(id); + } + } + + let mut workshop = launch.workshop().to_vec(); + + for preset in launch.presets() { + let html = std::env::current_dir()? + .join(".hemtt/presets") + .join(preset) + .with_extension("html"); + if !html.exists() { + return Err(Error::PresetNotFound(preset.to_string())); + } + let html = std::fs::read_to_string(html)?; + let regex = Regex::new( + r#"(?m)href="https:\/\/steamcommunity\.com\/sharedfiles\/filedetails\/\?id=(\d+)""#, + ) + .unwrap(); + for id in regex.captures_iter(&html).map(|c| c[1].to_string()) { + if !workshop.contains(&id) { + workshop.push(id); + } + } + } + // climb to the workshop folder if !launch.workshop().is_empty() { let Some(common) = arma3dir.path.parent() else { @@ -89,19 +122,24 @@ pub fn execute(matches: &ArgMatches) -> Result<(), Error> { if !workshop_folder.exists() { return Err(Error::WorkshopNotFound); }; - for load_mod in launch.workshop() { - let mod_path = workshop_folder.join(load_mod); + for load_mod in workshop { + if Some(load_mod.clone()) == meta { + warn!( + "Skipping mod {} as it is the same as the project's meta.cpp id", + load_mod + ); + continue; + } + let mod_path = workshop_folder.join(&load_mod); if !mod_path.exists() { - return Err(Error::WorkshopModNotFound(load_mod.to_string())); + return Err(Error::WorkshopModNotFound(load_mod)); }; mods.push(mod_path.display().to_string()); } } - if !launch.dlc().is_empty() { - for dlc in launch.dlc() { - mods.push(dlc.to_mod().to_string()); - } + for dlc in launch.dlc() { + mods.push(dlc.to_mod().to_string()); } let ctx = super::dev::execute(matches, launch.optionals())?; diff --git a/bin/src/error.rs b/bin/src/error.rs index 1af3fac5..3d17f5a4 100644 --- a/bin/src/error.rs +++ b/bin/src/error.rs @@ -40,6 +40,9 @@ pub enum Error { WorkshopNotFound, #[error("Workshop mod not found: {0}")] WorkshopModNotFound(String), + #[error("Preset not found: {0}")] + PresetNotFound(String), + #[error("Main prefix not found: {0}")] MainPrefixNotFound(String), diff --git a/book/commands/launch.md b/book/commands/launch.md index 4b500a80..a351c0ea 100644 --- a/book/commands/launch.md +++ b/book/commands/launch.md @@ -51,6 +51,9 @@ mainprefix = "z" workshop = [ "450814997", # CBA_A3's Workshop ID ] +presets = [ + "main", # .html presets from .hemtt/presets/ +] dlc = [ "Western Sahara", ] @@ -81,6 +84,10 @@ dlc = [ A list of workshop IDs to launch with your mod. These are not subscribed to, and will need to be manually subscribed to in Steam. +### presets + +A list of `.html` presets to launch with your mod. Exported from the Arma 3 Launcher, and kept in `.hemtt/presets/`. + ### dlc A list of DLCs to launch with your mod. The fullname or short-code can be used. @@ -110,7 +117,7 @@ The name of the Arma 3 executable to launch. This is usually `arma3` or `arma3_x ## Options -### -e, --executable +### -e, --executable <executable> The Arma 3 executable to launch. Overrides the `executable` option in the configuration file. diff --git a/libs/common/src/project/hemtt.rs b/libs/common/src/project/hemtt.rs index 8c3af3c6..b05b8973 100644 --- a/libs/common/src/project/hemtt.rs +++ b/libs/common/src/project/hemtt.rs @@ -73,6 +73,10 @@ pub struct LaunchOptions { /// DLCs that should be launched with the mod dlc: Vec, + #[serde(default)] + /// HTML presets that should be launched with the mod + presets: Vec, + #[serde(default)] /// Optional addons that should be built into the mod optionals: Vec, @@ -99,6 +103,12 @@ impl LaunchOptions { &self.dlc } + #[must_use] + /// HTML presets that should be launched with the mod + pub fn presets(&self) -> &[String] { + &self.presets + } + #[must_use] /// Optional addons that should be built into the mod pub fn optionals(&self) -> &[String] {