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    NO_DESTINATION, Parameter, SELECTOR_BASE, SelectorState, SelectorTransition, SkeletonBone, State,
7    StateMachine, 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: Some(f.uint(t, "m_Destination")?)
525                                    .filter(|&d| d != NO_DESTINATION),
526                                conditions: conditions(f, t, "m_ConditionConstantArray")?,
527                            })
528                        })
529                        .collect::<Result<_>>()?,
530                    full_path_id: f.uint(s, "m_FullPathID")?,
531                    is_entry: f.flag(s, "m_IsEntry")?,
532                })
533            })
534            .collect::<Result<_>>()?,
535        default_state: f.int(m, "m_DefaultState")?,
536        synchronized_layer_count: f.int(m, "m_SynchronizedLayerCount")?,
537    })
538}
539
540fn layer(f: &Fields, l: &Value) -> Result<Layer> {
541    let l = f.data(l)?;
542    let mask = f.get(l, "m_BodyMask")?;
543    Ok(Layer {
544        state_machine: f.int(l, "m_StateMachineIndex")?,
545        synchronized_layer: f.int(l, "m_StateMachineSynchronizedLayerIndex")?,
546        body_mask: [
547            f.uint(mask, "word0")?,
548            f.uint(mask, "word1")?,
549            f.uint(mask, "word2")?,
550        ],
551        skeleton_mask: f
552            .list(f.data(f.get(l, "m_SkeletonMask")?)?, "m_Data")?
553            .iter()
554            .map(|e| Ok((f.uint(e, "m_PathHash")?, f.float(e, "m_Weight")?)))
555            .collect::<Result<_>>()?,
556        binding: f.uint(l, "m_Binding")?,
557        blending_mode: f.int(l, "(int&)m_LayerBlendingMode")?,
558        default_weight: f.float(l, "m_DefaultWeight")?,
559        ik_pass: f.flag(l, "m_IKPass")?,
560        synced_layer_affects_timing: f.flag(l, "m_SyncedLayerAffectsTiming")?,
561    })
562}
563
564impl UnityAnimatorController {
565    /// The AnimatorController object `r`.
566    pub fn read(player: &Player, r: &ObjRef) -> Result<UnityAnimatorController> {
567        let v = player.decode(r)?;
568        let name = v.get("m_Name").and_then(Value::as_str).unwrap_or("").to_owned();
569        let what = format!("AnimatorController {}/{} {name:?}", r.file, r.path_id);
570        let f = Fields { what: &what };
571        let c = f.get(&v, "m_Controller")?;
572        let values = f.data(f.get(c, "m_Values")?)?;
573        let defaults = f.data(f.get(c, "m_DefaultValues")?)?;
574        let pointers = |k: &str| -> Result<Vec<ObjRef>> {
575            let mut out = Vec::new();
576            for p in f.list(&v, k)? {
577                if let Some(o) = player.resolve(&r.file, p)? {
578                    out.push(o);
579                }
580            }
581            Ok(out)
582        };
583        let controller = UnityAnimatorController {
584            controller: r.clone(),
585            name,
586            layers: f
587                .list(c, "m_LayerArray")?
588                .iter()
589                .map(|l| layer(&f, l))
590                .collect::<Result<_>>()?,
591            state_machines: f
592                .list(c, "m_StateMachineArray")?
593                .iter()
594                .map(|m| state_machine(&f, m))
595                .collect::<Result<_>>()?,
596            parameters: f
597                .list(values, "m_ValueArray")?
598                .iter()
599                .map(|p| {
600                    Ok(Parameter {
601                        id: f.uint(p, "m_ID")?,
602                        kind: f.int(p, "m_Type")?,
603                        index: f.int(p, "m_Index")?,
604                    })
605                })
606                .collect::<Result<_>>()?,
607            default_floats: f.floats(defaults, "m_FloatValues")?,
608            default_ints: f.ints(defaults, "m_IntValues")?,
609            default_bools: f.bools(defaults, "m_BoolValues")?,
610            clips: f
611                .list(&v, "m_AnimationClips")?
612                .iter()
613                .map(|p| player.resolve(&r.file, p))
614                .collect::<Result<_>>()?,
615            behaviours: pointers("m_StateMachineBehaviours")?,
616            tos: f.tos(&v, "m_TOS")?,
617        };
618        controller.check(&what)?;
619        Ok(controller)
620    }
621
622    /// The references inside the controller against what they index: layers' state machines, transitions' destinations,
623    /// blend trees' children and clips, parameters' defaults.
624    fn check(&self, what: &str) -> Result<()> {
625        let bad = |why: String| invalid(format!("{what}: {why}"));
626        for (k, l) in self.layers.iter().enumerate() {
627            if usize::try_from(l.state_machine).map_or(true, |i| i >= self.state_machines.len()) {
628                return Err(bad(format!(
629                    "layer {k} runs state machine {} of {}",
630                    l.state_machine,
631                    self.state_machines.len()
632                )));
633            }
634        }
635        for (m, machine) in self.state_machines.iter().enumerate() {
636            let states = machine.states.len() as i64;
637            let selectors = machine.selectors.len() as i64;
638            // a destination is a state (below SELECTOR_BASE) or SELECTOR_BASE plus a selector node (an exit, or an entry
639            // of another machine)
640            let reaches = |d: i64| {
641                (0..states).contains(&d)
642                    || (SELECTOR_BASE..SELECTOR_BASE.saturating_add(selectors)).contains(&d)
643            };
644            for t in machine
645                .states
646                .iter()
647                .flat_map(|s| &s.transitions)
648                .chain(&machine.any_state_transitions)
649            {
650                if !reaches(t.destination) {
651                    return Err(bad(format!(
652                        "state machine {m}: a transition to {} of {states} states and {selectors} selectors",
653                        t.destination
654                    )));
655                }
656            }
657            for selector in &machine.selectors {
658                for t in &selector.transitions {
659                    match t.destination {
660                        Some(d) if reaches(i64::from(d)) => {}
661                        Some(d) => {
662                            return Err(bad(format!(
663                                "state machine {m}: a selector transition to {d} of {states} states and {selectors} selectors"
664                            )));
665                        }
666                        // an entry node with nowhere to enter: the state machine of an empty layer has no state to start in
667                        None if selector.is_entry => {}
668                        None => {
669                            return Err(bad(format!(
670                                "state machine {m}: an exit selector transition to no destination"
671                            )));
672                        }
673                    }
674                }
675            }
676            for s in &machine.states {
677                for tree in &s.blend_trees {
678                    for n in tree {
679                        if n.children.iter().any(|&c| c as usize >= tree.len()) {
680                            return Err(bad(format!(
681                                "state machine {m}: a blend tree child beyond its {} nodes",
682                                tree.len()
683                            )));
684                        }
685                        if n.children.is_empty() && n.clip != u32::MAX && n.clip as usize >= self.clips.len()
686                        {
687                            return Err(bad(format!(
688                                "state machine {m}: a blend tree leaf plays clip {} of {}",
689                                n.clip,
690                                self.clips.len()
691                            )));
692                        }
693                    }
694                }
695            }
696        }
697        for p in &self.parameters {
698            let count = match p.kind {
699                1 => self.default_floats.len(),
700                3 => self.default_ints.len(),
701                4 | 9 => self.default_bools.len(),
702                k => return Err(bad(format!("a parameter of kind {k}"))),
703            };
704            if usize::try_from(p.index).map_or(true, |i| i >= count) {
705                return Err(bad(format!(
706                    "a parameter of kind {} at {} of {count} defaults",
707                    p.kind, p.index
708                )));
709            }
710        }
711        Ok(())
712    }
713}
714
715#[cfg(test)]
716mod tests {
717    use super::*;
718    use std::sync::Arc;
719
720    fn s(fields: &[(&str, Value)]) -> Value {
721        Value::Struct(fields.iter().map(|(k, v)| (Arc::from(*k), v.clone())).collect())
722    }
723
724    fn list(items: Vec<Value>) -> Value {
725        Value::Array(Array::Values(items))
726    }
727
728    fn vec3(x: f32, y: f32, z: f32) -> Value {
729        s(&[
730            ("x", Value::Float(x)),
731            ("y", Value::Float(y)),
732            ("z", Value::Float(z)),
733        ])
734    }
735
736    fn quat(x: f32, y: f32, z: f32, w: f32) -> Value {
737        s(&[
738            ("x", Value::Float(x)),
739            ("y", Value::Float(y)),
740            ("z", Value::Float(z)),
741            ("w", Value::Float(w)),
742        ])
743    }
744
745    /// A skeleton of two nodes, the second under the first with the one axes entry.
746    #[test]
747    fn a_skeleton_reads_with_its_nodes_ids_and_axes() {
748        let axes = s(&[
749            ("m_PreQ", quat(0.0, 0.0, 0.0, 1.0)),
750            ("m_PostQ", quat(0.5, 0.5, 0.5, 0.5)),
751            ("m_Sgn", vec3(1.0, -1.0, 1.0)),
752            (
753                "m_Limit",
754                s(&[("m_Min", vec3(-1.0, -2.0, -3.0)), ("m_Max", vec3(1.0, 2.0, 3.0))]),
755            ),
756            ("m_Length", Value::Float(0.25)),
757            ("m_Type", Value::Int(1)),
758        ]);
759        let node = |p: i64, a: i64| s(&[("m_ParentId", Value::Int(p)), ("m_AxesId", Value::Int(a))]);
760        let wrap = |nodes: Vec<Value>, ids: Vec<u32>, axes: Vec<Value>| {
761            s(&[(
762                "data",
763                s(&[
764                    ("m_Node", list(nodes)),
765                    ("m_ID", Value::Array(Array::U32(ids))),
766                    ("m_AxesArray", list(axes)),
767                ]),
768            )])
769        };
770        let f = Fields { what: "t" };
771        let sk = f
772            .skeleton(&wrap(
773                vec![node(-1, -1), node(0, 0)],
774                vec![7, 9],
775                vec![axes.clone()],
776            ))
777            .unwrap();
778        assert_eq!(sk.nodes, vec![(-1, -1), (0, 0)]);
779        assert_eq!(sk.ids, vec![7, 9]);
780        assert_eq!(sk.axes[0].sgn, [1.0, -1.0, 1.0]);
781        assert_eq!(
782            (sk.axes[0].min, sk.axes[0].max),
783            ([-1.0, -2.0, -3.0], [1.0, 2.0, 3.0])
784        );
785        assert_eq!((sk.axes[0].length, sk.axes[0].kind), (0.25, 1));
786        // an id missing, a parent and an axes index out of range
787        let e = |w: Value| f.skeleton(&w).unwrap_err().to_string();
788        assert!(
789            e(wrap(vec![node(-1, -1), node(0, 0)], vec![7], vec![axes.clone()]))
790                .contains("1 node ids for 2 nodes")
791        );
792        assert!(e(wrap(vec![node(5, -1)], vec![7], vec![])).contains("names parent 5"));
793        assert!(e(wrap(vec![node(-1, 0)], vec![7], vec![])).contains("axes 0"));
794    }
795
796    /// Fields are required and typed: a missing one and one of another type are errors naming the field and the object.
797    #[test]
798    fn fields_are_required_and_typed() {
799        let f = Fields {
800            what: "Avatar a/1 \"x\"",
801        };
802        let v = s(&[("m_Scale", Value::Float(2.0)), ("m_Name", Value::Int(3))]);
803        assert_eq!(f.float(&v, "m_Scale").unwrap(), 2.0);
804        let missing = f.float(&v, "m_Other").unwrap_err().to_string();
805        assert!(
806            missing.contains("Avatar a/1") && missing.contains("no m_Other"),
807            "{missing}"
808        );
809        let mistyped = f.string(&v, "m_Name").unwrap_err().to_string();
810        assert!(mistyped.contains("m_Name is not a string"), "{mistyped}");
811        assert!(f.uint(&s(&[("k", Value::Int(-1))]), "k").is_err());
812        assert!(
813            f.uints(&s(&[("k", Value::Array(Array::I32(vec![1, -2])))]), "k")
814                .is_err()
815        );
816        assert_eq!(
817            f.ints(&s(&[("k", Value::Array(Array::I32(vec![1, -2])))]), "k")
818                .unwrap(),
819            vec![1, -2]
820        );
821        assert!(f.ints(&s(&[("k", list(vec![]))]), "k").unwrap().is_empty());
822    }
823
824    /// The name table is pairs of a hash and a name.
825    #[test]
826    fn name_tables_read_as_pairs() {
827        let f = Fields { what: "t" };
828        let pair =
829            |h: u32, n: &str| Value::Pair(Box::new((Value::UInt(u64::from(h)), Value::String(n.into()))));
830        let v = s(&[("m_TOS", list(vec![pair(1, "a"), pair(2, "b/c")]))]);
831        assert_eq!(
832            f.tos(&v, "m_TOS").unwrap(),
833            vec![(1, "a".to_owned()), (2, "b/c".to_owned())]
834        );
835        let bad = s(&[("m_TOS", list(vec![Value::Int(3)]))]);
836        assert!(
837            f.tos(&bad, "m_TOS")
838                .unwrap_err()
839                .to_string()
840                .contains("not a pair")
841        );
842    }
843
844    /// A controller's internal references are checked: a layer's state machine, a transition's destination, a blend
845    /// tree's child and clip, a parameter's default.
846    #[test]
847    fn a_controller_is_checked_against_what_its_indices_name() {
848        let leaf = |clip: u32| BlendNode {
849            blend_type: 0,
850            event_id: u32::MAX,
851            event_y_id: u32::MAX,
852            children: vec![],
853            thresholds: vec![],
854            positions: vec![],
855            magnitudes: vec![],
856            pair_vectors: vec![],
857            pair_avg_mag_inv: vec![],
858            neighbors: vec![],
859            direct_events: vec![],
860            normalized_blend_values: false,
861            clip,
862            duration: 1.0,
863            cycle_offset: 0.0,
864            mirror: false,
865        };
866        let state = |clip: u32, to: i64| State {
867            transitions: vec![Transition {
868                conditions: vec![],
869                destination: to,
870                full_path_id: 0,
871                id: 0,
872                user_id: 0,
873                duration: 0.1,
874                offset: 0.0,
875                exit_time: 0.0,
876                has_exit_time: false,
877                has_fixed_duration: true,
878                interruption_source: 0,
879                ordered_interruption: true,
880                can_transition_to_self: true,
881            }],
882            blend_tree_index: vec![0],
883            blend_trees: vec![vec![leaf(clip)]],
884            name_id: 1,
885            path_id: 1,
886            full_path_id: 1,
887            tag_id: 0,
888            speed_param: 0,
889            mirror_param: 0,
890            cycle_offset_param: 0,
891            time_param: 0,
892            speed: 1.0,
893            cycle_offset: 0.0,
894            ik_on_feet: false,
895            write_default_values: true,
896            looping: true,
897            mirror: false,
898        };
899        let controller = |clip: u32, to: i64, machine: i64, param_index: i64| UnityAnimatorController {
900            controller: ObjRef {
901                file: "f".into(),
902                path_id: 1,
903            },
904            name: "c".into(),
905            layers: vec![Layer {
906                state_machine: machine,
907                synchronized_layer: 0,
908                body_mask: [u32::MAX; 3],
909                skeleton_mask: vec![],
910                binding: 5,
911                blending_mode: 0,
912                default_weight: 1.0,
913                ik_pass: false,
914                synced_layer_affects_timing: false,
915            }],
916            state_machines: vec![StateMachine {
917                states: vec![state(clip, to)],
918                any_state_transitions: vec![],
919                selectors: vec![],
920                default_state: 0,
921                synchronized_layer_count: 1,
922            }],
923            parameters: vec![Parameter {
924                id: 9,
925                kind: 1,
926                index: param_index,
927            }],
928            default_floats: vec![0.0],
929            default_ints: vec![],
930            default_bools: vec![],
931            // the second slot is a null pointer: it still counts as a clip index
932            clips: vec![
933                Some(ObjRef {
934                    file: "f".into(),
935                    path_id: 2,
936                }),
937                None,
938            ],
939            behaviours: vec![],
940            tos: vec![(5, "Base Layer".into())],
941        };
942        assert!(controller(0, 0, 0, 0).check("c").is_ok());
943        assert!(controller(1, 0, 0, 0).check("c").is_ok());
944        assert!(controller(0, 0, 0, 0).name_of(5) == Some("Base Layer"));
945        let e = |c: UnityAnimatorController| c.check("c").unwrap_err().to_string();
946        assert!(e(controller(3, 0, 0, 0)).contains("plays clip 3 of 2"));
947        assert!(e(controller(0, 4, 0, 0)).contains("a transition to 4"));
948        // a selector destination is SELECTOR_BASE plus its index: with none, 30000 is no destination
949        assert!(e(controller(0, 30000, 0, 0)).contains("a transition to 30000"));
950        assert!(e(controller(0, 0, 2, 0)).contains("runs state machine 2 of 1"));
951        assert!(e(controller(0, 0, 0, 3)).contains("at 3 of 1 defaults"));
952    }
953
954    /// The machine of an empty layer: no states, an entry node whose one transition stores `0xFFFFFFFF` and an exit node
955    /// that leads to selector node 0. A census of the 699 compiled controllers in 529 serialized files of PEAK, Sledding
956    /// Game, Big Walk and SkateBIRD found exactly this in 16 machines (`Ambience` and `Scout`, in each of PEAK's seven
957    /// level bundles and its loose `resources.assets`), and the destination nowhere else among the 1,671 selector
958    /// transitions.
959    fn empty_layer_machine(entry_destination: u64, exit_destination: u64) -> Value {
960        let transition = |destination: u64| {
961            s(&[(
962                "data",
963                s(&[
964                    ("m_Destination", Value::UInt(destination)),
965                    ("m_ConditionConstantArray", list(vec![])),
966                ]),
967            )])
968        };
969        let selector = |entry: bool, destination: u64| {
970            s(&[(
971                "data",
972                s(&[
973                    ("m_TransitionConstantArray", list(vec![transition(destination)])),
974                    ("m_FullPathID", Value::UInt(756_556_552)),
975                    ("m_IsEntry", Value::Bool(entry)),
976                ]),
977            )])
978        };
979        s(&[(
980            "data",
981            s(&[
982                ("m_StateConstantArray", list(vec![])),
983                ("m_AnyStateTransitionConstantArray", list(vec![])),
984                (
985                    "m_SelectorStateConstantArray",
986                    list(vec![
987                        selector(true, entry_destination),
988                        selector(false, exit_destination),
989                    ]),
990                ),
991                ("m_DefaultState", Value::Int(0)),
992                ("m_SynchronizedLayerCount", Value::Int(0)),
993            ]),
994        )])
995    }
996
997    /// A selector transition that stores `0xFFFFFFFF` leads nowhere (`None`); the controller holding it passes its
998    /// checks when it is an entry node's, and a stored destination off the end of the machine does not.
999    #[test]
1000    fn a_selector_transition_to_nothing_is_no_destination() {
1001        let f = Fields { what: "t" };
1002        let machine = state_machine(&f, &empty_layer_machine(u64::from(NO_DESTINATION), 30_000)).unwrap();
1003        assert!(machine.states.is_empty());
1004        assert_eq!(machine.selectors.len(), 2);
1005        assert!(machine.selectors[0].is_entry);
1006        assert_eq!(machine.selectors[0].transitions[0].destination, None);
1007        assert!(!machine.selectors[1].is_entry);
1008        assert_eq!(machine.selectors[1].transitions[0].destination, Some(30000));
1009
1010        let controller = |machine: StateMachine| UnityAnimatorController {
1011            controller: ObjRef {
1012                file: "f".into(),
1013                path_id: 1,
1014            },
1015            name: "Scout".into(),
1016            layers: vec![Layer {
1017                state_machine: 0,
1018                synchronized_layer: 0,
1019                body_mask: [u32::MAX; 3],
1020                skeleton_mask: vec![],
1021                binding: 5,
1022                blending_mode: 0,
1023                default_weight: 1.0,
1024                ik_pass: false,
1025                synced_layer_affects_timing: false,
1026            }],
1027            state_machines: vec![machine],
1028            parameters: vec![],
1029            default_floats: vec![],
1030            default_ints: vec![],
1031            default_bools: vec![],
1032            clips: vec![],
1033            behaviours: vec![],
1034            tos: vec![],
1035        };
1036        assert!(controller(machine.clone()).check("c").is_ok());
1037
1038        // no destination is an entry node's: an exit node without one, and a destination past the machine, are refused
1039        let mut exit_to_nowhere = machine.clone();
1040        exit_to_nowhere.selectors[1].transitions[0].destination = None;
1041        let e = controller(exit_to_nowhere).check("c").unwrap_err().to_string();
1042        assert!(e.contains("an exit selector transition to no destination"), "{e}");
1043        let mut past_the_end = machine;
1044        past_the_end.selectors[0].transitions[0].destination = Some(30002);
1045        let e = controller(past_the_end).check("c").unwrap_err().to_string();
1046        assert!(
1047            e.contains("a selector transition to 30002 of 0 states and 2 selectors"),
1048            "{e}"
1049        );
1050    }
1051}