1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
use serde::{Deserialize, Serialize};
use spring_ai_sys::COMMAND_TO_ID_ENGINE;

use crate::ai_interface::{
    callback::{
        command::{
            command_data::{
                path::{
                    FreePathCommandData, GetApproximateLengthPathCommandData,
                    GetNextWaypointPathCommandData, InitPathCommandData,
                },
                CommandData,
            },
            command_topic::CommandTopic,
        },
        engine::handle_command,
    },
    AIInterface,
};

#[derive(Debug, Copy, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
pub struct Path {
    ai_id: i32,
    path_id: i32,
}

impl AIInterface {
    pub fn new_path(
        &self,
        start_pos: [f32; 3],
        end_pos: [f32; 3],
        path_type: i32,
        goal_radius: f32,
    ) -> Result<Path, &'static str> {
        Path::new(self, start_pos, end_pos, path_type, goal_radius)
    }

    pub fn path_length(
        &self,
        start_pos: [f32; 3],
        end_pos: [f32; 3],
        path_type: i32,
        goal_radius: f32,
    ) -> Result<f32, &'static str> {
        let mut command_c_data = GetApproximateLengthPathCommandData {
            start_pos,
            end_pos,
            path_type,
            goal_radius,
        }
        .c_data();

        handle_command(
            self.ai_id,
            COMMAND_TO_ID_ENGINE,
            -1,
            CommandTopic::PathGetApproximateLength.into(),
            &mut command_c_data,
        )?;

        Ok(command_c_data.ret_approximatePathLength)
    }
}

impl Path {
    fn new(
        ai_interface: &AIInterface,
        start_pos: [f32; 3],
        end_pos: [f32; 3],
        path_type: i32,
        goal_radius: f32,
    ) -> Result<Self, &'static str> {
        let mut command_c_data = InitPathCommandData {
            start_pos,
            end_pos,
            path_type,
            goal_radius,
        }
        .c_data();

        handle_command(
            ai_interface.ai_id,
            COMMAND_TO_ID_ENGINE,
            -1,
            CommandTopic::PathInit.into(),
            &mut command_c_data,
        )?;

        Ok(Self {
            ai_id: ai_interface.ai_id,
            path_id: command_c_data.ret_pathId,
        })
    }

    pub fn next_waypoint(&self) -> Result<[f32; 3], &'static str> {
        let mut command_data = GetNextWaypointPathCommandData {
            path_id: self.path_id,
            next_waypoint_position: [0.0; 3],
        };

        handle_command(
            self.ai_id,
            COMMAND_TO_ID_ENGINE,
            -1,
            CommandTopic::PathGetNextWaypoint.into(),
            &mut command_data.c_data(),
        )?;

        Ok(command_data.next_waypoint_position)
    }

    pub fn free_path(self) -> Result<(), &'static str> {
        let mut command_data = FreePathCommandData {
            path_id: self.path_id,
        };

        handle_command(
            self.ai_id,
            COMMAND_TO_ID_ENGINE,
            -1,
            CommandTopic::PathFree.into(),
            &mut command_data.c_data(),
        )
    }
}