You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
Nothing/src-tauri/src/plan.rs

166 lines
4.3 KiB

use std::{collections::HashMap, path::PathBuf};
use serde::{ser::SerializeStruct, Deserialize, Deserializer, Serialize};
use serde_json::Value;
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Plan {
plan: Vec<PlanElement>,
current: usize,
#[serde(flatten)]
metadata: PlanMetadata,
}
#[derive(Deserialize, Debug, Clone)]
pub struct PlanMetadata {
stored_path: Option<PathBuf>,
update_url: Option<String>,
latest_server_etag: Option<String>,
identifier: Option<String>,
#[serde(default)]
#[serde(deserialize_with = "deserialize_option_string")]
last_stored_time: Option<String>,
}
impl PlanMetadata {
pub fn set_stored_path(&mut self, file: Option<PathBuf>) {
self.stored_path = file;
}
}
impl Serialize for PlanMetadata {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
let mut state = serializer.serialize_struct("PlanMetadata", 6)?;
state.serialize_field("update_url", &self.update_url)?;
state.serialize_field("stored_path", &self.stored_path)?;
state.serialize_field("latest_server_etag", &self.latest_server_etag)?;
state.serialize_field("identifier", &self.identifier)?;
state.serialize_field("last_stored_time", &self.last_stored_time)?;
if let Some(path) = &self.stored_path {
if let Some(name) = path.file_name() {
state.serialize_field("name", &name.to_str())?;
}
}
state.end()
}
}
// Custom deserializer that accepts both strings and legacy number for the stored_time field
fn deserialize_option_string<'de, D>(deserializer: D) -> Result<Option<String>, D::Error>
where
D: Deserializer<'de>,
{
let v: Option<Value> = Option::deserialize(deserializer)?;
Ok(match v {
Some(Value::String(s)) => Some(s),
Some(Value::Number(n)) => Some(n.to_string()),
_ => None,
})
}
impl From<PlanMetadata> for Option<Plan> {
fn from(metadata: PlanMetadata) -> Self {
Some(serde_json::from_slice(&std::fs::read(metadata.stored_path?).ok()?).ok()?)
}
}
impl Plan {
pub fn set_stored_path(&mut self, file: Option<PathBuf>) {
self.metadata.stored_path = file;
}
}
#[derive(Debug, Deserialize, Serialize, Clone)]
pub struct PlanElement {
area_key: String,
notes: String,
#[serde(default = "PlanElement::generate_uuid")]
uuid: uuid::Uuid,
#[serde(default = "PlanElement::edited")]
edited: bool,
anchor_act: Option<u8>,
#[serde(default, skip_serializing_if = "is_false")]
checkpoint: bool,
}
fn is_false(flag: &bool) -> bool {
!flag
}
impl PlanElement {
pub fn generate_uuid() -> uuid::Uuid {
uuid::Uuid::new_v4()
}
pub fn edited() -> bool {
false
}
}
#[allow(dead_code)]
#[derive(Debug, Deserialize)]
struct OldPlanElement {
area: OldArea,
note: String,
}
#[allow(dead_code)]
#[derive(Debug, Deserialize)]
struct OldPlan {
elements: Vec<OldPlanElement>,
position: usize,
}
#[derive(Debug, Deserialize)]
struct OldArea {
_rid: usize,
}
#[allow(dead_code)]
pub fn convert_old(path: PathBuf) -> Option<Plan> {
let plan: OldPlan =
serde_json::from_str(&std::fs::read_to_string(path).expect("Could not convert old"))
.expect("could not convert old");
let map = poe_data::world_area::load_world_areas_map(include_str!(
"../../data/processed_world_areas.json"
));
let map = map
.iter()
.map(|(k, v)| (v.key_id, k))
.collect::<HashMap<usize, &String>>();
Some(Plan {
current: plan.position,
plan: plan
.elements
.into_iter()
.map(|plan_element| PlanElement {
area_key: map[&plan_element.area._rid].to_owned(),
notes: plan_element.note,
uuid: PlanElement::generate_uuid(),
edited: PlanElement::edited(),
anchor_act: None,
checkpoint: false,
})
.collect::<Vec<PlanElement>>(),
metadata: PlanMetadata {
stored_path: None,
update_url: None,
latest_server_etag: None,
identifier: None,
last_stored_time: None,
},
})
}