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.
166 lines
4.3 KiB
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,
|
|
},
|
|
})
|
|
}
|