Skip to main content

unity_formats/animator/
read.rs

1//! Reading an Avatar and an AnimatorController into the typed data of [`crate::animator`]. Every field is
2//! required: a missing or mistyped one is an error naming it and the object (nothing defaults to zero).
3
4use crate::animator::{
5    AvatarAxes, AvatarHuman, AvatarSkeleton, BlendNode, Condition, HumanBone, HumanDescription, Layer,
6    Parameter, SELECTOR_BASE, SelectorState, SelectorTransition, SkeletonBone, State, StateMachine,
7    Transition, UnityAnimatorController, UnityAvatar, Xform,
8};
9use crate::player::{ObjRef, Player};
10use crate::value::{Array, Value};
11use crate::{Result, invalid};
12
13/// A field reader over one object: errors name `what` and the field.
14struct Fields<'a> {
15    what: &'a str,
16}
17
18impl Fields<'_> {
19    fn get<'v>(&self, v: &'v Value, k: &str) -> Result<&'v Value> {
20        v.get(k).ok_or_else(|| invalid(format!("{}: no {k}", self.what)))
21    }
22
23    /// The `data` of an offset-pointer wrapper (`{"data": {...}}`).
24    fn data<'v>(&self, v: &'v Value) -> Result<&'v Value> {
25        self.get(v, "data")
26    }
27
28    fn int(&self, v: &Value, k: &str) -> Result<i64> {
29        self.get(v, k)?
30            .as_i64()
31            .ok_or_else(|| invalid(format!("{}: {k} is not an integer", self.what)))
32    }
33
34    fn uint(&self, v: &Value, k: &str) -> Result<u32> {
35        u32::try_from(self.int(v, k)?)
36            .map_err(|_| invalid(format!("{}: {k} is not a 32-bit unsigned integer", self.what)))
37    }
38
39    fn float(&self, v: &Value, k: &str) -> Result<f32> {
40        self.get(v, k)?
41            .as_f32()
42            .ok_or_else(|| invalid(format!("{}: {k} is not a float", self.what)))
43    }
44
45    fn flag(&self, v: &Value, k: &str) -> Result<bool> {
46        match self.get(v, k)? {
47            Value::Bool(b) => Ok(*b),
48            x => x
49                .as_i64()
50                .map(|i| i != 0)
51                .ok_or_else(|| invalid(format!("{}: {k} is not a flag", self.what))),
52        }
53    }
54
55    fn string(&self, v: &Value, k: &str) -> Result<String> {
56        self.get(v, k)?
57            .as_str()
58            .map(str::to_owned)
59            .ok_or_else(|| invalid(format!("{}: {k} is not a string", self.what)))
60    }
61
62    fn vec3(&self, v: &Value, k: &str) -> Result<[f32; 3]> {
63        let x = self.get(v, k)?;
64        Ok([self.float(x, "x")?, self.float(x, "y")?, self.float(x, "z")?])
65    }
66
67    fn vec2(&self, x: &Value) -> Result<[f32; 2]> {
68        Ok([self.float(x, "x")?, self.float(x, "y")?])
69    }
70
71    /// A stored rotation, kept as stored; one of no length or not finite is no rotation and refused.
72    fn quat(&self, v: &Value, k: &str) -> Result<[f32; 4]> {
73        let x = self.get(v, k)?;
74        let q = [
75            self.float(x, "x")?,
76            self.float(x, "y")?,
77            self.float(x, "z")?,
78            self.float(x, "w")?,
79        ];
80        let length = q.iter().map(|&x| f64::from(x) * f64::from(x)).sum::<f64>().sqrt();
81        if !(length > 0.0 && length.is_finite()) {
82            return Err(invalid(format!("{}: {k} {q:?} is no rotation", self.what)));
83        }
84        Ok(q)
85    }
86
87    /// The elements of a list of structs; an empty list of any element type is empty.
88    fn list<'v>(&self, v: &'v Value, k: &str) -> Result<&'v [Value]> {
89        match self.get(v, k)? {
90            Value::Array(Array::Values(items)) => Ok(items),
91            Value::Array(a) if a.is_empty() => Ok(&[]),
92            _ => Err(invalid(format!("{}: {k} is not a list", self.what))),
93        }
94    }
95
96    /// A list of integers of any width.
97    fn ints(&self, v: &Value, k: &str) -> Result<Vec<i64>> {
98        let bad = || invalid(format!("{}: {k} is not a list of integers", self.what));
99        Ok(match self.get(v, k)? {
100            Value::Array(Array::I8(x)) => x.iter().map(|&i| i64::from(i)).collect(),
101            Value::Array(Array::I16(x)) => x.iter().map(|&i| i64::from(i)).collect(),
102            Value::Array(Array::I32(x)) => x.iter().map(|&i| i64::from(i)).collect(),
103            Value::Array(Array::I64(x)) => x.clone(),
104            Value::Array(Array::U8(x)) => x.iter().map(|&i| i64::from(i)).collect(),
105            Value::Array(Array::U16(x)) => x.iter().map(|&i| i64::from(i)).collect(),
106            Value::Array(Array::U32(x)) => x.iter().map(|&i| i64::from(i)).collect(),
107            Value::Array(Array::U64(x)) => x
108                .iter()
109                .map(|&i| i64::try_from(i).map_err(|_| bad()))
110                .collect::<Result<_>>()?,
111            Value::Array(Array::Values(x)) => x
112                .iter()
113                .map(|i| i.as_i64().ok_or_else(bad))
114                .collect::<Result<_>>()?,
115            Value::Array(a) if a.is_empty() => Vec::new(),
116            _ => return Err(bad()),
117        })
118    }
119
120    fn uints(&self, v: &Value, k: &str) -> Result<Vec<u32>> {
121        self.ints(v, k)?
122            .into_iter()
123            .map(|i| {
124                u32::try_from(i).map_err(|_| {
125                    invalid(format!(
126                        "{}: {k} holds {i}, not a 32-bit unsigned integer",
127                        self.what
128                    ))
129                })
130            })
131            .collect()
132    }
133
134    fn floats(&self, v: &Value, k: &str) -> Result<Vec<f32>> {
135        let bad = || invalid(format!("{}: {k} is not a list of floats", self.what));
136        Ok(match self.get(v, k)? {
137            Value::Array(Array::F32(x)) => x.clone(),
138            Value::Array(Array::Values(x)) => x
139                .iter()
140                .map(|i| i.as_f32().ok_or_else(bad))
141                .collect::<Result<_>>()?,
142            Value::Array(a) if a.is_empty() => Vec::new(),
143            _ => return Err(bad()),
144        })
145    }
146
147    fn bools(&self, v: &Value, k: &str) -> Result<Vec<bool>> {
148        let bad = || invalid(format!("{}: {k} is not a list of flags", self.what));
149        Ok(match self.get(v, k)? {
150            Value::Array(Array::Bool(x)) => x.clone(),
151            Value::Array(Array::U8(x)) => x.iter().map(|&b| b != 0).collect(),
152            Value::Array(Array::Values(x)) => x
153                .iter()
154                .map(|i| match i {
155                    Value::Bool(b) => Ok(*b),
156                    other => other.as_i64().map(|n| n != 0).ok_or_else(bad),
157                })
158                .collect::<Result<_>>()?,
159            Value::Array(a) if a.is_empty() => Vec::new(),
160            _ => return Err(bad()),
161        })
162    }
163
164    /// A list of `(hash, text)` pairs (`m_TOS`).
165    fn tos(&self, v: &Value, k: &str) -> Result<Vec<(u32, String)>> {
166        self.list(v, k)?
167            .iter()
168            .map(|p| match p {
169                Value::Pair(pair) => {
170                    let hash = pair
171                        .0
172                        .as_i64()
173                        .and_then(|h| u32::try_from(h).ok())
174                        .ok_or_else(|| {
175                            invalid(format!("{}: {k} holds a hash that is not 32 bits", self.what))
176                        })?;
177                    let text = pair.1.as_str().ok_or_else(|| {
178                        invalid(format!("{}: {k} holds a name that is not a string", self.what))
179                    })?;
180                    Ok((hash, text.to_owned()))
181                }
182                _ => Err(invalid(format!(
183                    "{}: {k} holds something that is not a pair",
184                    self.what
185                ))),
186            })
187            .collect()
188    }
189
190    fn xform(&self, v: &Value) -> Result<Xform> {
191        Ok(Xform {
192            t: self.vec3(v, "t")?,
193            q: self.quat(v, "q")?,
194            s: self.vec3(v, "s")?,
195        })
196    }
197
198    /// `{"data": {"m_X": [xform, ...]}}`.
199    fn pose(&self, v: &Value) -> Result<Vec<Xform>> {
200        let d = self.data(v)?;
201        self.list(d, "m_X")?.iter().map(|x| self.xform(x)).collect()
202    }
203
204    /// `{"data": {"m_Node", "m_ID", "m_AxesArray"}}`.
205    fn skeleton(&self, v: &Value) -> Result<AvatarSkeleton> {
206        let d = self.data(v)?;
207        let nodes = self
208            .list(d, "m_Node")?
209            .iter()
210            .map(|n| Ok((self.int(n, "m_ParentId")?, self.int(n, "m_AxesId")?)))
211            .collect::<Result<Vec<_>>>()?;
212        let ids = self.uints(d, "m_ID")?;
213        if ids.len() != nodes.len() {
214            return Err(invalid(format!(
215                "{}: {} node ids for {} nodes",
216                self.what,
217                ids.len(),
218                nodes.len()
219            )));
220        }
221        let axes = self
222            .list(d, "m_AxesArray")?
223            .iter()
224            .map(|a| {
225                let limit = self.get(a, "m_Limit")?;
226                Ok(AvatarAxes {
227                    pre_q: self.quat(a, "m_PreQ")?,
228                    post_q: self.quat(a, "m_PostQ")?,
229                    sgn: self.vec3(a, "m_Sgn")?,
230                    min: self.vec3(limit, "m_Min")?,
231                    max: self.vec3(limit, "m_Max")?,
232                    length: self.float(a, "m_Length")?,
233                    kind: self.int(a, "m_Type")?,
234                })
235            })
236            .collect::<Result<Vec<_>>>()?;
237        for (k, &(parent, axes_id)) in nodes.iter().enumerate() {
238            let in_range = |i: i64, n: usize| i == -1 || usize::try_from(i).is_ok_and(|i| i < n);
239            if !in_range(parent, nodes.len()) || !in_range(axes_id, axes.len()) {
240                return Err(invalid(format!(
241                    "{}: node {k} names parent {parent} and axes {axes_id} of {} nodes and {} axes",
242                    self.what,
243                    nodes.len(),
244                    axes.len()
245                )));
246            }
247        }
248        Ok(AvatarSkeleton { nodes, ids, axes })
249    }
250}
251
252fn human(f: &Fields, v: &Value) -> Result<Option<AvatarHuman>> {
253    let d = f.data(v)?;
254    let skeleton = f.skeleton(f.get(d, "m_Skeleton")?)?;
255    // a generic avatar's human data is empty
256    if skeleton.nodes.is_empty() {
257        return Ok(None);
258    }
259    let hand = |k: &str| f.ints(f.data(f.get(d, k)?)?, "m_HandBoneIndex");
260    let pose = f.pose(f.get(d, "m_SkeletonPose")?)?;
261    if pose.len() != skeleton.nodes.len() {
262        return Err(invalid(format!(
263            "{}: {} human poses for {} human nodes",
264            f.what,
265            pose.len(),
266            skeleton.nodes.len()
267        )));
268    }
269    Ok(Some(AvatarHuman {
270        root: f.xform(f.get(d, "m_RootX")?)?,
271        skeleton,
272        pose,
273        left_hand: hand("m_LeftHand")?,
274        right_hand: hand("m_RightHand")?,
275        bone_index: f.ints(d, "m_HumanBoneIndex")?,
276        bone_mass: f.floats(d, "m_HumanBoneMass")?,
277        scale: f.float(d, "m_Scale")?,
278        arm_twist: f.float(d, "m_ArmTwist")?,
279        fore_arm_twist: f.float(d, "m_ForeArmTwist")?,
280        upper_leg_twist: f.float(d, "m_UpperLegTwist")?,
281        leg_twist: f.float(d, "m_LegTwist")?,
282        arm_stretch: f.float(d, "m_ArmStretch")?,
283        leg_stretch: f.float(d, "m_LegStretch")?,
284        feet_spacing: f.float(d, "m_FeetSpacing")?,
285        has_left_hand: f.flag(d, "m_HasLeftHand")?,
286        has_right_hand: f.flag(d, "m_HasRightHand")?,
287        has_translation_dof: f.flag(d, "m_HasTDoF")?,
288    }))
289}
290
291fn description(f: &Fields, v: &Value) -> Result<HumanDescription> {
292    let human = f
293        .list(v, "m_Human")?
294        .iter()
295        .map(|b| {
296            let limit = f.get(b, "m_Limit")?;
297            Ok(HumanBone {
298                bone_name: f.string(b, "m_BoneName")?,
299                human_name: f.string(b, "m_HumanName")?,
300                min: f.vec3(limit, "m_Min")?,
301                max: f.vec3(limit, "m_Max")?,
302                value: f.vec3(limit, "m_Value")?,
303                length: f.float(limit, "m_Length")?,
304                modified: f.flag(limit, "m_Modified")?,
305            })
306        })
307        .collect::<Result<Vec<_>>>()?;
308    let skeleton = f
309        .list(v, "m_Skeleton")?
310        .iter()
311        .map(|b| {
312            Ok(SkeletonBone {
313                name: f.string(b, "m_Name")?,
314                parent: f.string(b, "m_ParentName")?,
315                position: f.vec3(b, "m_Position")?,
316                rotation: f.quat(b, "m_Rotation")?,
317                scale: f.vec3(b, "m_Scale")?,
318            })
319        })
320        .collect::<Result<Vec<_>>>()?;
321    Ok(HumanDescription {
322        human,
323        skeleton,
324        arm_twist: f.float(v, "m_ArmTwist")?,
325        fore_arm_twist: f.float(v, "m_ForeArmTwist")?,
326        upper_leg_twist: f.float(v, "m_UpperLegTwist")?,
327        leg_twist: f.float(v, "m_LegTwist")?,
328        arm_stretch: f.float(v, "m_ArmStretch")?,
329        leg_stretch: f.float(v, "m_LegStretch")?,
330        feet_spacing: f.float(v, "m_FeetSpacing")?,
331        global_scale: f.float(v, "m_GlobalScale")?,
332        root_motion_bone_name: f.string(v, "m_RootMotionBoneName")?,
333        has_translation_dof: f.flag(v, "m_HasTranslationDoF")?,
334        has_extra_root: f.flag(v, "m_HasExtraRoot")?,
335        skeleton_has_parents: f.flag(v, "m_SkeletonHasParents")?,
336    })
337}
338
339impl UnityAvatar {
340    /// The Avatar object `r`.
341    pub fn read(player: &Player, r: &ObjRef) -> Result<UnityAvatar> {
342        let v = player.decode(r)?;
343        let name = v.get("m_Name").and_then(Value::as_str).unwrap_or("").to_owned();
344        let what = format!("Avatar {}/{} {name:?}", r.file, r.path_id);
345        let f = Fields { what: &what };
346        let a = f.get(&v, "m_Avatar")?;
347        let skeleton = f.skeleton(f.get(a, "m_AvatarSkeleton")?)?;
348        let skeleton_pose = f.pose(f.get(a, "m_AvatarSkeletonPose")?)?;
349        let default_pose = f.pose(f.get(a, "m_DefaultPose")?)?;
350        for (pose, which) in [(&skeleton_pose, "skeleton pose"), (&default_pose, "default pose")] {
351            if pose.len() != skeleton.nodes.len() {
352                return Err(invalid(format!(
353                    "{what}: {} {which} transforms for {} nodes",
354                    pose.len(),
355                    skeleton.nodes.len()
356                )));
357            }
358        }
359        let root_motion_skeleton = f.skeleton(f.get(a, "m_RootMotionSkeleton")?)?;
360        let root_motion_pose = f.pose(f.get(a, "m_RootMotionSkeletonPose")?)?;
361        // the root motion skeleton's pose is stored with its nodes or not at all (SkateBIRD's seagull and little bird have
362        // two nodes and no pose)
363        if !root_motion_pose.is_empty() && root_motion_pose.len() != root_motion_skeleton.nodes.len() {
364            return Err(invalid(format!(
365                "{what}: {} root motion poses for {} root motion nodes",
366                root_motion_pose.len(),
367                root_motion_skeleton.nodes.len()
368            )));
369        }
370        Ok(UnityAvatar {
371            avatar: r.clone(),
372            name,
373            skeleton,
374            skeleton_pose,
375            default_pose,
376            skeleton_name_ids: f.uints(a, "m_SkeletonNameIDArray")?,
377            human: human(&f, f.get(a, "m_Human")?)?,
378            human_skeleton_index: f.ints(a, "m_HumanSkeletonIndexArray")?,
379            human_skeleton_reverse: f.ints(a, "m_HumanSkeletonReverseIndexArray")?,
380            root_motion_bone_index: f.int(a, "m_RootMotionBoneIndex")?,
381            root_motion_bone: f.xform(f.get(a, "m_RootMotionBoneX")?)?,
382            root_motion_skeleton,
383            root_motion_pose,
384            root_motion_skeleton_index: f.ints(a, "m_RootMotionSkeletonIndexArray")?,
385            tos: f.tos(&v, "m_TOS")?,
386            description: description(&f, f.get(&v, "m_HumanDescription")?)?,
387        })
388    }
389}
390
391fn conditions(f: &Fields, v: &Value, k: &str) -> Result<Vec<Condition>> {
392    f.list(v, k)?
393        .iter()
394        .map(|c| {
395            let c = f.data(c)?;
396            Ok(Condition {
397                mode: f.int(c, "m_ConditionMode")?,
398                parameter: f.uint(c, "m_EventID")?,
399                threshold: f.float(c, "m_EventThreshold")?,
400                exit_time: f.float(c, "m_ExitTime")?,
401            })
402        })
403        .collect()
404}
405
406fn transition(f: &Fields, t: &Value) -> Result<Transition> {
407    let t = f.data(t)?;
408    Ok(Transition {
409        conditions: conditions(f, t, "m_ConditionConstantArray")?,
410        destination: f.int(t, "m_DestinationState")?,
411        full_path_id: f.uint(t, "m_FullPathID")?,
412        id: f.uint(t, "m_ID")?,
413        user_id: f.uint(t, "m_UserID")?,
414        duration: f.float(t, "m_TransitionDuration")?,
415        offset: f.float(t, "m_TransitionOffset")?,
416        exit_time: f.float(t, "m_ExitTime")?,
417        has_exit_time: f.flag(t, "m_HasExitTime")?,
418        has_fixed_duration: f.flag(t, "m_HasFixedDuration")?,
419        interruption_source: f.int(t, "m_InterruptionSource")?,
420        ordered_interruption: f.flag(t, "m_OrderedInterruption")?,
421        can_transition_to_self: f.flag(t, "m_CanTransitionToSelf")?,
422    })
423}
424
425fn blend_node(f: &Fields, n: &Value) -> Result<BlendNode> {
426    let n = f.data(n)?;
427    let one = f.data(f.get(n, "m_Blend1dData")?)?;
428    let two = f.data(f.get(n, "m_Blend2dData")?)?;
429    let direct = f.data(f.get(n, "m_BlendDirectData")?)?;
430    Ok(BlendNode {
431        blend_type: f.int(n, "m_BlendType")?,
432        event_id: f.uint(n, "m_BlendEventID")?,
433        event_y_id: f.uint(n, "m_BlendEventYID")?,
434        children: f.uints(n, "m_ChildIndices")?,
435        thresholds: f.floats(one, "m_ChildThresholdArray")?,
436        positions: f
437            .list(two, "m_ChildPositionArray")?
438            .iter()
439            .map(|p| f.vec2(p))
440            .collect::<Result<_>>()?,
441        magnitudes: f.floats(two, "m_ChildMagnitudeArray")?,
442        pair_vectors: f
443            .list(two, "m_ChildPairVectorArray")?
444            .iter()
445            .map(|p| f.vec2(p))
446            .collect::<Result<_>>()?,
447        pair_avg_mag_inv: f.floats(two, "m_ChildPairAvgMagInvArray")?,
448        neighbors: f
449            .list(two, "m_ChildNeighborListArray")?
450            .iter()
451            .map(|l| f.uints(l, "m_NeighborArray"))
452            .collect::<Result<_>>()?,
453        direct_events: f.uints(direct, "m_ChildBlendEventIDArray")?,
454        normalized_blend_values: f.flag(direct, "m_NormalizedBlendValues")?,
455        clip: f.uint(n, "m_ClipID")?,
456        duration: f.float(n, "m_Duration")?,
457        cycle_offset: f.float(n, "m_CycleOffset")?,
458        mirror: f.flag(n, "m_Mirror")?,
459    })
460}
461
462fn state(f: &Fields, s: &Value) -> Result<State> {
463    let s = f.data(s)?;
464    Ok(State {
465        transitions: f
466            .list(s, "m_TransitionConstantArray")?
467            .iter()
468            .map(|t| transition(f, t))
469            .collect::<Result<_>>()?,
470        blend_tree_index: f.ints(s, "m_BlendTreeConstantIndexArray")?,
471        blend_trees: f
472            .list(s, "m_BlendTreeConstantArray")?
473            .iter()
474            .map(|tree| {
475                let tree = f.data(tree)?;
476                f.list(tree, "m_NodeArray")?
477                    .iter()
478                    .map(|n| blend_node(f, n))
479                    .collect::<Result<Vec<_>>>()
480            })
481            .collect::<Result<_>>()?,
482        name_id: f.uint(s, "m_NameID")?,
483        path_id: f.uint(s, "m_PathID")?,
484        full_path_id: f.uint(s, "m_FullPathID")?,
485        tag_id: f.uint(s, "m_TagID")?,
486        speed_param: f.uint(s, "m_SpeedParamID")?,
487        mirror_param: f.uint(s, "m_MirrorParamID")?,
488        cycle_offset_param: f.uint(s, "m_CycleOffsetParamID")?,
489        time_param: f.uint(s, "m_TimeParamID")?,
490        speed: f.float(s, "m_Speed")?,
491        cycle_offset: f.float(s, "m_CycleOffset")?,
492        ik_on_feet: f.flag(s, "m_IKOnFeet")?,
493        write_default_values: f.flag(s, "m_WriteDefaultValues")?,
494        looping: f.flag(s, "m_Loop")?,
495        mirror: f.flag(s, "m_Mirror")?,
496    })
497}
498
499fn state_machine(f: &Fields, m: &Value) -> Result<StateMachine> {
500    let m = f.data(m)?;
501    Ok(StateMachine {
502        states: f
503            .list(m, "m_StateConstantArray")?
504            .iter()
505            .map(|s| state(f, s))
506            .collect::<Result<_>>()?,
507        any_state_transitions: f
508            .list(m, "m_AnyStateTransitionConstantArray")?
509            .iter()
510            .map(|t| transition(f, t))
511            .collect::<Result<_>>()?,
512        selectors: f
513            .list(m, "m_SelectorStateConstantArray")?
514            .iter()
515            .map(|s| {
516                let s = f.data(s)?;
517                Ok(SelectorState {
518                    transitions: f
519                        .list(s, "m_TransitionConstantArray")?
520                        .iter()
521                        .map(|t| {
522                            let t = f.data(t)?;
523                            Ok(SelectorTransition {
524                                destination: f.uint(t, "m_Destination")?,
525                                conditions: conditions(f, t, "m_ConditionConstantArray")?,
526                            })
527                        })
528                        .collect::<Result<_>>()?,
529                    full_path_id: f.uint(s, "m_FullPathID")?,
530                    is_entry: f.flag(s, "m_IsEntry")?,
531                })
532            })
533            .collect::<Result<_>>()?,
534        default_state: f.int(m, "m_DefaultState")?,
535        synchronized_layer_count: f.int(m, "m_SynchronizedLayerCount")?,
536    })
537}
538
539fn layer(f: &Fields, l: &Value) -> Result<Layer> {
540    let l = f.data(l)?;
541    let mask = f.get(l, "m_BodyMask")?;
542    Ok(Layer {
543        state_machine: f.int(l, "m_StateMachineIndex")?,
544        synchronized_layer: f.int(l, "m_StateMachineSynchronizedLayerIndex")?,
545        body_mask: [
546            f.uint(mask, "word0")?,
547            f.uint(mask, "word1")?,
548            f.uint(mask, "word2")?,
549        ],
550        skeleton_mask: f
551            .list(f.data(f.get(l, "m_SkeletonMask")?)?, "m_Data")?
552            .iter()
553            .map(|e| Ok((f.uint(e, "m_PathHash")?, f.float(e, "m_Weight")?)))
554            .collect::<Result<_>>()?,
555        binding: f.uint(l, "m_Binding")?,
556        blending_mode: f.int(l, "(int&)m_LayerBlendingMode")?,
557        default_weight: f.float(l, "m_DefaultWeight")?,
558        ik_pass: f.flag(l, "m_IKPass")?,
559        synced_layer_affects_timing: f.flag(l, "m_SyncedLayerAffectsTiming")?,
560    })
561}
562
563impl UnityAnimatorController {
564    /// The AnimatorController object `r`.
565    pub fn read(player: &Player, r: &ObjRef) -> Result<UnityAnimatorController> {
566        let v = player.decode(r)?;
567        let name = v.get("m_Name").and_then(Value::as_str).unwrap_or("").to_owned();
568        let what = format!("AnimatorController {}/{} {name:?}", r.file, r.path_id);
569        let f = Fields { what: &what };
570        let c = f.get(&v, "m_Controller")?;
571        let values = f.data(f.get(c, "m_Values")?)?;
572        let defaults = f.data(f.get(c, "m_DefaultValues")?)?;
573        let pointers = |k: &str| -> Result<Vec<ObjRef>> {
574            let mut out = Vec::new();
575            for p in f.list(&v, k)? {
576                if let Some(o) = player.resolve(&r.file, p)? {
577                    out.push(o);
578                }
579            }
580            Ok(out)
581        };
582        let controller = UnityAnimatorController {
583            controller: r.clone(),
584            name,
585            layers: f
586                .list(c, "m_LayerArray")?
587                .iter()
588                .map(|l| layer(&f, l))
589                .collect::<Result<_>>()?,
590            state_machines: f
591                .list(c, "m_StateMachineArray")?
592                .iter()
593                .map(|m| state_machine(&f, m))
594                .collect::<Result<_>>()?,
595            parameters: f
596                .list(values, "m_ValueArray")?
597                .iter()
598                .map(|p| {
599                    Ok(Parameter {
600                        id: f.uint(p, "m_ID")?,
601                        kind: f.int(p, "m_Type")?,
602                        index: f.int(p, "m_Index")?,
603                    })
604                })
605                .collect::<Result<_>>()?,
606            default_floats: f.floats(defaults, "m_FloatValues")?,
607            default_ints: f.ints(defaults, "m_IntValues")?,
608            default_bools: f.bools(defaults, "m_BoolValues")?,
609            clips: f
610                .list(&v, "m_AnimationClips")?
611                .iter()
612                .map(|p| player.resolve(&r.file, p))
613                .collect::<Result<_>>()?,
614            behaviours: pointers("m_StateMachineBehaviours")?,
615            tos: f.tos(&v, "m_TOS")?,
616        };
617        controller.check(&what)?;
618        Ok(controller)
619    }
620
621    /// The references inside the controller against what they index: layers' state machines, transitions' destinations,
622    /// blend trees' children and clips, parameters' defaults.
623    fn check(&self, what: &str) -> Result<()> {
624        let bad = |why: String| invalid(format!("{what}: {why}"));
625        for (k, l) in self.layers.iter().enumerate() {
626            if usize::try_from(l.state_machine).map_or(true, |i| i >= self.state_machines.len()) {
627                return Err(bad(format!(
628                    "layer {k} runs state machine {} of {}",
629                    l.state_machine,
630                    self.state_machines.len()
631                )));
632            }
633        }
634        for (m, machine) in self.state_machines.iter().enumerate() {
635            let states = machine.states.len() as i64;
636            let selectors = machine.selectors.len() as i64;
637            // a destination is a state (below SELECTOR_BASE) or SELECTOR_BASE plus a selector node (an exit, or an entry
638            // of another machine)
639            let reaches = |d: i64| {
640                (0..states).contains(&d)
641                    || (SELECTOR_BASE..SELECTOR_BASE.saturating_add(selectors)).contains(&d)
642            };
643            for t in machine
644                .states
645                .iter()
646                .flat_map(|s| &s.transitions)
647                .chain(&machine.any_state_transitions)
648            {
649                if !reaches(t.destination) {
650                    return Err(bad(format!(
651                        "state machine {m}: a transition to {} of {states} states and {selectors} selectors",
652                        t.destination
653                    )));
654                }
655            }
656            for t in machine.selectors.iter().flat_map(|s| &s.transitions) {
657                if !reaches(i64::from(t.destination)) {
658                    return Err(bad(format!(
659                        "state machine {m}: a selector transition to {} of {states} states and {selectors} selectors",
660                        t.destination
661                    )));
662                }
663            }
664            for s in &machine.states {
665                for tree in &s.blend_trees {
666                    for n in tree {
667                        if n.children.iter().any(|&c| c as usize >= tree.len()) {
668                            return Err(bad(format!(
669                                "state machine {m}: a blend tree child beyond its {} nodes",
670                                tree.len()
671                            )));
672                        }
673                        if n.children.is_empty() && n.clip != u32::MAX && n.clip as usize >= self.clips.len()
674                        {
675                            return Err(bad(format!(
676                                "state machine {m}: a blend tree leaf plays clip {} of {}",
677                                n.clip,
678                                self.clips.len()
679                            )));
680                        }
681                    }
682                }
683            }
684        }
685        for p in &self.parameters {
686            let count = match p.kind {
687                1 => self.default_floats.len(),
688                3 => self.default_ints.len(),
689                4 | 9 => self.default_bools.len(),
690                k => return Err(bad(format!("a parameter of kind {k}"))),
691            };
692            if usize::try_from(p.index).map_or(true, |i| i >= count) {
693                return Err(bad(format!(
694                    "a parameter of kind {} at {} of {count} defaults",
695                    p.kind, p.index
696                )));
697            }
698        }
699        Ok(())
700    }
701}
702
703#[cfg(test)]
704mod tests {
705    use super::*;
706    use std::sync::Arc;
707
708    fn s(fields: &[(&str, Value)]) -> Value {
709        Value::Struct(fields.iter().map(|(k, v)| (Arc::from(*k), v.clone())).collect())
710    }
711
712    fn list(items: Vec<Value>) -> Value {
713        Value::Array(Array::Values(items))
714    }
715
716    fn vec3(x: f32, y: f32, z: f32) -> Value {
717        s(&[
718            ("x", Value::Float(x)),
719            ("y", Value::Float(y)),
720            ("z", Value::Float(z)),
721        ])
722    }
723
724    fn quat(x: f32, y: f32, z: f32, w: f32) -> Value {
725        s(&[
726            ("x", Value::Float(x)),
727            ("y", Value::Float(y)),
728            ("z", Value::Float(z)),
729            ("w", Value::Float(w)),
730        ])
731    }
732
733    /// A skeleton of two nodes, the second under the first with the one axes entry.
734    #[test]
735    fn a_skeleton_reads_with_its_nodes_ids_and_axes() {
736        let axes = s(&[
737            ("m_PreQ", quat(0.0, 0.0, 0.0, 1.0)),
738            ("m_PostQ", quat(0.5, 0.5, 0.5, 0.5)),
739            ("m_Sgn", vec3(1.0, -1.0, 1.0)),
740            (
741                "m_Limit",
742                s(&[("m_Min", vec3(-1.0, -2.0, -3.0)), ("m_Max", vec3(1.0, 2.0, 3.0))]),
743            ),
744            ("m_Length", Value::Float(0.25)),
745            ("m_Type", Value::Int(1)),
746        ]);
747        let node = |p: i64, a: i64| s(&[("m_ParentId", Value::Int(p)), ("m_AxesId", Value::Int(a))]);
748        let wrap = |nodes: Vec<Value>, ids: Vec<u32>, axes: Vec<Value>| {
749            s(&[(
750                "data",
751                s(&[
752                    ("m_Node", list(nodes)),
753                    ("m_ID", Value::Array(Array::U32(ids))),
754                    ("m_AxesArray", list(axes)),
755                ]),
756            )])
757        };
758        let f = Fields { what: "t" };
759        let sk = f
760            .skeleton(&wrap(
761                vec![node(-1, -1), node(0, 0)],
762                vec![7, 9],
763                vec![axes.clone()],
764            ))
765            .unwrap();
766        assert_eq!(sk.nodes, vec![(-1, -1), (0, 0)]);
767        assert_eq!(sk.ids, vec![7, 9]);
768        assert_eq!(sk.axes[0].sgn, [1.0, -1.0, 1.0]);
769        assert_eq!(
770            (sk.axes[0].min, sk.axes[0].max),
771            ([-1.0, -2.0, -3.0], [1.0, 2.0, 3.0])
772        );
773        assert_eq!((sk.axes[0].length, sk.axes[0].kind), (0.25, 1));
774        // an id missing, a parent and an axes index out of range
775        let e = |w: Value| f.skeleton(&w).unwrap_err().to_string();
776        assert!(
777            e(wrap(vec![node(-1, -1), node(0, 0)], vec![7], vec![axes.clone()]))
778                .contains("1 node ids for 2 nodes")
779        );
780        assert!(e(wrap(vec![node(5, -1)], vec![7], vec![])).contains("names parent 5"));
781        assert!(e(wrap(vec![node(-1, 0)], vec![7], vec![])).contains("axes 0"));
782    }
783
784    /// Fields are required and typed: a missing one and one of another type are errors naming the field and the object.
785    #[test]
786    fn fields_are_required_and_typed() {
787        let f = Fields {
788            what: "Avatar a/1 \"x\"",
789        };
790        let v = s(&[("m_Scale", Value::Float(2.0)), ("m_Name", Value::Int(3))]);
791        assert_eq!(f.float(&v, "m_Scale").unwrap(), 2.0);
792        let missing = f.float(&v, "m_Other").unwrap_err().to_string();
793        assert!(
794            missing.contains("Avatar a/1") && missing.contains("no m_Other"),
795            "{missing}"
796        );
797        let mistyped = f.string(&v, "m_Name").unwrap_err().to_string();
798        assert!(mistyped.contains("m_Name is not a string"), "{mistyped}");
799        assert!(f.uint(&s(&[("k", Value::Int(-1))]), "k").is_err());
800        assert!(
801            f.uints(&s(&[("k", Value::Array(Array::I32(vec![1, -2])))]), "k")
802                .is_err()
803        );
804        assert_eq!(
805            f.ints(&s(&[("k", Value::Array(Array::I32(vec![1, -2])))]), "k")
806                .unwrap(),
807            vec![1, -2]
808        );
809        assert!(f.ints(&s(&[("k", list(vec![]))]), "k").unwrap().is_empty());
810    }
811
812    /// The name table is pairs of a hash and a name.
813    #[test]
814    fn name_tables_read_as_pairs() {
815        let f = Fields { what: "t" };
816        let pair =
817            |h: u32, n: &str| Value::Pair(Box::new((Value::UInt(u64::from(h)), Value::String(n.into()))));
818        let v = s(&[("m_TOS", list(vec![pair(1, "a"), pair(2, "b/c")]))]);
819        assert_eq!(
820            f.tos(&v, "m_TOS").unwrap(),
821            vec![(1, "a".to_owned()), (2, "b/c".to_owned())]
822        );
823        let bad = s(&[("m_TOS", list(vec![Value::Int(3)]))]);
824        assert!(
825            f.tos(&bad, "m_TOS")
826                .unwrap_err()
827                .to_string()
828                .contains("not a pair")
829        );
830    }
831
832    /// A controller's internal references are checked: a layer's state machine, a transition's destination, a blend
833    /// tree's child and clip, a parameter's default.
834    #[test]
835    fn a_controller_is_checked_against_what_its_indices_name() {
836        let leaf = |clip: u32| BlendNode {
837            blend_type: 0,
838            event_id: u32::MAX,
839            event_y_id: u32::MAX,
840            children: vec![],
841            thresholds: vec![],
842            positions: vec![],
843            magnitudes: vec![],
844            pair_vectors: vec![],
845            pair_avg_mag_inv: vec![],
846            neighbors: vec![],
847            direct_events: vec![],
848            normalized_blend_values: false,
849            clip,
850            duration: 1.0,
851            cycle_offset: 0.0,
852            mirror: false,
853        };
854        let state = |clip: u32, to: i64| State {
855            transitions: vec![Transition {
856                conditions: vec![],
857                destination: to,
858                full_path_id: 0,
859                id: 0,
860                user_id: 0,
861                duration: 0.1,
862                offset: 0.0,
863                exit_time: 0.0,
864                has_exit_time: false,
865                has_fixed_duration: true,
866                interruption_source: 0,
867                ordered_interruption: true,
868                can_transition_to_self: true,
869            }],
870            blend_tree_index: vec![0],
871            blend_trees: vec![vec![leaf(clip)]],
872            name_id: 1,
873            path_id: 1,
874            full_path_id: 1,
875            tag_id: 0,
876            speed_param: 0,
877            mirror_param: 0,
878            cycle_offset_param: 0,
879            time_param: 0,
880            speed: 1.0,
881            cycle_offset: 0.0,
882            ik_on_feet: false,
883            write_default_values: true,
884            looping: true,
885            mirror: false,
886        };
887        let controller = |clip: u32, to: i64, machine: i64, param_index: i64| UnityAnimatorController {
888            controller: ObjRef {
889                file: "f".into(),
890                path_id: 1,
891            },
892            name: "c".into(),
893            layers: vec![Layer {
894                state_machine: machine,
895                synchronized_layer: 0,
896                body_mask: [u32::MAX; 3],
897                skeleton_mask: vec![],
898                binding: 5,
899                blending_mode: 0,
900                default_weight: 1.0,
901                ik_pass: false,
902                synced_layer_affects_timing: false,
903            }],
904            state_machines: vec![StateMachine {
905                states: vec![state(clip, to)],
906                any_state_transitions: vec![],
907                selectors: vec![],
908                default_state: 0,
909                synchronized_layer_count: 1,
910            }],
911            parameters: vec![Parameter {
912                id: 9,
913                kind: 1,
914                index: param_index,
915            }],
916            default_floats: vec![0.0],
917            default_ints: vec![],
918            default_bools: vec![],
919            // the second slot is a null pointer: it still counts as a clip index
920            clips: vec![
921                Some(ObjRef {
922                    file: "f".into(),
923                    path_id: 2,
924                }),
925                None,
926            ],
927            behaviours: vec![],
928            tos: vec![(5, "Base Layer".into())],
929        };
930        assert!(controller(0, 0, 0, 0).check("c").is_ok());
931        assert!(controller(1, 0, 0, 0).check("c").is_ok());
932        assert!(controller(0, 0, 0, 0).name_of(5) == Some("Base Layer"));
933        let e = |c: UnityAnimatorController| c.check("c").unwrap_err().to_string();
934        assert!(e(controller(3, 0, 0, 0)).contains("plays clip 3 of 2"));
935        assert!(e(controller(0, 4, 0, 0)).contains("a transition to 4"));
936        // a selector destination is SELECTOR_BASE plus its index: with none, 30000 is no destination
937        assert!(e(controller(0, 30000, 0, 0)).contains("a transition to 30000"));
938        assert!(e(controller(0, 0, 2, 0)).contains("runs state machine 2 of 1"));
939        assert!(e(controller(0, 0, 0, 3)).contains("at 3 of 1 defaults"));
940    }
941}