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}
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/// see [NativeDB](https://nativedb.red4ext.com/Vector2)
80#[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/// see [NativeDB](https://nativedb.red4ext.com/HDRColor)
89#[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/// asset handle ID
100#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
101#[serde(transparent)]
102pub struct HandleId(#[serde(deserialize_with = "deserialize_number_from_string")] u32);
103
104/// wrapper with handle ID
105#[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/// specific resource ID
113#[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/// specific translation ID
123#[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/// animation aggregated informations summary
145#[allow(dead_code, non_snake_case)]
146#[derive(Debug)]
147pub struct PathSummary {
148    /// animation name
149    Name: Name,
150    /// unique handle ID
151    HandleId: HandleId,
152    /// index in sequence
153    Index: usize,
154    /// path to the nested element
155    Path: Vec<usize>,
156}
157
158impl InkAnimSequence {
159    /// summarize all paths matching sequences of digits
160    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}