use std::path::PathBuf;
use serde::{Deserialize, Serialize};
use serde_aux::prelude::*;
use self::{
anim::{InkAnimSequence, Target},
widget::SiblingOrNested,
};
mod conversion;
use conversion::deserialize_lockey_from_anything;
pub mod anim;
pub mod widget;
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct Name {
#[serde(rename = "$type")]
r#type: String,
#[serde(rename = "$storage")]
storage: String,
#[serde(rename = "$value")]
value: String,
}
impl Name {
pub fn as_str(&self) -> &str {
self.value.as_str()
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "lowercase")]
pub enum Storage {
String,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ResourcePath {
#[serde(rename = "$storage")]
storage: Storage,
#[serde(rename = "$value")]
value: PathBuf,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(tag = "$type")]
pub enum DepotPath {
ResourcePath(ResourcePath),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct Data<T> {
pub version: usize,
pub build_version: usize,
pub root_chunk: T,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct Header {
wolven_kit_version: String,
w_kit_json_version: String,
game_version: usize,
exported_date_time: chrono::DateTime<chrono::Utc>,
data_type: String,
archive_file_name: PathBuf,
}
impl std::fmt::Display for Header {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(
f,
"🗃️ {}\n🐺 {} ({})",
self.archive_file_name.display(),
self.wolven_kit_version,
self.w_kit_json_version,
)
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct File<T> {
pub header: Header,
pub data: Data<T>,
}
impl<T> File<T> {
pub fn resource(self) -> T {
self.data.root_chunk
}
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, PartialOrd)]
#[serde(tag = "$type")]
#[serde(rename_all = "PascalCase")]
pub struct Vector2 {
pub x: f32,
pub y: f32,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, PartialOrd)]
#[serde(tag = "$type")]
#[serde(rename_all = "PascalCase")]
pub struct HDRColor {
pub alpha: f32,
pub blue: f32,
pub green: f32,
pub red: f32,
}
#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
#[serde(transparent)]
pub struct HandleId(#[serde(deserialize_with = "deserialize_number_from_string")] u32);
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(rename_all = "PascalCase")]
pub struct InkWrapper<T> {
pub handle_id: HandleId,
pub data: T,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct CName(String);
#[derive(Debug, Clone, Serialize, Deserialize)]
pub enum LocKey {
ID(u32),
Value(String),
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct LocalizationString {
#[serde(deserialize_with = "deserialize_lockey_from_anything")]
value: Option<LocKey>,
}
impl<T> std::fmt::Display for InkWrapper<T>
where
T: std::fmt::Display,
{
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "({}) {}", self.handle_id, self.data)
}
}
impl std::fmt::Display for HandleId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "🔑 {}", self.0)
}
}
#[allow(dead_code, non_snake_case)]
#[derive(Debug)]
pub struct PathSummary {
Name: Name,
HandleId: HandleId,
Index: usize,
Path: Vec<usize>,
}
impl InkAnimSequence {
pub fn get_path_indexes_matching(&self, searched: &[usize]) -> Vec<PathSummary> {
let count = searched.len();
let _last = count - 1;
let mut out = vec![];
for (target_index, target) in self.targets.iter().enumerate() {
match target {
Target::WithHandleId(handle) => {
let path = &handle.data.path;
if path.sibling_or_nested(searched) {
out.push(PathSummary {
Name: self.name.clone(),
HandleId: handle.handle_id,
Index: target_index,
Path: path.clone(),
});
}
}
_ => continue,
}
}
out
}
}