Skip to main content

warpack_formats/
object.rs

1use std::collections::BTreeMap;
2
3use serde::{Deserialize, Serialize};
4
5use crate::metadata::FieldVariant;
6use crate::metadata::MetadataStore;
7use crate::ObjectId;
8use crate::ObjectKind;
9use crate::parser::slk;
10use crate::ValueType;
11
12#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
13pub enum Value {
14    String(String),
15    Int(i32),
16    Real(f32),
17    Unreal(f32),
18}
19
20impl Value {
21    pub fn default(type_id: u32) -> Option<Self> {
22        match type_id {
23            0 => Some(Value::Unreal(0.0)),
24            1 => Some(Value::Real(0.0)),
25            2 => Some(Value::Int(0)),
26            3 => Some(Value::String("".into())),
27            _ => None
28        }
29    }
30
31    pub fn from_str_and_ty(value: &str, ty: ValueType) -> Option<Self> {
32        Some(match ty {
33            ValueType::Unreal => Value::Unreal(value.parse().ok()?),
34            ValueType::Real => Value::Real(value.parse().ok()?),
35            ValueType::Int => Value::Int(value.parse().ok()?),
36            ValueType::String => Value::String(value.into()),
37        })
38    }
39
40    pub fn type_id(&self) -> u32 {
41        match self {
42            Value::Int(..) => 0,
43            Value::Real(..) => 1,
44            Value::Unreal(..) => 2,
45            Value::String(..) => 3,
46        }
47    }
48}
49
50#[derive(Debug, Clone, Copy, PartialEq, Serialize, Deserialize)]
51pub enum ValueKind {
52    Common,
53    SD,
54    HD,
55}
56
57#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
58pub struct LeveledValue {
59    pub level: u32,
60    pub value: Option<Value>,
61    pub value_sd: Option<Value>,
62    pub value_hd: Option<Value>,
63}
64
65#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
66pub enum FieldKind {
67    Simple { value: Option<Value>, value_sd: Option<Value>, value_hd: Option<Value> },
68    Leveled { values: Vec<LeveledValue> },
69}
70
71#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
72pub struct Field {
73    pub id: ObjectId,
74    pub kind: FieldKind,
75}
76
77#[derive(Debug, Clone, Serialize, Deserialize)]
78pub struct Object {
79    kind: ObjectKind,
80    id: ObjectId,
81    aliased_id: Option<ObjectId>,
82    parent_id: Option<ObjectId>,
83    fields: BTreeMap<ObjectId, Field>,
84    dirty: bool,
85}
86
87impl Object {
88    pub fn new(id: ObjectId, kind: ObjectKind) -> Object {
89        Object {
90            id,
91            kind,
92            aliased_id: None,
93            parent_id: None,
94            fields: Default::default(),
95            dirty: true,
96        }
97    }
98
99    pub fn with_parent(id: ObjectId, parent_id: ObjectId, kind: ObjectKind) -> Object {
100        Object {
101            id,
102            kind,
103            aliased_id: None,
104            parent_id: Some(parent_id),
105            fields: Default::default(),
106            dirty: true,
107        }
108    }
109
110    pub fn id(&self) -> ObjectId {
111        self.id
112    }
113
114    pub fn set_id(&mut self, id: ObjectId) {
115        self.id = id
116    }
117
118    pub fn aliased_id(&self) -> Option<ObjectId> {
119        self.aliased_id
120    }
121
122    pub fn set_aliased_id(&mut self, aliased_id: Option<ObjectId>) {
123        self.aliased_id = aliased_id
124    }
125
126    pub fn parent_id(&self) -> Option<ObjectId> {
127        self.parent_id
128    }
129
130    pub fn set_parent_id(&mut self, parent_id: Option<ObjectId>) {
131        self.parent_id = parent_id
132    }
133
134    pub fn kind(&self) -> ObjectKind {
135        self.kind
136    }
137
138    pub fn is_dirty(&self) -> bool {
139        self.dirty
140    }
141
142    pub fn set_dirty(&mut self, dirty: bool) {
143        self.dirty = dirty
144    }
145
146    pub fn fields(&self) -> impl Iterator<Item=(&ObjectId, &Field)> {
147        self.fields.iter()
148    }
149
150    pub fn field(&self, id: ObjectId) -> Option<&Field> {
151        self.fields.get(&id)
152    }
153
154    pub fn simple_field(&self, id: ObjectId, value_kind: ValueKind) -> Option<&Value> {
155        self.fields.get(&id).and_then(|field| match &field.kind {
156            FieldKind::Simple { value, value_sd, value_hd } =>
157                match value_kind {
158                    ValueKind::Common => value.as_ref(),
159                    ValueKind::SD => value_sd.as_ref().or(value.as_ref()),
160                    ValueKind::HD => value_hd.as_ref().or(value.as_ref()),
161                }
162            _ => None,
163        })
164    }
165
166    pub fn leveled_field(&self, id: ObjectId, level: u32, value_kind: ValueKind) -> Option<&Value> {
167        self.fields.get(&id).and_then(|field| match &field.kind {
168            FieldKind::Leveled { values } => values
169                .iter()
170                .find(|value| value.level == level)
171                .and_then(|value| match value_kind {
172                    ValueKind::Common => value.value.as_ref(),
173                    ValueKind::SD => value.value_sd.as_ref().or(value.value.as_ref()),
174                    ValueKind::HD =>  value.value_hd.as_ref().or(value.value.as_ref())
175                }),
176            _ => None,
177        })
178    }
179
180    pub fn unset_simple_field(&mut self, id: ObjectId) {
181        self.dirty = true;
182
183        self.fields.remove(&id);
184    }
185
186    pub fn unset_leveled_field(&mut self, id: ObjectId, level: u32) {
187        self.dirty = true;
188
189        if let Some(field) = self.fields.get_mut(&id) {
190            if let FieldKind::Leveled { values } = &mut field.kind {
191                values.retain(|dv| dv.level != level)
192            }
193        }
194    }
195
196    pub fn set_simple_field(&mut self, id: ObjectId, value: Value, value_kind: ValueKind) {
197        self.dirty = true;
198
199        let field = self.fields.entry(id).or_insert_with(|| Field {
200            id,
201            kind: FieldKind::Simple {
202                value: None,
203                value_sd: None,
204                value_hd: None,
205            },
206        });
207
208        match &mut field.kind {
209            FieldKind::Simple { value: value_ref, value_sd: value_sd_ref, value_hd: value_hd_ref } => {
210                match value_kind {
211                    ValueKind::Common => value_ref,
212                    ValueKind::SD => value_sd_ref,
213                    ValueKind::HD => value_hd_ref
214                }.replace(value);
215            },
216            FieldKind::Leveled { .. } => eprintln!(
217                "tried to insert simple field {} for object {}, but a data field {} already exists",
218                    id, self.id, field.id
219            ),
220        }
221    }
222
223    pub fn set_leveled_field(&mut self, id: ObjectId, level: u32, value: Value, value_kind: ValueKind) {
224        self.dirty = true;
225
226        let field = self.fields.entry(id).or_insert_with(|| Field {
227            id,
228            kind: FieldKind::Leveled {
229                values: Default::default(),
230            },
231        });
232
233        match &mut field.kind {
234            FieldKind::Simple { .. } => eprintln!(
235                "tried to insert data field {} for object {}, but a simple field {} already exists",
236                id, self.id, field.id
237            ),
238            FieldKind::Leveled { values } => {
239                if let Some(leveled_value) = values.iter_mut().find(|dv| dv.level == level) {
240                    match value_kind {
241                        ValueKind::Common => leveled_value.value = Some(value),
242                        ValueKind::SD => leveled_value.value_sd = Some(value),
243                        ValueKind::HD => leveled_value.value_hd = Some(value)
244                    }
245                } else {
246                    values.push(
247                        LeveledValue {
248                            level,
249                            value: if value_kind == ValueKind::Common {
250                                Some(value.clone())
251                            } else {
252                                None
253                            },
254                            value_sd: if value_kind == ValueKind::SD {
255                                Some(value.clone())
256                            } else {
257                                None
258                            },
259                            value_hd: if value_kind == ValueKind::HD {
260                                Some(value.clone())
261                            } else {
262                                None
263                            }
264                        }
265                    );
266                }
267            }
268        }
269    }
270
271    /// Merges this object's data with another object's data
272    /// Doesn't do field-level merging because it's not needed
273    /// in our use case. Just override the fields in this object
274    /// from the fields in the other.
275    pub fn add_from(&mut self, other: &Object) {
276        self.dirty = true;
277
278        for (id, field) in &other.fields {
279            self.fields.insert(*id, field.clone());
280        }
281    }
282
283    pub(crate) fn process_slk_field(
284        &mut self,
285        value: &slk::Value,
286        name: &str,
287        metadata: &MetadataStore,
288    ) -> Option<()> {
289        let (field_meta, level) = metadata.query_slk_field(name, &self)?;
290
291        let value = Value::from_str_and_ty(value.as_inner()?, field_meta.value_ty)?;
292        let field_id = field_meta.id;
293
294        match field_meta.variant {
295            FieldVariant::Normal { .. } => self.set_simple_field(field_id, value, ValueKind::Common),
296            FieldVariant::Leveled { .. } | FieldVariant::Data { .. } => self.set_leveled_field(
297                field_id,
298                level.expect("field must have level specified"),
299                value,
300                ValueKind::Common,
301            ),
302        }
303
304        Some(())
305    }
306
307    pub(crate) fn process_func_field(
308        &mut self,
309        key: &str,
310        value: &str,
311        index: i8,
312        metadata: &MetadataStore,
313    ) -> Option<()> {
314        let hd = key.ends_with(":hd");
315        let value_kind = if hd { ValueKind::HD } else { ValueKind::Common };
316        let field_name = key.strip_suffix(":hd").unwrap_or(key);
317        let (field_meta, level) = metadata.query_profile_field(field_name, &self, index)?;
318        let value = Value::from_str_and_ty(value, field_meta.value_ty)?;
319
320        if let Some(level) = level {
321            self.set_leveled_field(field_meta.id, level, value, value_kind)
322        } else {
323            self.set_simple_field(field_meta.id, value, value_kind)
324        }
325
326        Some(())
327    }
328}