1use crate::*;
2use boxcars;
3use std::sync::Arc;
4
5fn or_zero_boxcars_3f() -> boxcars::Vector3f {
6 boxcars::Vector3f {
7 x: 0.0,
8 y: 0.0,
9 z: 0.0,
10 }
11}
12
13type RigidBodyArrayResult<F> = SubtrActorResult<[F; 12]>;
14type RigidBodyQuaternionArrayResult<F> = SubtrActorResult<[F; 13]>;
15type RigidBodyBasisArrayResult<F> = SubtrActorResult<[F; 15]>;
16
17pub fn get_rigid_body_properties<F: TryFrom<f32>>(
19 rigid_body: &boxcars::RigidBody,
20) -> RigidBodyArrayResult<F>
21where
22 <F as TryFrom<f32>>::Error: std::fmt::Debug,
23{
24 let linear_velocity = rigid_body
25 .linear_velocity
26 .unwrap_or_else(or_zero_boxcars_3f);
27 let angular_velocity = rigid_body
28 .angular_velocity
29 .unwrap_or_else(or_zero_boxcars_3f);
30 let rotation = rigid_body.rotation;
31 let location = rigid_body.location;
32 let (rx, ry, rz) =
33 glam::quat(rotation.x, rotation.y, rotation.z, rotation.w).to_euler(glam::EulerRot::XYZ);
34 convert_all_floats!(
35 location.x,
36 location.y,
37 location.z,
38 rx,
39 ry,
40 rz,
41 linear_velocity.x,
42 linear_velocity.y,
43 linear_velocity.z,
44 angular_velocity.x,
45 angular_velocity.y,
46 angular_velocity.z,
47 )
48}
49
50pub fn get_rigid_body_properties_quaternion<F: TryFrom<f32>>(
52 rigid_body: &boxcars::RigidBody,
53) -> RigidBodyQuaternionArrayResult<F>
54where
55 <F as TryFrom<f32>>::Error: std::fmt::Debug,
56{
57 let linear_velocity = rigid_body
58 .linear_velocity
59 .unwrap_or_else(or_zero_boxcars_3f);
60 let angular_velocity = rigid_body
61 .angular_velocity
62 .unwrap_or_else(or_zero_boxcars_3f);
63 let rotation = rigid_body.rotation;
64 let location = rigid_body.location;
65 convert_all_floats!(
66 location.x,
67 location.y,
68 location.z,
69 rotation.x,
70 rotation.y,
71 rotation.z,
72 rotation.w,
73 linear_velocity.x,
74 linear_velocity.y,
75 linear_velocity.z,
76 angular_velocity.x,
77 angular_velocity.y,
78 angular_velocity.z,
79 )
80}
81
82pub fn get_rigid_body_properties_basis<F: TryFrom<f32>>(
84 rigid_body: &boxcars::RigidBody,
85) -> RigidBodyBasisArrayResult<F>
86where
87 <F as TryFrom<f32>>::Error: std::fmt::Debug,
88{
89 let linear_velocity = rigid_body
90 .linear_velocity
91 .unwrap_or_else(or_zero_boxcars_3f);
92 let angular_velocity = rigid_body
93 .angular_velocity
94 .unwrap_or_else(or_zero_boxcars_3f);
95 let rotation = rigid_body.rotation;
96 let location = rigid_body.location;
97 let quat = glam::quat(rotation.x, rotation.y, rotation.z, rotation.w);
98 let forward = quat.mul_vec3(glam::Vec3::X);
99 let up = quat.mul_vec3(glam::Vec3::Z);
100 convert_all_floats!(
101 location.x,
102 location.y,
103 location.z,
104 forward.x,
105 forward.y,
106 forward.z,
107 up.x,
108 up.y,
109 up.z,
110 linear_velocity.x,
111 linear_velocity.y,
112 linear_velocity.z,
113 angular_velocity.x,
114 angular_velocity.y,
115 angular_velocity.z,
116 )
117}
118
119pub fn get_rigid_body_properties_no_velocities<F: TryFrom<f32>>(
121 rigid_body: &boxcars::RigidBody,
122) -> SubtrActorResult<[F; 7]>
123where
124 <F as TryFrom<f32>>::Error: std::fmt::Debug,
125{
126 let rotation = rigid_body.rotation;
127 let location = rigid_body.location;
128 convert_all_floats!(
129 location.x, location.y, location.z, rotation.x, rotation.y, rotation.z, rotation.w
130 )
131}
132
133fn default_rb_state<F: TryFrom<f32>>() -> RigidBodyArrayResult<F>
134where
135 <F as TryFrom<f32>>::Error: std::fmt::Debug,
136{
137 convert_all!(
138 convert_float_conversion_error,
139 0.0,
140 0.0,
141 0.0,
142 0.0,
143 0.0,
144 0.0,
145 0.0,
146 0.0,
147 0.0,
148 0.0,
149 0.0,
150 0.0,
151 )
152}
153
154fn default_rb_state_quaternion<F: TryFrom<f32>>() -> RigidBodyQuaternionArrayResult<F>
155where
156 <F as TryFrom<f32>>::Error: std::fmt::Debug,
157{
158 convert_all_floats!(
159 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
160 )
161}
162
163fn default_rb_state_basis<F: TryFrom<f32>>() -> RigidBodyBasisArrayResult<F>
164where
165 <F as TryFrom<f32>>::Error: std::fmt::Debug,
166{
167 convert_all_floats!(
168 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,
169 )
170}
171
172fn default_rb_state_no_velocities<F: TryFrom<f32>>() -> SubtrActorResult<[F; 7]>
173where
174 <F as TryFrom<f32>>::Error: std::fmt::Debug,
175{
176 convert_all_floats!(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0,)
177}
178
179build_global_feature_adder!(
180 SecondsRemaining,
181 |_, processor: &dyn ProcessorView, _frame, _index, _current_time| {
182 convert_all_floats!(processor.get_seconds_remaining().unwrap_or(0) as f32)
183 },
184 "seconds remaining"
185);
186
187build_global_feature_adder!(
188 CurrentTime,
189 |_, _processor, _frame, _index, current_time: f32| { convert_all_floats!(current_time) },
190 "current time"
191);
192
193build_global_feature_adder!(
194 ReplicatedStateName,
195 |_, processor: &dyn ProcessorView, _frame, _index, _current_time| {
196 convert_all_floats!(processor.get_replicated_state_name().unwrap_or(0) as f32)
197 },
198 "game state"
199);
200
201build_global_feature_adder!(
202 ReplicatedGameStateTimeRemaining,
203 |_, processor: &dyn ProcessorView, _frame, _index, _current_time| {
204 convert_all_floats!(
205 processor
206 .get_replicated_game_state_time_remaining()
207 .unwrap_or(0) as f32
208 )
209 },
210 "kickoff countdown"
211);
212
213build_global_feature_adder!(
214 BallHasBeenHit,
215 |_, processor: &dyn ProcessorView, _frame, _index, _current_time| {
216 convert_all_floats!(if processor.get_ball_has_been_hit().unwrap_or(false) {
217 1.0
218 } else {
219 0.0
220 })
221 },
222 "ball has been hit"
223);
224
225build_global_feature_adder!(
226 FrameTime,
227 |_, _processor, frame: &boxcars::Frame, _index, _current_time| {
228 convert_all_floats!(frame.time)
229 },
230 "frame time"
231);
232
233build_global_feature_adder!(
234 BallRigidBody,
235 |_, processor: &dyn ProcessorView, _frame, _index, _current_time| {
236 processor
237 .get_normalized_ball_rigid_body()
238 .and_then(|rb| get_rigid_body_properties(&rb))
239 .or_else(|_| default_rb_state())
240 },
241 "Ball - position x",
242 "Ball - position y",
243 "Ball - position z",
244 "Ball - rotation x",
245 "Ball - rotation y",
246 "Ball - rotation z",
247 "Ball - linear velocity x",
248 "Ball - linear velocity y",
249 "Ball - linear velocity z",
250 "Ball - angular velocity x",
251 "Ball - angular velocity y",
252 "Ball - angular velocity z",
253);
254
255build_global_feature_adder!(
256 BallRigidBodyNoVelocities,
257 |_, processor: &dyn ProcessorView, _frame, _index, _current_time| {
258 processor
259 .get_normalized_ball_rigid_body()
260 .and_then(|rb| get_rigid_body_properties_no_velocities(&rb))
261 .or_else(|_| default_rb_state_no_velocities())
262 },
263 "Ball - position x",
264 "Ball - position y",
265 "Ball - position z",
266 "Ball - rotation x",
267 "Ball - rotation y",
268 "Ball - rotation z",
269 "Ball - rotation w",
270);
271
272build_global_feature_adder!(
273 VelocityAddedBallRigidBodyNoVelocities,
274 |_, processor: &dyn ProcessorView, _frame, _index, current_time: f32| {
275 processor
276 .get_velocity_applied_ball_rigid_body(current_time)
277 .and_then(|rb| get_rigid_body_properties_no_velocities(&rb))
278 .or_else(|_| default_rb_state_no_velocities())
279 },
280 "Ball - position x",
281 "Ball - position y",
282 "Ball - position z",
283 "Ball - rotation x",
284 "Ball - rotation y",
285 "Ball - rotation z",
286 "Ball - rotation w",
287);
288
289#[derive(derive_new::new)]
291pub struct InterpolatedBallRigidBodyNoVelocities<F> {
292 close_enough_to_frame_time: f32,
293 _zero: std::marker::PhantomData<F>,
294}
295
296impl<F> InterpolatedBallRigidBodyNoVelocities<F> {
297 pub fn arc_new(close_enough_to_frame_time: f32) -> Arc<Self> {
299 Arc::new(Self::new(close_enough_to_frame_time))
300 }
301}
302
303global_feature_adder!(
304 InterpolatedBallRigidBodyNoVelocities,
305 |s: &InterpolatedBallRigidBodyNoVelocities<F>,
306 processor: &dyn ProcessorView,
307 _frame: &boxcars::Frame,
308 _index,
309 current_time: f32| {
310 processor
311 .get_interpolated_ball_rigid_body(current_time, s.close_enough_to_frame_time)
312 .map(|v| get_rigid_body_properties_no_velocities(&v))
313 .unwrap_or_else(|_| default_rb_state_no_velocities())
314 },
315 "Ball - position x",
316 "Ball - position y",
317 "Ball - position z",
318 "Ball - rotation x",
319 "Ball - rotation y",
320 "Ball - rotation z",
321 "Ball - rotation w",
322);
323
324build_player_feature_adder!(
325 PlayerRigidBody,
326 |_, player_id: &PlayerId, processor: &dyn ProcessorView, _frame, _index, _current_time: f32| {
327 let rigid_body = processor.get_normalized_player_rigid_body(player_id);
328 if let Ok(rb) = rigid_body {
329 get_rigid_body_properties(&rb)
330 } else {
331 default_rb_state()
332 }
333 },
334 "position x",
335 "position y",
336 "position z",
337 "rotation x",
338 "rotation y",
339 "rotation z",
340 "linear velocity x",
341 "linear velocity y",
342 "linear velocity z",
343 "angular velocity x",
344 "angular velocity y",
345 "angular velocity z",
346);
347
348build_player_feature_adder!(
349 PlayerRigidBodyNoVelocities,
350 |_, player_id: &PlayerId, processor: &dyn ProcessorView, _frame, _index, _current_time: f32| {
351 let rigid_body = processor.get_normalized_player_rigid_body(player_id);
352 if let Ok(rb) = rigid_body {
353 get_rigid_body_properties_no_velocities(&rb)
354 } else {
355 default_rb_state_no_velocities()
356 }
357 },
358 "position x",
359 "position y",
360 "position z",
361 "rotation x",
362 "rotation y",
363 "rotation z",
364 "rotation w"
365);
366
367build_player_feature_adder!(
368 VelocityAddedPlayerRigidBodyNoVelocities,
369 |_, player_id: &PlayerId, processor: &dyn ProcessorView, _frame, _index, current_time: f32| {
370 let rigid_body = processor.get_velocity_applied_player_rigid_body(player_id, current_time);
371 if let Ok(rb) = rigid_body {
372 get_rigid_body_properties_no_velocities(&rb)
373 } else {
374 default_rb_state_no_velocities()
375 }
376 },
377 "position x",
378 "position y",
379 "position z",
380 "rotation x",
381 "rotation y",
382 "rotation z",
383 "rotation w"
384);
385
386#[derive(derive_new::new)]
388pub struct InterpolatedPlayerRigidBodyNoVelocities<F> {
389 close_enough_to_frame_time: f32,
390 _zero: std::marker::PhantomData<F>,
391}
392
393impl<F> InterpolatedPlayerRigidBodyNoVelocities<F> {
394 pub fn arc_new(close_enough_to_frame_time: f32) -> Arc<Self> {
396 Arc::new(Self::new(close_enough_to_frame_time))
397 }
398}
399
400player_feature_adder!(
401 InterpolatedPlayerRigidBodyNoVelocities,
402 |s: &InterpolatedPlayerRigidBodyNoVelocities<F>,
403 player_id: &PlayerId,
404 processor: &dyn ProcessorView,
405 _frame: &boxcars::Frame,
406 _index,
407 current_time: f32| {
408 processor
409 .get_interpolated_player_rigid_body(
410 player_id,
411 current_time,
412 s.close_enough_to_frame_time,
413 )
414 .map(|v| get_rigid_body_properties_no_velocities(&v))
415 .unwrap_or_else(|_| default_rb_state_no_velocities())
416 },
417 "i position x",
418 "i position y",
419 "i position z",
420 "i rotation x",
421 "i rotation y",
422 "i rotation z",
423 "i rotation w"
424);
425
426build_player_feature_adder!(
427 PlayerRelativeBallPosition,
428 |_, player_id: &PlayerId, processor: &dyn ProcessorView, _frame, _index, _current_time: f32| {
429 let relative_position = processor
430 .get_normalized_player_rigid_body(player_id)
431 .ok()
432 .zip(processor.get_normalized_ball_rigid_body().ok())
433 .map(|(player_rigid_body, ball_rigid_body)| {
434 vec_to_glam(&ball_rigid_body.location) - vec_to_glam(&player_rigid_body.location)
435 })
436 .unwrap_or(glam::f32::Vec3::ZERO);
437 convert_all_floats!(
438 relative_position.x,
439 relative_position.y,
440 relative_position.z
441 )
442 },
443 "relative ball position x",
444 "relative ball position y",
445 "relative ball position z"
446);
447
448build_player_feature_adder!(
449 PlayerRelativeBallVelocity,
450 |_, player_id: &PlayerId, processor: &dyn ProcessorView, _frame, _index, _current_time: f32| {
451 let relative_velocity = processor
452 .get_normalized_player_rigid_body(player_id)
453 .ok()
454 .zip(processor.get_normalized_ball_rigid_body().ok())
455 .map(|(player_rigid_body, ball_rigid_body)| {
456 vec_to_glam(
457 &ball_rigid_body
458 .linear_velocity
459 .unwrap_or_else(or_zero_boxcars_3f),
460 ) - vec_to_glam(
461 &player_rigid_body
462 .linear_velocity
463 .unwrap_or_else(or_zero_boxcars_3f),
464 )
465 })
466 .unwrap_or(glam::f32::Vec3::ZERO);
467 convert_all_floats!(
468 relative_velocity.x,
469 relative_velocity.y,
470 relative_velocity.z
471 )
472 },
473 "relative ball velocity x",
474 "relative ball velocity y",
475 "relative ball velocity z"
476);
477
478build_player_feature_adder!(
479 PlayerLocalRelativeBallPosition,
480 |_, player_id: &PlayerId, processor: &dyn ProcessorView, _frame, _index, _current_time: f32| {
481 let local_relative_position = processor
482 .get_normalized_player_rigid_body(player_id)
483 .ok()
484 .zip(processor.get_normalized_ball_rigid_body().ok())
485 .map(|(player_rigid_body, ball_rigid_body)| {
486 let player_rotation = player_rigid_body.rotation;
487 let player_quat = glam::quat(
488 player_rotation.x,
489 player_rotation.y,
490 player_rotation.z,
491 player_rotation.w,
492 );
493 let world_relative_position = vec_to_glam(&ball_rigid_body.location)
494 - vec_to_glam(&player_rigid_body.location);
495 player_quat.inverse().mul_vec3(world_relative_position)
496 })
497 .unwrap_or(glam::f32::Vec3::ZERO);
498 convert_all_floats!(
499 local_relative_position.x,
500 local_relative_position.y,
501 local_relative_position.z
502 )
503 },
504 "local relative ball position x",
505 "local relative ball position y",
506 "local relative ball position z"
507);
508
509build_player_feature_adder!(
510 PlayerLocalRelativeBallVelocity,
511 |_, player_id: &PlayerId, processor: &dyn ProcessorView, _frame, _index, _current_time: f32| {
512 let local_relative_velocity = processor
513 .get_normalized_player_rigid_body(player_id)
514 .ok()
515 .zip(processor.get_normalized_ball_rigid_body().ok())
516 .map(|(player_rigid_body, ball_rigid_body)| {
517 let player_rotation = player_rigid_body.rotation;
518 let player_quat = glam::quat(
519 player_rotation.x,
520 player_rotation.y,
521 player_rotation.z,
522 player_rotation.w,
523 );
524 let world_relative_velocity = vec_to_glam(
525 &ball_rigid_body
526 .linear_velocity
527 .unwrap_or_else(or_zero_boxcars_3f),
528 ) - vec_to_glam(
529 &player_rigid_body
530 .linear_velocity
531 .unwrap_or_else(or_zero_boxcars_3f),
532 );
533 player_quat.inverse().mul_vec3(world_relative_velocity)
534 })
535 .unwrap_or(glam::f32::Vec3::ZERO);
536 convert_all_floats!(
537 local_relative_velocity.x,
538 local_relative_velocity.y,
539 local_relative_velocity.z
540 )
541 },
542 "local relative ball velocity x",
543 "local relative ball velocity y",
544 "local relative ball velocity z"
545);
546
547build_player_feature_adder!(
548 PlayerBallDistance,
549 |_, player_id: &PlayerId, processor: &dyn ProcessorView, _frame, _index, _current_time: f32| {
550 let distance = processor
551 .get_normalized_player_rigid_body(player_id)
552 .ok()
553 .zip(processor.get_normalized_ball_rigid_body().ok())
554 .map(|(player_rigid_body, ball_rigid_body)| {
555 (vec_to_glam(&player_rigid_body.location) - vec_to_glam(&ball_rigid_body.location))
556 .length()
557 })
558 .unwrap_or(0.0);
559 convert_all_floats!(distance)
560 },
561 "distance to ball"
562);
563
564build_player_feature_adder!(
565 PlayerBoost,
566 |_, player_id: &PlayerId, processor: &dyn ProcessorView, _frame, _index, _current_time: f32| {
567 convert_all_floats!(processor.get_player_boost_level(player_id).unwrap_or(0.0))
568 },
569 "boost level (raw replay units)"
570);
571
572fn u8_get_f32(v: u8) -> SubtrActorResult<f32> {
573 Ok(v.into())
574}
575
576build_player_feature_adder!(
577 PlayerJump,
578 |_,
579 player_id: &PlayerId,
580 processor: &dyn ProcessorView,
581 _frame,
582 _frame_number,
583 _current_time: f32| {
584 convert_all_floats!(
585 processor
586 .get_dodge_active(player_id)
587 .and_then(u8_get_f32)
588 .unwrap_or(0.0),
589 processor
590 .get_jump_active(player_id)
591 .and_then(u8_get_f32)
592 .unwrap_or(0.0),
593 processor
594 .get_double_jump_active(player_id)
595 .and_then(u8_get_f32)
596 .unwrap_or(0.0),
597 )
598 },
599 "dodge active",
600 "jump active",
601 "double jump active"
602);
603
604build_player_feature_adder!(
605 PlayerAnyJump,
606 |_,
607 player_id: &PlayerId,
608 processor: &dyn ProcessorView,
609 _frame,
610 _frame_number,
611 _current_time: f32| {
612 let dodge_is_active = processor.get_dodge_active(player_id).unwrap_or(0) % 2;
613 let jump_is_active = processor.get_jump_active(player_id).unwrap_or(0) % 2;
614 let double_jump_is_active = processor.get_double_jump_active(player_id).unwrap_or(0) % 2;
615 let value: f32 = [dodge_is_active, jump_is_active, double_jump_is_active]
616 .into_iter()
617 .enumerate()
618 .map(|(index, is_active)| (1 << index) * is_active)
619 .sum::<u8>() as f32;
620 convert_all_floats!(value)
621 },
622 "any_jump_active"
623);
624
625build_player_feature_adder!(
626 PlayerDodgeRefreshed,
627 |_,
628 player_id: &PlayerId,
629 processor: &dyn ProcessorView,
630 _frame,
631 _frame_number,
632 _current_time: f32| {
633 let dodge_refresh_count = processor
634 .current_frame_dodge_refreshed_events()
635 .iter()
636 .filter(|event| &event.player == player_id)
637 .count() as f32;
638 convert_all_floats!(dodge_refresh_count)
639 },
640 "dodge refresh count"
641);
642
643const DEMOLISH_APPEARANCE_FRAME_COUNT: usize = 30;
644
645build_player_feature_adder!(
646 PlayerDemolishedBy,
647 |_,
648 player_id: &PlayerId,
649 processor: &dyn ProcessorView,
650 _frame,
651 frame_number,
652 _current_time: f32| {
653 let demolisher_index = processor
654 .demolishes()
655 .iter()
656 .find(|demolish_info| {
657 &demolish_info.victim == player_id
658 && frame_number - demolish_info.frame < DEMOLISH_APPEARANCE_FRAME_COUNT
659 })
660 .map(|demolish_info| {
661 processor
662 .iter_player_ids_in_order()
663 .position(|player_id| player_id == &demolish_info.attacker)
664 .unwrap_or_else(|| processor.iter_player_ids_in_order().count())
665 })
666 .and_then(|v| i32::try_from(v).ok())
667 .unwrap_or(-1);
668 convert_all_floats!(demolisher_index as f32)
669 },
670 "player demolished by"
671);
672
673build_player_feature_adder!(
674 PlayerRigidBodyQuaternions,
675 |_, player_id: &PlayerId, processor: &dyn ProcessorView, _frame, _index, _current_time: f32| {
676 let rigid_body = processor.get_normalized_player_rigid_body(player_id);
677 if let Ok(rb) = rigid_body {
678 let rotation = rb.rotation;
679 let location = rb.location;
680 convert_all_floats!(
681 location.x, location.y, location.z, rotation.x, rotation.y, rotation.z, rotation.w
682 )
683 } else {
684 convert_all_floats!(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0)
685 }
686 },
687 "position x",
688 "position y",
689 "position z",
690 "quaternion x",
691 "quaternion y",
692 "quaternion z",
693 "quaternion w"
694);
695
696build_player_feature_adder!(
697 PlayerRigidBodyQuaternionVelocities,
698 |_, player_id: &PlayerId, processor: &dyn ProcessorView, _frame, _index, _current_time: f32| {
699 let rigid_body = processor.get_normalized_player_rigid_body(player_id);
700 if let Ok(rb) = rigid_body {
701 get_rigid_body_properties_quaternion(&rb)
702 } else {
703 default_rb_state_quaternion()
704 }
705 },
706 "position x",
707 "position y",
708 "position z",
709 "quaternion x",
710 "quaternion y",
711 "quaternion z",
712 "quaternion w",
713 "linear velocity x",
714 "linear velocity y",
715 "linear velocity z",
716 "angular velocity x",
717 "angular velocity y",
718 "angular velocity z",
719);
720
721build_player_feature_adder!(
722 PlayerRigidBodyBasis,
723 |_, player_id: &PlayerId, processor: &dyn ProcessorView, _frame, _index, _current_time: f32| {
724 let rigid_body = processor.get_normalized_player_rigid_body(player_id);
725 if let Ok(rb) = rigid_body {
726 get_rigid_body_properties_basis(&rb)
727 } else {
728 default_rb_state_basis()
729 }
730 },
731 "position x",
732 "position y",
733 "position z",
734 "forward x",
735 "forward y",
736 "forward z",
737 "up x",
738 "up y",
739 "up z",
740 "linear velocity x",
741 "linear velocity y",
742 "linear velocity z",
743 "angular velocity x",
744 "angular velocity y",
745 "angular velocity z",
746);
747
748build_global_feature_adder!(
749 BallRigidBodyQuaternions,
750 |_, processor: &dyn ProcessorView, _frame, _index, _current_time| {
751 match processor.get_normalized_ball_rigid_body() {
752 Ok(rb) => {
753 let rotation = rb.rotation;
754 let location = rb.location;
755 convert_all_floats!(
756 location.x, location.y, location.z, rotation.x, rotation.y, rotation.z,
757 rotation.w
758 )
759 }
760 Err(_) => convert_all_floats!(0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 1.0),
761 }
762 },
763 "Ball - position x",
764 "Ball - position y",
765 "Ball - position z",
766 "Ball - quaternion x",
767 "Ball - quaternion y",
768 "Ball - quaternion z",
769 "Ball - quaternion w"
770);
771
772build_global_feature_adder!(
773 BallRigidBodyQuaternionVelocities,
774 |_, processor: &dyn ProcessorView, _frame, _index, _current_time| {
775 processor
776 .get_normalized_ball_rigid_body()
777 .and_then(|rb| get_rigid_body_properties_quaternion(&rb))
778 .or_else(|_| default_rb_state_quaternion())
779 },
780 "Ball - position x",
781 "Ball - position y",
782 "Ball - position z",
783 "Ball - quaternion x",
784 "Ball - quaternion y",
785 "Ball - quaternion z",
786 "Ball - quaternion w",
787 "Ball - linear velocity x",
788 "Ball - linear velocity y",
789 "Ball - linear velocity z",
790 "Ball - angular velocity x",
791 "Ball - angular velocity y",
792 "Ball - angular velocity z",
793);
794
795build_global_feature_adder!(
796 BallRigidBodyBasis,
797 |_, processor: &dyn ProcessorView, _frame, _index, _current_time| {
798 processor
799 .get_normalized_ball_rigid_body()
800 .and_then(|rb| get_rigid_body_properties_basis(&rb))
801 .or_else(|_| default_rb_state_basis())
802 },
803 "Ball - position x",
804 "Ball - position y",
805 "Ball - position z",
806 "Ball - forward x",
807 "Ball - forward y",
808 "Ball - forward z",
809 "Ball - up x",
810 "Ball - up y",
811 "Ball - up z",
812 "Ball - linear velocity x",
813 "Ball - linear velocity y",
814 "Ball - linear velocity z",
815 "Ball - angular velocity x",
816 "Ball - angular velocity y",
817 "Ball - angular velocity z",
818);