diff --git a/Cargo.lock b/Cargo.lock index a9de28e092..e0578b1956 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5805,6 +5805,7 @@ dependencies = [ "image", "lazy_static", "ron", + "serde", "tracing", ] diff --git a/common/assets/Cargo.toml b/common/assets/Cargo.toml index 6da6273516..84c5f21b87 100644 --- a/common/assets/Cargo.toml +++ b/common/assets/Cargo.toml @@ -6,6 +6,7 @@ description = "Crate for game loading assets for veloren." version = "0.9.0" [dependencies] +serde = {version = "1.0", features = ["derive"]} lazy_static = "1.4.0" assets_manager = {version = "0.4.2", features = ["bincode", "ron", "json", "hot-reloading"]} ron = { version = "0.6", default-features = false } diff --git a/common/assets/src/lib.rs b/common/assets/src/lib.rs index f07bb63901..85f519cb1a 100644 --- a/common/assets/src/lib.rs +++ b/common/assets/src/lib.rs @@ -254,3 +254,158 @@ impl Compound for Directory { Ok(Directory(files)) } } + +pub mod asset_tweak { + use super::{Asset, AssetExt, RonLoader}; + use serde::{de::DeserializeOwned, Deserialize}; + + #[derive(Clone, Deserialize)] + struct AssetTweakWrapper(T); + + impl Asset for AssetTweakWrapper + where + T: Clone + Sized + Send + Sync + 'static + DeserializeOwned, + { + type Loader = RonLoader; + + const EXTENSION: &'static str = "ron"; + } + + /// NOTE: Don't use it in code, it's debug only + pub fn tweak_expect(path: &str) -> T + where + T: Clone + Sized + Send + Sync + 'static + DeserializeOwned, + { + tracing::warn!("AssetTweaker used in release build!"); + let handle = as AssetExt>::load_expect(path); + let AssetTweakWrapper(value) = handle.read().clone(); + value + } +} + +#[cfg(test)] +mod tests { + use super::asset_tweak::tweak; + use std::{ + convert::AsRef, + fmt::Debug, + fs::{self, File}, + io::Write, + path::{Path, PathBuf}, + }; + + // Return path to repository by searching 10 directories back + fn find_root() -> Option { + std::env::current_dir().map_or(None, |path| { + // If we are in the root, push path + if path.join(".git").is_dir() { + return Some(path); + } + // Search .git directory in parent directries + for ancestor in path.ancestors().take(10) { + if ancestor.join(".git").is_dir() { + return Some(ancestor.to_path_buf()); + } + } + None + }) + } + + struct DirectoryGuard

+ where + P: AsRef, + { + dir: P, + } + + impl

DirectoryGuard

+ where + P: AsRef, + { + fn create(dir: P) -> Self { + fs::create_dir_all(&dir).expect("failed to create directory"); + Self { dir } + } + } + + impl

Drop for DirectoryGuard

+ where + P: AsRef, + { + fn drop(&mut self) { fs::remove_dir(&self.dir).expect("failed to remove directory"); } + } + + struct FileGuard

+ where + P: AsRef + Debug, + { + file: P, + } + + impl

FileGuard

+ where + P: AsRef + Debug, + { + fn create(file: P) -> (Self, File) { + let f = + File::create(&file).unwrap_or_else(|_| panic!("failed to create file {:?}", &file)); + (Self { file }, f) + } + } + + impl

Drop for FileGuard

+ where + P: AsRef + Debug, + { + fn drop(&mut self) { + fs::remove_file(&self.file) + .unwrap_or_else(|_| panic!("failed to create file {:?}", &self.file)); + } + } + + #[test] + fn test_tweaked_string() { + let root = find_root().expect("failed to discover repository_root"); + let tweak_dir = root.join("assets/common/tweak/"); + let _dir_guard = DirectoryGuard::create(tweak_dir.clone()); + + // define test files + let from_int = tweak_dir.clone().join("int_tweak.ron"); + let from_string = tweak_dir.clone().join("string_tweak.ron"); + let from_map = tweak_dir.clone().join("map_tweak.ron"); + + // setup fs guards + let (_file_guard1, mut file1) = FileGuard::create(from_int); + let (_file_guard2, mut file2) = FileGuard::create(from_string); + let (_file_guard3, mut file3) = FileGuard::create(from_map); + + // write to file and check result + file1.write(b"(5)").expect("failed to write to the file"); + let x = tweak::("common.tweak.int_tweak"); + assert_eq!(x, 5); + + // write to file and check result + file2 + .write(br#"("Hello Zest")"#) + .expect("failed to write to the file"); + let x = tweak::("common.tweak.string_tweak"); + assert_eq!(x, "Hello Zest".to_owned()); + + // write to file and check result + file3 + .write( + br#" + ({ + "wow": 4, + "such": 5, + }) + "#, + ) + .expect("failed to write to the file"); + let x: std::collections::HashMap = tweak("common.tweak.map_tweak"); + let mut map = std::collections::HashMap::new(); + map.insert("wow".to_owned(), 4); + map.insert("such".to_owned(), 5); + assert_eq!(x, map); + } +}