1use std::path::PathBuf;
2
3use serde::{Deserialize, Serialize, ser::SerializeStruct};
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, Default, Clone, Deserialize, PartialEq)]
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 Serialize for Name {
29 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
30 where
31 S: serde::Serializer,
32 {
33 serializer.serialize_str(&self.value)
34 }
35}
36
37impl Name {
38 pub fn as_str(&self) -> &str {
39 self.value.as_str()
40 }
41}
42
43#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
44#[serde(rename_all = "lowercase")]
45pub enum Storage {
46 #[default]
47 String,
48}
49
50#[derive(Debug, Default, Clone, Serialize, Deserialize, PartialEq)]
51pub struct ResourcePath {
52 #[serde(rename = "$storage")]
53 storage: Storage,
54 #[serde(rename = "$value")]
55 value: PathBuf,
56}
57
58#[derive(Debug, Clone, Deserialize, PartialEq)]
59#[serde(tag = "$type")]
60pub enum DepotPath {
61 ResourcePath(ResourcePath),
62}
63
64impl Serialize for DepotPath {
65 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
66 where
67 S: serde::Serializer,
68 {
69 match self {
70 Self::ResourcePath(x) => {
71 serializer.serialize_str(x.value.as_path().as_os_str().to_str().unwrap_or_default())
72 }
73 }
74 }
75}
76
77impl Default for DepotPath {
78 fn default() -> Self {
79 Self::ResourcePath(ResourcePath::default())
80 }
81}
82
83#[derive(Debug, Clone, Serialize, Deserialize)]
84#[serde(rename_all = "PascalCase")]
85pub struct Data<T> {
86 pub version: usize,
87 pub build_version: usize,
88 pub root_chunk: T,
89}
90
91#[derive(Debug, Clone, Serialize, Deserialize)]
92#[serde(rename_all = "PascalCase")]
93pub struct Header {
94 wolven_kit_version: String,
95 w_kit_json_version: String,
96 game_version: usize,
97 exported_date_time: chrono::DateTime<chrono::Utc>,
98 data_type: String,
99 archive_file_name: PathBuf,
100}
101
102impl std::fmt::Display for Header {
103 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
104 write!(
105 f,
106 "šļø {}\nšŗ {} ({})",
107 self.archive_file_name.display(),
108 self.wolven_kit_version,
109 self.w_kit_json_version,
110 )
111 }
112}
113
114#[derive(Debug, Clone, Serialize, Deserialize)]
115#[serde(rename_all = "PascalCase")]
116pub struct File<T> {
117 pub header: Header,
118 pub data: Data<T>,
119}
120
121impl<T> File<T> {
122 pub fn resource(self) -> T {
123 self.data.root_chunk
124 }
125}
126
127#[derive(Debug, Default, Clone, Deserialize, PartialEq, PartialOrd)]
129#[serde(tag = "$type")]
130#[serde(rename_all = "PascalCase")]
131pub struct Vector2 {
132 pub x: f32,
133 pub y: f32,
134}
135
136impl Serialize for Vector2 {
137 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
138 where
139 S: serde::Serializer,
140 {
141 let mut s = serializer.serialize_struct("Vector2", 2)?;
142 s.serialize_field("X", &self.x)?;
143 s.serialize_field("Y", &self.y)?;
144 s.end()
145 }
146}
147
148#[derive(Debug, Default, Clone, Deserialize, PartialEq, PartialOrd)]
150#[serde(tag = "$type")]
151#[serde(rename_all = "PascalCase")]
152pub struct HDRColor {
153 pub alpha: f32,
154 pub blue: f32,
155 pub green: f32,
156 pub red: f32,
157}
158
159impl Serialize for HDRColor {
160 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
161 where
162 S: serde::Serializer,
163 {
164 let mut s = serializer.serialize_struct("HDRColor", 4)?;
165 s.serialize_field("alpha", &self.alpha)?;
166 s.serialize_field("blue", &self.blue)?;
167 s.serialize_field("green", &self.green)?;
168 s.serialize_field("red", &self.red)?;
169 s.end()
170 }
171}
172
173#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize, PartialEq)]
177#[serde(transparent)]
178pub struct HandleId(#[serde(deserialize_with = "deserialize_number_from_string")] u32);
179
180#[derive(Debug, Clone, Deserialize)]
182#[serde(rename_all = "PascalCase")]
183pub struct InkWrapper<T> {
184 pub handle_id: HandleId,
185 pub data: T,
186}
187
188impl<T> Serialize for InkWrapper<T>
189where
190 T: Serialize,
191{
192 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
193 where
194 S: serde::Serializer,
195 {
196 self.data.serialize(serializer)
197 }
198}
199
200impl<T> Default for InkWrapper<T>
201where
202 T: Default,
203{
204 fn default() -> Self {
205 Self {
206 handle_id: Default::default(),
207 data: Default::default(),
208 }
209 }
210}
211
212impl<T> PartialEq for InkWrapper<T>
213where
214 T: PartialEq<T>,
215{
216 fn eq(&self, other: &Self) -> bool {
217 self.handle_id == other.handle_id && self.data == other.data
218 }
219}
220
221#[derive(Debug, Clone, Serialize, Deserialize)]
223pub struct CName(String);
224
225#[derive(Debug, Clone, Deserialize)]
226pub enum LocKey {
227 ID(u32),
228 Value(String),
229}
230
231impl Default for LocKey {
232 fn default() -> Self {
233 LocKey::ID(0)
234 }
235}
236
237impl Serialize for LocKey {
238 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
239 where
240 S: serde::Serializer,
241 {
242 match self {
243 Self::ID(x) => serializer.serialize_u32(*x),
244 Self::Value(x) => serializer.serialize_str(x.as_str()),
245 }
246 }
247}
248
249impl PartialEq for LocKey {
250 fn eq(&self, other: &Self) -> bool {
251 match (self, other) {
252 (Self::ID(lhs), Self::ID(rhs)) => lhs == rhs,
253 (Self::Value(lhs), Self::Value(rhs)) => lhs == rhs,
254 (Self::ID(lhs), Self::Value(rhs)) => &lhs.to_string() == rhs,
255 (Self::Value(lhs), Self::ID(rhs)) => lhs == &rhs.to_string(),
256 }
257 }
258}
259
260#[derive(Debug, Clone, Deserialize, PartialEq, Default)]
262pub struct LocalizationString {
263 #[serde(deserialize_with = "deserialize_lockey_from_anything")]
264 value: Option<LocKey>,
265}
266
267impl Serialize for LocalizationString {
268 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
269 where
270 S: serde::Serializer,
271 {
272 match &self.value {
273 Some(x)
274 if *x != LocKey::default()
275 && *x != LocKey::Value("".into())
276 && *x != LocKey::ID(0) =>
277 {
278 serializer.serialize_some(x)
279 }
280 _ => serializer.serialize_none(),
281 }
282 }
283}
284
285pub fn is_any_default_localization_string(
286 LocalizationString { value }: &LocalizationString,
287) -> bool {
288 match value {
289 None => true,
290 Some(LocKey::ID(0)) => true,
291 Some(LocKey::Value(x)) if x.is_empty() => true,
292 _ => false,
293 }
294}
295
296impl<T> std::fmt::Display for InkWrapper<T>
297where
298 T: std::fmt::Display,
299{
300 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
301 write!(f, "({}) {}", self.handle_id, self.data)
302 }
303}
304
305impl std::fmt::Display for HandleId {
306 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
307 write!(f, "š {}", self.0)
308 }
309}
310
311#[allow(dead_code, non_snake_case)]
313#[derive(Debug)]
314pub struct PathSummary {
315 Name: Name,
317 HandleId: HandleId,
319 Index: usize,
321 Path: Vec<usize>,
323}
324
325impl InkAnimSequence {
326 pub fn get_path_indexes_matching(&self, searched: &[usize]) -> Vec<PathSummary> {
328 let count = searched.len();
329 let _last = count - 1;
330 let mut out = vec![];
331 for (target_index, target) in self.targets.iter().enumerate() {
332 match target {
333 Target::WithHandleId(handle) => {
334 let path = &handle.data.path;
335 if path.sibling_or_nested(searched) {
336 out.push(PathSummary {
337 Name: self.name.clone(),
338 HandleId: handle.handle_id,
339 Index: target_index,
340 Path: path.clone(),
341 });
342 }
343 }
344 _ => continue,
345 }
346 }
347 out
348 }
349}