inkanim_types/ink/
mod.rs

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
13/// everything related to *.inkanim*
14pub mod anim;
15/// everything related to *.inkwidget*
16pub 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/// see [NativeDB](https://nativedb.red4ext.com/Vector2)
128#[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/// see [NativeDB](https://nativedb.red4ext.com/HDRColor)
149#[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/// asset handle ID
174///
175/// identifies the index in the graph.
176#[derive(Debug, Default, Clone, Copy, Serialize, Deserialize, PartialEq)]
177#[serde(transparent)]
178pub struct HandleId(#[serde(deserialize_with = "deserialize_number_from_string")] u32);
179
180/// wrapper with handle ID
181#[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/// specific resource ID
222#[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/// specific translation ID
261#[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/// animation aggregated informations summary
312#[allow(dead_code, non_snake_case)]
313#[derive(Debug)]
314pub struct PathSummary {
315    /// animation name
316    Name: Name,
317    /// unique handle ID
318    HandleId: HandleId,
319    /// index in sequence
320    Index: usize,
321    /// path to the nested element
322    Path: Vec<usize>,
323}
324
325impl InkAnimSequence {
326    /// summarize all paths matching sequences of digits
327    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}