Darktide Mod Manager #39
6 changed files with 91 additions and 15 deletions
7
Cargo.lock
generated
7
Cargo.lock
generated
|
@ -702,6 +702,7 @@ dependencies = [
|
||||||
"libloading",
|
"libloading",
|
||||||
"nanorand",
|
"nanorand",
|
||||||
"oodle-sys",
|
"oodle-sys",
|
||||||
|
"path-clean",
|
||||||
"pin-project-lite",
|
"pin-project-lite",
|
||||||
"promptly",
|
"promptly",
|
||||||
"sdk",
|
"sdk",
|
||||||
|
@ -1698,6 +1699,12 @@ dependencies = [
|
||||||
"subtle",
|
"subtle",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "path-clean"
|
||||||
|
version = "1.0.1"
|
||||||
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
|
checksum = "17359afc20d7ab31fdb42bb844c8b3bb1dabd7dcf7e68428492da7f16966fcef"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "pbkdf2"
|
name = "pbkdf2"
|
||||||
version = "0.11.0"
|
version = "0.11.0"
|
||||||
|
|
|
@ -163,22 +163,22 @@ fn build_mod_data_lua(state: Arc<State>) -> String {
|
||||||
lua.push_str(" new_mod(\"");
|
lua.push_str(" new_mod(\"");
|
||||||
lua.push_str(mod_info.get_id());
|
lua.push_str(mod_info.get_id());
|
||||||
lua.push_str("\", {\n init = \"");
|
lua.push_str("\", {\n init = \"");
|
||||||
lua.push_str(resources.get_init());
|
lua.push_str(&resources.get_init().to_string_lossy());
|
||||||
|
|
||||||
if let Some(data) = resources.get_data() {
|
if let Some(data) = resources.get_data() {
|
||||||
lua.push_str("\",\n data = \"");
|
lua.push_str("\",\n data = \"");
|
||||||
lua.push_str(data);
|
lua.push_str(&data.to_string_lossy());
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(localization) = resources.get_localization() {
|
if let Some(localization) = resources.get_localization() {
|
||||||
lua.push_str("\",\n localization = \"");
|
lua.push_str("\",\n localization = \"");
|
||||||
lua.push_str(localization);
|
lua.push_str(&localization.to_string_lossy());
|
||||||
}
|
}
|
||||||
|
|
||||||
lua.push_str("\",\n })\n");
|
lua.push_str("\",\n })\n");
|
||||||
} else {
|
} else {
|
||||||
lua.push_str(" return dofile(\"");
|
lua.push_str(" return dofile(\"");
|
||||||
lua.push_str(resources.get_init());
|
lua.push_str(&resources.get_init().to_string_lossy());
|
||||||
lua.push_str("\")");
|
lua.push_str("\")");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -61,23 +61,23 @@ impl PackageInfo {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Data, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub(crate) struct ModResourceInfo {
|
pub(crate) struct ModResourceInfo {
|
||||||
init: String,
|
init: PathBuf,
|
||||||
data: Option<String>,
|
data: Option<PathBuf>,
|
||||||
localization: Option<String>,
|
localization: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ModResourceInfo {
|
impl ModResourceInfo {
|
||||||
pub(crate) fn get_init(&self) -> &String {
|
pub(crate) fn get_init(&self) -> &PathBuf {
|
||||||
&self.init
|
&self.init
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_data(&self) -> Option<&String> {
|
pub(crate) fn get_data(&self) -> Option<&PathBuf> {
|
||||||
self.data.as_ref()
|
self.data.as_ref()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn get_localization(&self) -> Option<&String> {
|
pub(crate) fn get_localization(&self) -> Option<&PathBuf> {
|
||||||
self.localization.as_ref()
|
self.localization.as_ref()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -89,8 +89,10 @@ pub(crate) struct ModInfo {
|
||||||
description: Arc<String>,
|
description: Arc<String>,
|
||||||
enabled: bool,
|
enabled: bool,
|
||||||
#[lens(ignore)]
|
#[lens(ignore)]
|
||||||
|
#[data(ignore)]
|
||||||
packages: Vector<PackageInfo>,
|
packages: Vector<PackageInfo>,
|
||||||
#[lens(ignore)]
|
#[lens(ignore)]
|
||||||
|
#[data(ignore)]
|
||||||
resources: ModResourceInfo,
|
resources: ModResourceInfo,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -28,6 +28,7 @@ tracing-error = "0.2.0"
|
||||||
tracing-subscriber = { version = "0.3.16", features = ["env-filter"] }
|
tracing-subscriber = { version = "0.3.16", features = ["env-filter"] }
|
||||||
tracing = { version = "0.1.37", features = ["async-await"] }
|
tracing = { version = "0.1.37", features = ["async-await"] }
|
||||||
zip = "0.6.3"
|
zip = "0.6.3"
|
||||||
|
path-clean = "1.0.1"
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tempfile = "3.3.0"
|
tempfile = "3.3.0"
|
||||||
|
|
|
@ -164,6 +164,23 @@ where
|
||||||
.wrap_err("failed to build bundle")
|
.wrap_err("failed to build bundle")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn normalize_file_path<P: AsRef<Path>>(path: P) -> Result<PathBuf> {
|
||||||
|
let path = path.as_ref();
|
||||||
|
|
||||||
|
if path.is_absolute() || path.has_root() {
|
||||||
|
let err = eyre::eyre!("path is absolute: {}", path.display());
|
||||||
|
return Err(err).with_suggestion(|| "Specify a relative file path.".to_string());
|
||||||
|
}
|
||||||
|
|
||||||
|
let path = path_clean::clean(path);
|
||||||
|
|
||||||
|
if path.starts_with("..") {
|
||||||
|
eyre::bail!("path starts with a parent component: {}", path.display());
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(path)
|
||||||
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip_all)]
|
#[tracing::instrument(skip_all)]
|
||||||
pub(crate) async fn run(_ctx: sdk::Context, matches: &ArgMatches) -> Result<()> {
|
pub(crate) async fn run(_ctx: sdk::Context, matches: &ArgMatches) -> Result<()> {
|
||||||
unsafe {
|
unsafe {
|
||||||
|
@ -172,7 +189,54 @@ pub(crate) async fn run(_ctx: sdk::Context, matches: &ArgMatches) -> Result<()>
|
||||||
|
|
||||||
let cfg = {
|
let cfg = {
|
||||||
let dir = matches.get_one::<PathBuf>("directory").cloned();
|
let dir = matches.get_one::<PathBuf>("directory").cloned();
|
||||||
find_project_config(dir).await?
|
let mut cfg = find_project_config(dir).await?;
|
||||||
|
|
||||||
|
cfg.resources.init = normalize_file_path(cfg.resources.init)
|
||||||
|
.wrap_err("invalid config field 'resources.init'")
|
||||||
|
.with_suggestion(|| {
|
||||||
|
"Specify a file path relative to and child path of the \
|
||||||
|
directory where 'dtmt.cfg' is."
|
||||||
|
.to_string()
|
||||||
|
})
|
||||||
|
.with_suggestion(|| {
|
||||||
|
"Use 'dtmt new' in a separate directory to generate \
|
||||||
|
a valid mod template."
|
||||||
|
.to_string()
|
||||||
|
})?;
|
||||||
|
|
||||||
|
if let Some(path) = cfg.resources.data {
|
||||||
|
let path = normalize_file_path(path)
|
||||||
|
.wrap_err("invalid config field 'resources.data'")
|
||||||
|
.with_suggestion(|| {
|
||||||
|
"Specify a file path relative to and child path of the \
|
||||||
|
directory where 'dtmt.cfg' is."
|
||||||
|
.to_string()
|
||||||
|
})
|
||||||
|
.with_suggestion(|| {
|
||||||
|
"Use 'dtmt new' in a separate directory to generate \
|
||||||
|
a valid mod template."
|
||||||
|
.to_string()
|
||||||
|
})?;
|
||||||
|
cfg.resources.data = Some(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
if let Some(path) = cfg.resources.localization {
|
||||||
|
let path = normalize_file_path(path)
|
||||||
|
.wrap_err("invalid config field 'resources.localization'")
|
||||||
|
.with_suggestion(|| {
|
||||||
|
"Specify a file path relative to and child path of the \
|
||||||
|
directory where 'dtmt.cfg' is."
|
||||||
|
.to_string()
|
||||||
|
})
|
||||||
|
.with_suggestion(|| {
|
||||||
|
"Use 'dtmt new' in a separate directory to generate \
|
||||||
|
a valid mod template."
|
||||||
|
.to_string()
|
||||||
|
})?;
|
||||||
|
cfg.resources.localization = Some(path);
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg
|
||||||
};
|
};
|
||||||
|
|
||||||
let dest = {
|
let dest = {
|
||||||
|
|
|
@ -1,14 +1,16 @@
|
||||||
mod log;
|
mod log;
|
||||||
|
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
pub use log::*;
|
pub use log::*;
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, serde::Deserialize)]
|
#[derive(Clone, Debug, Default, serde::Deserialize)]
|
||||||
pub struct ModConfigResources {
|
pub struct ModConfigResources {
|
||||||
pub init: String,
|
pub init: PathBuf,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub data: Option<String>,
|
pub data: Option<PathBuf>,
|
||||||
#[serde(default)]
|
#[serde(default)]
|
||||||
pub localization: Option<String>,
|
pub localization: Option<PathBuf>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, Default, serde::Deserialize)]
|
#[derive(Clone, Debug, Default, serde::Deserialize)]
|
||||||
|
|
Loading…
Add table
Reference in a new issue