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