subtr-actor 0.8.5

Rocket League replay transformer
Documentation
use super::*;

fn rigid_body(position: glam::Vec3, velocity: glam::Vec3) -> boxcars::RigidBody {
    boxcars::RigidBody {
        sleeping: false,
        location: glam_to_vec(&position),
        rotation: boxcars::Quaternion {
            x: 0.0,
            y: 0.0,
            z: 0.0,
            w: 1.0,
        },
        linear_velocity: Some(glam_to_vec(&velocity)),
        angular_velocity: Some(glam_to_vec(&glam::Vec3::ZERO)),
    }
}

fn player(id: u64, is_team_0: bool, position: glam::Vec3, velocity: glam::Vec3) -> PlayerSample {
    PlayerSample {
        player_id: boxcars::RemoteId::Steam(id),
        is_team_0,
        rigid_body: Some(rigid_body(position, velocity)),
        boost_amount: None,
        last_boost_amount: None,
        boost_active: false,
        dodge_active: false,
        powerslide_active: false,
        match_goals: None,
        match_assists: None,
        match_saves: None,
        match_shots: None,
        match_score: None,
    }
}

fn frame(frame_number: usize, time: f32) -> FrameInfo {
    FrameInfo {
        frame_number,
        time,
        dt: 0.1,
        seconds_remaining: None,
    }
}

fn players(players: Vec<PlayerSample>) -> PlayerFrameState {
    PlayerFrameState { players }
}

#[test]
fn bump_detector_credits_player_with_clear_directional_impulse() {
    let mut calculator = BumpCalculator::new();
    let initiator_id = boxcars::RemoteId::Steam(1);
    let victim_id = boxcars::RemoteId::Steam(2);

    calculator
        .update(
            &frame(0, 0.0),
            &players(vec![
                player(
                    1,
                    true,
                    glam::Vec3::new(0.0, 0.0, 17.0),
                    glam::Vec3::new(1200.0, 0.0, 0.0),
                ),
                player(
                    2,
                    false,
                    glam::Vec3::new(260.0, 0.0, 17.0),
                    glam::Vec3::ZERO,
                ),
            ]),
            &FrameEventsState::default(),
            true,
        )
        .unwrap();

    calculator
        .update(
            &frame(1, 0.1),
            &players(vec![
                player(
                    1,
                    true,
                    glam::Vec3::new(120.0, 0.0, 17.0),
                    glam::Vec3::new(650.0, 0.0, 0.0),
                ),
                player(
                    2,
                    false,
                    glam::Vec3::new(300.0, 0.0, 17.0),
                    glam::Vec3::new(700.0, 0.0, 0.0),
                ),
            ]),
            &FrameEventsState::default(),
            true,
        )
        .unwrap();

    assert_eq!(calculator.events().len(), 1);
    let event = &calculator.events()[0];
    assert_eq!(event.initiator, initiator_id);
    assert_eq!(event.victim, victim_id);
    assert!(!event.is_team_bump);
    assert!(event.confidence > 0.4);

    assert_eq!(
        calculator
            .player_stats()
            .get(&boxcars::RemoteId::Steam(1))
            .unwrap()
            .bumps_inflicted,
        1
    );
    assert_eq!(
        calculator
            .player_stats()
            .get(&boxcars::RemoteId::Steam(2))
            .unwrap()
            .bumps_taken,
        1
    );
    assert_eq!(calculator.team_zero_stats().bumps_inflicted, 1);
}

#[test]
fn bump_detector_ignores_ambiguous_or_weak_contacts() {
    let mut calculator = BumpCalculator::new();

    calculator
        .update(
            &frame(0, 0.0),
            &players(vec![
                player(
                    1,
                    true,
                    glam::Vec3::new(0.0, 0.0, 17.0),
                    glam::Vec3::new(200.0, 0.0, 0.0),
                ),
                player(
                    2,
                    false,
                    glam::Vec3::new(240.0, 0.0, 17.0),
                    glam::Vec3::new(-200.0, 0.0, 0.0),
                ),
            ]),
            &FrameEventsState::default(),
            true,
        )
        .unwrap();

    calculator
        .update(
            &frame(1, 0.1),
            &players(vec![
                player(
                    1,
                    true,
                    glam::Vec3::new(20.0, 0.0, 17.0),
                    glam::Vec3::new(120.0, 0.0, 0.0),
                ),
                player(
                    2,
                    false,
                    glam::Vec3::new(220.0, 0.0, 17.0),
                    glam::Vec3::new(-120.0, 0.0, 0.0),
                ),
            ]),
            &FrameEventsState::default(),
            true,
        )
        .unwrap();

    assert!(calculator.events().is_empty());
    assert!(calculator.player_stats().is_empty());
}

#[test]
fn bump_detector_suppresses_same_pair_repeats() {
    let mut calculator = BumpCalculator::new();

    let samples = [
        (
            glam::Vec3::new(0.0, 0.0, 17.0),
            glam::Vec3::new(1200.0, 0.0, 0.0),
            glam::Vec3::new(260.0, 0.0, 17.0),
            glam::Vec3::ZERO,
        ),
        (
            glam::Vec3::new(120.0, 0.0, 17.0),
            glam::Vec3::new(1200.0, 0.0, 0.0),
            glam::Vec3::new(300.0, 0.0, 17.0),
            glam::Vec3::new(700.0, 0.0, 0.0),
        ),
        (
            glam::Vec3::new(240.0, 0.0, 17.0),
            glam::Vec3::new(650.0, 0.0, 0.0),
            glam::Vec3::new(420.0, 0.0, 17.0),
            glam::Vec3::new(1400.0, 0.0, 0.0),
        ),
    ];

    for (
        frame_number,
        (initiator_position, initiator_velocity, victim_position, victim_velocity),
    ) in samples.into_iter().enumerate()
    {
        calculator
            .update(
                &frame(frame_number, frame_number as f32 * 0.1),
                &players(vec![
                    player(1, true, initiator_position, initiator_velocity),
                    player(2, false, victim_position, victim_velocity),
                ]),
                &FrameEventsState::default(),
                true,
            )
            .unwrap();
    }

    assert_eq!(calculator.events().len(), 1);
}