use std::path::PathBuf;
use serde::{Deserialize, Serialize};
use serde_json::{Map, Value};
use typeshare::typeshare;
use crate::{search::Searchable, validate::ModValidationError};
#[typeshare]
#[derive(Debug, Clone, Serialize)]
#[serde(rename_all = "camelCase")]
pub struct LocalMod {
pub enabled: bool,
pub errors: Vec<ModValidationError>,
pub mod_path: String,
pub manifest: ModManifest,
}
#[typeshare]
#[derive(Debug, Serialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct FailedMod {
pub error: ModValidationError,
pub mod_path: String,
pub display_path: String,
}
#[typeshare]
#[derive(Debug, Serialize, Clone)]
#[serde(tag = "loadState", content = "mod", rename_all = "camelCase")]
pub enum UnsafeLocalMod {
Valid(Box<LocalMod>),
Invalid(FailedMod),
}
impl UnsafeLocalMod {
pub fn get_errs(&self) -> Vec<&ModValidationError> {
match self {
Self::Invalid(m) => {
vec![&m.error]
}
Self::Valid(m) => {
if m.enabled {
m.errors.iter().collect()
} else {
vec![]
}
}
}
}
pub fn get_unique_name(&self) -> &String {
match self {
Self::Invalid(m) => &m.mod_path,
Self::Valid(m) => &m.manifest.unique_name,
}
}
pub fn get_name(&self) -> &String {
match self {
Self::Invalid(m) => &m.display_path,
Self::Valid(m) => &m.manifest.name,
}
}
pub fn get_enabled(&self) -> bool {
match self {
Self::Invalid(_) => false,
Self::Valid(m) => m.enabled,
}
}
pub fn get_path(&self) -> &str {
match self {
Self::Invalid(m) => &m.mod_path,
Self::Valid(m) => &m.mod_path,
}
}
}
impl Searchable for UnsafeLocalMod {
fn get_values(&self) -> Vec<String> {
match self {
UnsafeLocalMod::Invalid(m) => vec![m.display_path.clone()],
UnsafeLocalMod::Valid(m) => vec![
m.manifest.name.clone(),
m.manifest.unique_name.clone(),
m.manifest.author.clone(),
],
}
}
}
#[cfg(test)]
impl LocalMod {
pub fn get_test(num: u8) -> Self {
let txt =
include_str!("../../test_files/test_local_mod.json").replace("$num$", &num.to_string());
let manifest: ModManifest = serde_json::from_str(&txt).unwrap();
Self {
manifest,
mod_path: "".to_string(),
enabled: true,
errors: vec![],
}
}
}
pub fn get_paths_to_preserve(local_mod: Option<&LocalMod>) -> Vec<PathBuf> {
if let Some(local_mod) = local_mod {
let mut paths: Vec<PathBuf> =
vec![PathBuf::from("config.json"), PathBuf::from("save.json")];
if let Some(raw_paths) = local_mod.manifest.paths_to_preserve.to_owned() {
for path in raw_paths.iter() {
paths.push(PathBuf::from(path));
}
}
return paths;
}
vec![PathBuf::from("config.json")] }
#[typeshare]
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct ModManifest {
pub unique_name: String,
pub name: String,
pub author: String,
pub version: String,
#[serde(skip_serializing_if = "Option::is_none")]
pub filename: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub owml_version: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub dependencies: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub conflicts: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub paths_to_preserve: Option<Vec<String>>,
#[serde(skip_serializing_if = "Option::is_none")]
pub warning: Option<ModWarning>,
#[serde(skip_serializing_if = "Option::is_none")]
pub patcher: Option<String>,
#[deprecated(since = "0.12.1", note = "please use `donate_links` instead")]
#[serde(skip_serializing_if = "Option::is_none")]
pub donate_link: Option<String>,
#[serde(skip_serializing_if = "Option::is_none")]
pub donate_links: Option<Vec<String>>,
}
impl ModManifest {
#[allow(deprecated)]
pub fn migrate_donation_link(&mut self) {
if let Some(link) = self.donate_link.to_owned() {
if let Some(links) = self.donate_links.as_mut() {
links.push(link);
} else {
self.donate_links = Some(vec![link]);
}
}
}
}
#[typeshare]
#[derive(Debug, Serialize, Deserialize, Clone)]
#[serde(rename_all = "camelCase")]
pub struct ModWarning {
pub title: String,
pub body: String,
}
#[derive(Debug, Serialize, Deserialize)]
pub struct ModStubConfig {
pub enabled: bool,
#[serde(skip_serializing_if = "Option::is_none")]
pub settings: Option<Map<String, Value>>,
}