1use 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
13struct 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 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 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 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 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 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 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 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 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 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 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 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 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 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 #[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 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 #[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 #[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 #[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 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 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}