use std::{collections::HashMap, env, error::Error, fmt::Debug, fs, path::{Path, PathBuf}, time::Instant};
use aho_corasick::AhoCorasick;
use base64::Engine;
use serde_json::Value;
use crate::gdobj::GDObjProperty;
pub fn get_local_levels_path() -> Result<PathBuf, Box<dyn Error>> {
if let Ok(local_appdata) = env::var("LOCALAPPDATA") && Path::new(&local_appdata).exists(){
Ok(format!("{local_appdata}/GeometryDash/CCLocalLevels.dat").into())
} else {
Err("Could not find local levels file".into())
}
}
pub fn dbg_write<T: Into<String>>(val: T) {
fs::write(".debug", val.into()).unwrap();
}
pub struct Benchmark {
inst: Instant,
desc: String
}
impl Benchmark {
pub fn start<T: Into<String>>(desc: T) -> Self {
let start = Instant::now();
Benchmark { inst: start, desc: desc.into() }
}
pub fn stop(&mut self) {
let elapsed = self.inst.elapsed();
println!("{} benchmark: {:.3}ms", self.desc, elapsed.as_micros() as f64 / 1000.0)
}
}
#[macro_export]
macro_rules! timer {
($tok:expr) => {
Benchmark::start($tok)
};
}
pub fn vec_as_str(v: &Vec<u8>) -> String {
String::from_utf8(v.to_owned()).unwrap()
}
pub fn properties_from_json(vals: Value) -> HashMap<GDObjProperty, Value> {
vals.as_object().unwrap().into_iter()
.map(|(k, v)| (GDObjProperty::from_name(k.clone()), v.clone())).collect()
}
pub fn proper_plist_tags(s: String) -> String {
let find = &[
"<k>", "</k>", "<i>", "</i>", "<d>", "</d>", "<d />","<t/>", "<f/>",
"<t />", "<f />", "<s>", "</s>", "<r>", "</r>"
];
let replace = &[
"<key>", "</key>", "<integer>", "</integer>", "<dict>", "</dict>", "<dict />","<true/>", "<false/>",
"<true />", "<false />", "<string>", "</string>", "<real>", "</real>"
];
let ac = AhoCorasick::new(find).unwrap();
let plist = ac.replace_all(&s, replace);
return plist
}
pub fn clamp_to_values(val: f64, clamps: &[f64]) -> f64 {
clamps.iter().min_by(|&&a, &&b| {
let dist_a = (a - val).abs();
let dist_b = (b - val).abs();
dist_a.partial_cmp(&dist_b).unwrap()
}).unwrap().clone()
}
pub fn b64_decode<T: AsRef<[u8]> + Debug>(encoded: T) -> Vec<u8> {
base64::engine::general_purpose::URL_SAFE.decode(encoded).unwrap()
}
pub fn b64_encode(encoded: Vec<u8>) -> String {
base64::engine::general_purpose::URL_SAFE.encode(encoded)
}