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 archive_file_name: PathBuf,
71}
72
73impl std::fmt::Display for Header {
74 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
75 write!(
76 f,
77 "šļø {}\nšŗ {} ({})",
78 self.archive_file_name.display(),
79 self.wolven_kit_version,
80 self.w_kit_json_version,
81 )
82 }
83}
84
85#[derive(Debug, Clone, Serialize, Deserialize)]
86#[serde(rename_all = "PascalCase")]
87pub struct File<T> {
88 pub header: Header,
89 pub data: Data<T>,
90}
91
92impl<T> File<T> {
93 pub fn resource(self) -> T {
94 self.data.root_chunk
95 }
96}
97
98#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, PartialOrd)]
100#[serde(tag = "$type")]
101#[serde(rename_all = "PascalCase")]
102pub struct Vector2 {
103 pub x: f32,
104 pub y: f32,
105}
106
107#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, PartialOrd)]
109#[serde(tag = "$type")]
110#[serde(rename_all = "PascalCase")]
111pub struct HDRColor {
112 pub alpha: f32,
113 pub blue: f32,
114 pub green: f32,
115 pub red: f32,
116}
117
118#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
122#[serde(transparent)]
123pub struct HandleId(#[serde(deserialize_with = "deserialize_number_from_string")] u32);
124
125#[derive(Debug, Clone, Serialize, Deserialize)]
127#[serde(rename_all = "PascalCase")]
128pub struct InkWrapper<T> {
129 pub handle_id: HandleId,
130 pub data: T,
131}
132
133#[derive(Debug, Clone, Serialize, Deserialize)]
135pub struct CName(String);
136
137#[derive(Debug, Clone, Serialize, Deserialize)]
138pub enum LocKey {
139 ID(u32),
140 Value(String),
141}
142
143#[derive(Debug, Clone, Serialize, Deserialize)]
145pub struct LocalizationString {
146 #[serde(deserialize_with = "deserialize_lockey_from_anything")]
147 value: Option<LocKey>,
148}
149
150impl<T> std::fmt::Display for InkWrapper<T>
151where
152 T: std::fmt::Display,
153{
154 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
155 write!(f, "({}) {}", self.handle_id, self.data)
156 }
157}
158
159impl std::fmt::Display for HandleId {
160 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
161 write!(f, "š {}", self.0)
162 }
163}
164
165#[allow(dead_code, non_snake_case)]
167#[derive(Debug)]
168pub struct PathSummary {
169 Name: Name,
171 HandleId: HandleId,
173 Index: usize,
175 Path: Vec<usize>,
177}
178
179impl InkAnimSequence {
180 pub fn get_path_indexes_matching(&self, searched: &[usize]) -> Vec<PathSummary> {
182 let count = searched.len();
183 let _last = count - 1;
184 let mut out = vec![];
185 for (target_index, target) in self.targets.iter().enumerate() {
186 match target {
187 Target::WithHandleId(handle) => {
188 let path = &handle.data.path;
189 if path.sibling_or_nested(searched) {
190 out.push(PathSummary {
191 Name: self.name.clone(),
192 HandleId: handle.handle_id,
193 Index: target_index,
194 Path: path.clone(),
195 });
196 }
197 }
198 _ => continue,
199 }
200 }
201 out
202 }
203}