From ebcbdaeec0e5d21d58aa8a10488bc3c829ed8552 Mon Sep 17 00:00:00 2001 From: Lucas Schwiderski Date: Wed, 22 Feb 2023 15:48:43 +0100 Subject: [PATCH] feat(dtmm): Rework mod template Ditch the `.mod` file and move its data into the config file. The `run` function was the only thing that could have been dynamic, but the vast majority of mods in VT2 never made use of that. Infact, VMF was probably the only mod that had a different content for that. --- crates/dtmm/src/engine.rs | 20 ++++++--------- crates/dtmm/src/state.rs | 45 ++++++++++++++++++++++++++++++--- crates/dtmt/src/cmd/build.rs | 31 ++++++++--------------- crates/dtmt/src/cmd/new.rs | 32 ++++++++--------------- crates/dtmt/src/mods/archive.rs | 18 ------------- lib/sdk/src/lib.rs | 20 +++++++++++++++ 6 files changed, 91 insertions(+), 75 deletions(-) diff --git a/crates/dtmm/src/engine.rs b/crates/dtmm/src/engine.rs index 0ec0566..3526cb5 100644 --- a/crates/dtmm/src/engine.rs +++ b/crates/dtmm/src/engine.rs @@ -14,9 +14,9 @@ use sdk::filetype::lua; use sdk::filetype::package::Package; use sdk::murmur::Murmur64; use sdk::{ - Bundle, BundleDatabase, BundleFile, BundleFileType, BundleFileVariant, FromBinary, ToBinary, + Bundle, BundleDatabase, BundleFile, BundleFileType, BundleFileVariant, FromBinary, ModConfig, + ToBinary, }; -use serde::Deserialize; use tokio::io::AsyncWriteExt; use tokio::{fs, try_join}; use tracing::Instrument; @@ -176,7 +176,10 @@ async fn build_bundles(state: Arc) -> Result<()> { bundle.add_file(file); - let src = mod_dir.join(pkg_info.get_name()); + let bundle_name = Murmur64::hash(pkg_info.get_name()) + .to_string() + .to_ascii_lowercase(); + let src = mod_dir.join(&bundle_name); let dest = bundle_dir.clone(); let pkg_name = pkg_info.get_name().clone(); let mod_name = mod_info.get_name().clone(); @@ -200,7 +203,7 @@ async fn build_bundles(state: Arc) -> Result<()> { dest.display() ); fs::hard_link(&src, dest.as_ref()).await.wrap_err_with(|| { - format!("failed to hard link bundle {pkg_name} for mod {mod_name}") + format!("failed to hard link bundle {pkg_name} for mod {mod_name}. src: {}, dest: {}", src.display(), dest.display()) }) } .instrument(span); @@ -376,13 +379,6 @@ pub(crate) async fn deploy_mods(state: State) -> Result<()> { Ok(()) } -#[derive(Debug, Default, Deserialize)] -struct ModConfig { - name: String, - #[serde(default)] - description: String, -} - #[tracing::instrument(skip(state))] pub(crate) async fn import_mod(state: State, info: FileInfo) -> Result { let data = fs::read(&info.path) @@ -462,7 +458,7 @@ pub(crate) async fn import_mod(state: State, info: FileInfo) -> Result .into_iter() .map(|(name, files)| PackageInfo::new(name, files.into_iter().collect())) .collect(); - let info = ModInfo::new(mod_cfg.name, mod_cfg.description, packages); + let info = ModInfo::new(mod_cfg, packages); Ok(info) } diff --git a/crates/dtmm/src/state.rs b/crates/dtmm/src/state.rs index ec6530d..3241585 100644 --- a/crates/dtmm/src/state.rs +++ b/crates/dtmm/src/state.rs @@ -7,6 +7,7 @@ use druid::{ AppDelegate, Command, Data, DelegateCtx, Env, FileInfo, Handled, Lens, Selector, SingleUse, Target, }; +use sdk::ModConfig; use tokio::sync::mpsc::UnboundedSender; use crate::Config; @@ -58,6 +59,27 @@ impl PackageInfo { } } +#[derive(Clone, Data, Debug)] +pub(crate) struct ModResourceInfo { + init: String, + data: String, + localization: String, +} + +impl ModResourceInfo { + pub(crate) fn get_init(&self) -> &String { + &self.init + } + + pub(crate) fn get_data(&self) -> &String { + &self.data + } + + pub(crate) fn get_localization(&self) -> &String { + &self.localization + } +} + #[derive(Clone, Data, Debug, Lens)] pub(crate) struct ModInfo { name: String, @@ -65,15 +87,22 @@ pub(crate) struct ModInfo { enabled: bool, #[lens(ignore)] packages: Vector, + #[lens(ignore)] + resources: ModResourceInfo, } impl ModInfo { - pub fn new(name: String, description: String, packages: Vector) -> Self { + pub fn new(cfg: ModConfig, packages: Vector) -> Self { Self { - name, - description: Arc::new(description), - packages, + name: cfg.name, + description: Arc::new(cfg.description), enabled: false, + packages, + resources: ModResourceInfo { + init: cfg.resources.init, + data: cfg.resources.data, + localization: cfg.resources.localization, + }, } } @@ -84,6 +113,14 @@ impl ModInfo { pub(crate) fn get_name(&self) -> &String { &self.name } + + pub(crate) fn get_enabled(&self) -> bool { + self.enabled + } + + pub(crate) fn get_resources(&self) -> &ModResourceInfo { + &self.resources + } } impl PartialEq for ModInfo { diff --git a/crates/dtmt/src/cmd/build.rs b/crates/dtmt/src/cmd/build.rs index c2a2045..0c34a11 100644 --- a/crates/dtmt/src/cmd/build.rs +++ b/crates/dtmt/src/cmd/build.rs @@ -7,8 +7,7 @@ use color_eyre::{Help, Report}; use futures::future::try_join_all; use futures::StreamExt; use sdk::filetype::package::Package; -use sdk::{Bundle, BundleFile}; -use serde::Deserialize; +use sdk::{Bundle, BundleFile, ModConfig}; use tokio::fs::{self, File}; use tokio::io::AsyncReadExt; @@ -36,16 +35,8 @@ pub(crate) fn command_definition() -> Command { )) } -#[derive(Debug, Default, Deserialize)] -struct ProjectConfig { - #[serde(skip)] - dir: PathBuf, - name: String, - packages: Vec, -} - #[tracing::instrument] -async fn find_project_config(dir: Option) -> Result { +async fn find_project_config(dir: Option) -> Result { let (path, mut file) = if let Some(path) = dir { let file = File::open(&path.join(PROJECT_CONFIG_NAME)) .await @@ -83,7 +74,7 @@ async fn find_project_config(dir: Option) -> Result { let mut buf = String::new(); file.read_to_string(&mut buf).await?; - let mut cfg: ProjectConfig = serde_sjson::from_str(&buf)?; + let mut cfg: ModConfig = serde_sjson::from_str(&buf)?; cfg.dir = path; Ok(cfg) } @@ -210,23 +201,23 @@ pub(crate) async fn run(_ctx: sdk::Context, matches: &ArgMatches) -> Result<()> }) }); - let bundles = try_join_all(tasks).await?; + let bundles = try_join_all(tasks) + .await + .wrap_err("failed to build mod bundles")?; - let mod_file = { - let mut path = cfg.dir.join(&cfg.name); - path.set_extension("mod"); - fs::read(path).await? + let config_file = { + let path = cfg.dir.join("dtmt.cfg"); + fs::read(&path) + .await + .wrap_err_with(|| format!("failed to read mod config at {}", path.display()))? }; - let config_file = fs::read(cfg.dir.join("dtmt.cfg")).await?; - { let dest = dest.clone(); let name = cfg.name.clone(); tokio::task::spawn_blocking(move || { let mut archive = Archive::new(name); - archive.add_mod_file(mod_file); archive.add_config(config_file); for bundle in bundles { diff --git a/crates/dtmt/src/cmd/new.rs b/crates/dtmt/src/cmd/new.rs index a7a66ca..e757f49 100644 --- a/crates/dtmt/src/cmd/new.rs +++ b/crates/dtmt/src/cmd/new.rs @@ -8,13 +8,19 @@ use futures::{StreamExt, TryStreamExt}; use string_template::Template; use tokio::fs::{self, DirBuilder}; -const TEMPLATES: [(&str, &str); 6] = [ +const TEMPLATES: [(&str, &str); 5] = [ ( "dtmt.cfg", r#"name = "{{name}}" description = "An elaborate description of my cool game mod!" version = "0.1.0" +resources = { + script = "scripts/mods/{{name}}/init" + data = "scripts/mods/{{name}}/data" + localization = "scripts/mods/{{name}}/locationzation" +} + packages = [ "packages/{{name}}" ] @@ -23,21 +29,6 @@ depends = [ "dmf" ] "#, - ), - ( - "{{name}}.mod", - r#"return { - run = function() - fassert(rawget(_G, "new_mod"), "`{{title}}` encountered an error loading the Darktide Mod Framework.") - - new_mod("{{name}}", { - mod_script = "scripts/mods/{{name}}/{{name}}", - mod_data = "scripts/mods/{{name}}/{{name}}_data", - mod_localization = "scripts/mods/{{name}}/{{name}}_localization", - }) - end, - packages = {}, -}"#, ), ( "packages/{{name}}.package", @@ -47,7 +38,7 @@ depends = [ "#, ), ( - "scripts/mods/{{name}}/{{name}}.lua", + "scripts/mods/{{name}}/init.lua", r#"local mod = get_mod("{{name}}") -- Your mod code goes here. @@ -55,7 +46,7 @@ depends = [ "#, ), ( - "scripts/mods/{{name}}/{{name}}_data.lua", + "scripts/mods/{{name}}/data.lua", r#"local mod = get_mod("{{name}}") return { @@ -65,7 +56,7 @@ return { }"#, ), ( - "scripts/mods/{{name}}/{{name}}_localization.lua", + "scripts/mods/{{name}}/localization.lua", r#"return { mod_description = { en = "An elaborate description of my cool game mod!", @@ -127,8 +118,7 @@ pub(crate) async fn run(_ctx: sdk::Context, matches: &ArgMatches) -> Result<()> promptly::prompt_default("The mod identifier name", default)? }; - tracing::debug!(root = %root.display()); - tracing::debug!(title, name); + tracing::debug!(root = %root.display(), title, name); let mut data = HashMap::new(); data.insert("name", name.as_str()); diff --git a/crates/dtmt/src/mods/archive.rs b/crates/dtmt/src/mods/archive.rs index 683314e..9f9eaa1 100644 --- a/crates/dtmt/src/mods/archive.rs +++ b/crates/dtmt/src/mods/archive.rs @@ -12,7 +12,6 @@ use zip::ZipWriter; pub struct Archive { name: String, bundles: Vec, - mod_file: Option>, config_file: Option>, } @@ -21,7 +20,6 @@ impl Archive { Self { name, bundles: Vec::new(), - mod_file: None, config_file: None, } } @@ -30,10 +28,6 @@ impl Archive { self.bundles.push(bundle) } - pub fn add_mod_file(&mut self, content: Vec) { - self.mod_file = Some(content); - } - pub fn add_config(&mut self, content: Vec) { self.config_file = Some(content); } @@ -42,11 +36,6 @@ impl Archive { where P: AsRef, { - let mod_file = self - .mod_file - .as_ref() - .ok_or_else(|| eyre::eyre!("Mod file is missing in mod archive"))?; - let config_file = self .config_file .as_ref() @@ -64,13 +53,6 @@ impl Archive { let base_path = PathBuf::from(&self.name); - { - let mut name = base_path.join(&self.name); - name.set_extension("mod"); - zip.start_file(name.to_string_lossy(), Default::default())?; - zip.write_all(mod_file)?; - } - { let name = base_path.join("dtmt.cfg"); zip.start_file(name.to_string_lossy(), Default::default())?; diff --git a/lib/sdk/src/lib.rs b/lib/sdk/src/lib.rs index e229e28..1ce68d6 100644 --- a/lib/sdk/src/lib.rs +++ b/lib/sdk/src/lib.rs @@ -9,3 +9,23 @@ pub use bundle::database::BundleDatabase; pub use bundle::decompress; pub use bundle::{Bundle, BundleFile, BundleFileType, BundleFileVariant}; pub use context::Context; + +#[derive(Clone, Debug, Default, serde::Deserialize)] +pub struct ModConfigResources { + pub init: String, + pub data: String, + pub localization: String, +} + +#[derive(Clone, Debug, Default, serde::Deserialize)] +pub struct ModConfig { + #[serde(skip)] + pub dir: std::path::PathBuf, + pub name: String, + pub description: String, + pub version: String, + pub packages: Vec, + pub resources: ModConfigResources, + #[serde(default)] + pub depends: Vec, +}