spring_ai_rs/ai_interface/callback/
feature.rs1use 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}