1use std::path::PathBuf;
2
3use serde::{Deserialize, Serialize};
4use serde_aux::prelude::*;
5
6use self::{
7 anim::{InkAnimSequence, Target},
8 widget::SiblingOrNested,
9};
10mod conversion;
11use conversion::deserialize_lockey_from_anything;
12
13pub mod anim;
15pub mod widget;
17
18#[derive(Debug, Clone, Serialize, Deserialize)]
19pub struct Name {
20 #[serde(rename = "$type")]
21 r#type: String,
22 #[serde(rename = "$storage")]
23 storage: String,
24 #[serde(rename = "$value")]
25 value: String,
26}
27
28impl Name {
29 pub fn as_str(&self) -> &str {
30 self.value.as_str()
31 }
32}
33
34#[derive(Debug, Clone, Serialize, Deserialize)]
35#[serde(rename_all = "lowercase")]
36pub enum Storage {
37 String,
38}
39
40#[derive(Debug, Clone, Serialize, Deserialize)]
41pub struct ResourcePath {
42 #[serde(rename = "$storage")]
43 storage: Storage,
44 #[serde(rename = "$value")]
45 value: PathBuf,
46}
47
48#[derive(Debug, Clone, Serialize, Deserialize)]
49#[serde(tag = "$type")]
50pub enum DepotPath {
51 ResourcePath(ResourcePath),
52}
53
54#[derive(Debug, Clone, Serialize, Deserialize)]
55#[serde(rename_all = "PascalCase")]
56pub struct Data<T> {
57 pub version: usize,
58 pub build_version: usize,
59 pub root_chunk: T,
60}
61
62#[derive(Debug, Clone, Serialize, Deserialize)]
63#[serde(rename_all = "PascalCase")]
64pub struct Header {
65 wolven_kit_version: String,
66 w_kit_json_version: String,
67 game_version: usize,
68 exported_date_time: chrono::DateTime<chrono::Utc>,
69 data_type: String,
70}
71
72#[derive(Debug, Clone, Serialize, Deserialize)]
73#[serde(rename_all = "PascalCase")]
74pub struct File<T> {
75 pub header: Header,
76 pub data: Data<T>,
77}
78
79#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, PartialOrd)]
81#[serde(tag = "$type")]
82#[serde(rename_all = "PascalCase")]
83pub struct Vector2 {
84 pub x: f32,
85 pub y: f32,
86}
87
88#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, PartialOrd)]
90#[serde(tag = "$type")]
91#[serde(rename_all = "PascalCase")]
92pub struct HDRColor {
93 pub alpha: f32,
94 pub blue: f32,
95 pub green: f32,
96 pub red: f32,
97}
98
99#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
101#[serde(transparent)]
102pub struct HandleId(#[serde(deserialize_with = "deserialize_number_from_string")] u32);
103
104#[derive(Debug, Clone, Serialize, Deserialize)]
106#[serde(rename_all = "PascalCase")]
107pub struct InkWrapper<T> {
108 pub handle_id: HandleId,
109 pub data: T,
110}
111
112#[derive(Debug, Clone, Serialize, Deserialize)]
114pub struct CName(String);
115
116#[derive(Debug, Clone, Serialize, Deserialize)]
117pub enum LocKey {
118 ID(u32),
119 Value(String),
120}
121
122#[derive(Debug, Clone, Serialize, Deserialize)]
124pub struct LocalizationString {
125 #[serde(deserialize_with = "deserialize_lockey_from_anything")]
126 value: Option<LocKey>,
127}
128
129impl<T> std::fmt::Display for InkWrapper<T>
130where
131 T: std::fmt::Display,
132{
133 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
134 write!(f, "({}) {}", self.handle_id, self.data)
135 }
136}
137
138impl std::fmt::Display for HandleId {
139 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
140 write!(f, "🔑 {}", self.0)
141 }
142}
143
144#[allow(dead_code, non_snake_case)]
146#[derive(Debug)]
147pub struct PathSummary {
148 Name: Name,
150 HandleId: HandleId,
152 Index: usize,
154 Path: Vec<usize>,
156}
157
158impl InkAnimSequence {
159 pub fn get_path_indexes_matching(&self, searched: &[usize]) -> Vec<PathSummary> {
161 let count = searched.len();
162 let _last = count - 1;
163 let mut out = vec![];
164 for (target_index, target) in self.targets.iter().enumerate() {
165 match target {
166 Target::WithHandleId(handle) => {
167 let path = &handle.data.path;
168 if path.sibling_or_nested(searched) {
169 out.push(PathSummary {
170 Name: self.name.clone(),
171 HandleId: handle.handle_id,
172 Index: target_index,
173 Path: path.clone(),
174 });
175 }
176 }
177 _ => continue,
178 }
179 }
180 out
181 }
182}