spring_ai_rs/ai_interface/callback/
feature.rs

1use std::error::Error;
2
3use serde::{Deserialize, Serialize};
4
5use crate::{
6    ai_interface::{
7        callback::{facing::Facing, feature_def::FeatureDef, unit_def::UnitDef},
8        AIInterface,
9    },
10    get_callback,
11};
12
13#[derive(Debug, Copy, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
14pub struct Feature {
15    pub ai_id: i32,
16    pub(crate) feature_id: i32,
17}
18
19#[derive(Debug, Clone)]
20pub struct FeatureInterface {
21    pub ai_id: i32,
22}
23
24#[derive(Debug, Clone)]
25pub struct FeatureAll {
26    feature_def: FeatureDef,
27    health: f32,
28    reclaim_left: f32,
29    position: [f32; 3],
30    ressurect_def: UnitDef,
31    building_facing: Facing,
32}
33
34impl AIInterface {
35    pub fn feature_interface(&self) -> FeatureInterface {
36        FeatureInterface { ai_id: self.ai_id }
37    }
38}
39
40const MAX_FEATURES: usize = 128;
41
42impl FeatureInterface {
43    pub fn get_features(&self) -> Result<Vec<Feature>, Box<dyn Error>> {
44        let get_features = get_callback!(self.ai_id, getFeatures)?;
45
46        let mut ret = [-1_i32; MAX_FEATURES];
47        unsafe { get_features(self.ai_id, ret.as_mut_ptr(), MAX_FEATURES as i32) };
48
49        Ok(ret
50            .iter()
51            .filter_map(|&i| {
52                if i == -1 {
53                    None
54                } else {
55                    Some(Feature {
56                        ai_id: self.ai_id,
57                        feature_id: i,
58                    })
59                }
60            })
61            .collect())
62    }
63
64    pub fn features_at(
65        &self,
66        location: [f32; 3],
67        radius: f32,
68        spherical: bool,
69    ) -> Result<Vec<Feature>, Box<dyn Error>> {
70        let get_features_func = get_callback!(self.ai_id, getFeaturesIn)?;
71
72        let mut unit_list = [-1_i32; MAX_FEATURES];
73        unsafe {
74            get_features_func(
75                self.ai_id,
76                location.clone().as_mut_ptr(),
77                radius,
78                spherical,
79                unit_list.as_mut_ptr(),
80                MAX_FEATURES as i32,
81            )
82        };
83
84        Ok(unit_list
85            .iter()
86            .filter_map(|&feature_id| {
87                if feature_id == -1 {
88                    None
89                } else {
90                    Some(Feature {
91                        ai_id: self.ai_id,
92                        feature_id,
93                    })
94                }
95            })
96            .collect())
97    }
98}
99
100impl Feature {
101    pub fn feature_def(&self) -> Result<FeatureDef, Box<dyn Error>> {
102        let get_def_func = get_callback!(self.ai_id, Feature_getDef)?;
103        Ok(FeatureDef {
104            ai_id: self.ai_id,
105            feature_def_id: unsafe { get_def_func(self.ai_id, self.feature_id) },
106        })
107    }
108
109    pub fn health(&self) -> Result<f32, Box<dyn Error>> {
110        let get_max_health = get_callback!(self.ai_id, Feature_getHealth)?;
111        Ok(unsafe { get_max_health(self.ai_id, self.feature_id) })
112    }
113
114    pub fn reclaim_left(&self) -> Result<f32, Box<dyn Error>> {
115        let get_max_health = get_callback!(self.ai_id, Feature_getReclaimLeft)?;
116        Ok(unsafe { get_max_health(self.ai_id, self.feature_id) })
117    }
118
119    pub fn position(&self) -> Result<[f32; 3], Box<dyn Error>> {
120        let get_position_func = get_callback!(self.ai_id, Feature_getPosition)?;
121
122        let mut ret = [0.0_f32; 3];
123        unsafe { get_position_func(self.ai_id, self.feature_id, ret.as_mut_ptr()) };
124
125        Ok(ret)
126    }
127
128    pub fn ressurect_def(&self) -> Result<UnitDef, Box<dyn Error>> {
129        let get_ressurect_def = get_callback!(self.ai_id, Feature_getResurrectDef)?;
130        let ressurect_def_id = unsafe { get_ressurect_def(self.ai_id, self.feature_id) };
131        Ok(UnitDef {
132            ai_id: self.ai_id,
133            def_id: ressurect_def_id,
134        })
135    }
136
137    pub fn building_facing(&self) -> Result<Facing, Box<dyn Error>> {
138        let get_building_facing = get_callback!(self.ai_id, Feature_getBuildingFacing)?;
139        Ok((unsafe { get_building_facing(self.ai_id, self.feature_id) } as i32).into())
140    }
141
142    pub fn all(&self) -> Result<FeatureAll, Box<dyn Error>> {
143        Ok(FeatureAll {
144            feature_def: self.feature_def()?,
145            health: self.health()?,
146            reclaim_left: self.reclaim_left()?,
147            position: self.position()?,
148            ressurect_def: self.ressurect_def()?,
149            building_facing: self.building_facing()?,
150        })
151    }
152}