inkanim_types/ink/
mod.rs

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
13/// everything related to *.inkanim*
14pub mod anim;
15/// everything related to *.inkwidget*
16pub 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/// see [NativeDB](https://nativedb.red4ext.com/Vector2)
99#[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/// see [NativeDB](https://nativedb.red4ext.com/HDRColor)
108#[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/// asset handle ID
119///
120/// identifies the index in the graph.
121#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
122#[serde(transparent)]
123pub struct HandleId(#[serde(deserialize_with = "deserialize_number_from_string")] u32);
124
125/// wrapper with handle ID
126#[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/// specific resource ID
134#[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/// specific translation ID
144#[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/// animation aggregated informations summary
166#[allow(dead_code, non_snake_case)]
167#[derive(Debug)]
168pub struct PathSummary {
169    /// animation name
170    Name: Name,
171    /// unique handle ID
172    HandleId: HandleId,
173    /// index in sequence
174    Index: usize,
175    /// path to the nested element
176    Path: Vec<usize>,
177}
178
179impl InkAnimSequence {
180    /// summarize all paths matching sequences of digits
181    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}