use std::error::Error;
use serde::{Deserialize, Serialize};
use crate::{
ai_interface::{
callback::{facing::Facing, feature_def::FeatureDef, unit_def::UnitDef},
AIInterface,
},
get_callback,
};
#[derive(Debug, Copy, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
pub struct Feature {
pub ai_id: i32,
pub(crate) feature_id: i32,
}
#[derive(Debug, Clone)]
pub struct FeatureInterface {
pub ai_id: i32,
}
#[derive(Debug, Clone)]
pub struct FeatureAll {
feature_def: FeatureDef,
health: f32,
reclaim_left: f32,
position: [f32; 3],
ressurect_def: UnitDef,
building_facing: Facing,
}
impl AIInterface {
pub fn feature_interface(&self) -> FeatureInterface {
FeatureInterface { ai_id: self.ai_id }
}
}
const MAX_FEATURES: usize = 128;
impl FeatureInterface {
pub fn get_features(&self) -> Result<Vec<Feature>, Box<dyn Error>> {
let get_features = get_callback!(self.ai_id, getFeatures)?;
let mut ret = [-1_i32; MAX_FEATURES];
unsafe { get_features(self.ai_id, ret.as_mut_ptr(), MAX_FEATURES as i32) };
Ok(ret
.iter()
.filter_map(|&i| {
if i == -1 {
None
} else {
Some(Feature {
ai_id: self.ai_id,
feature_id: i,
})
}
})
.collect())
}
pub fn features_at(
&self,
location: [f32; 3],
radius: f32,
spherical: bool,
) -> Result<Vec<Feature>, Box<dyn Error>> {
let get_features_func = get_callback!(self.ai_id, getFeaturesIn)?;
let mut unit_list = [-1_i32; MAX_FEATURES];
unsafe {
get_features_func(
self.ai_id,
location.clone().as_mut_ptr(),
radius,
spherical,
unit_list.as_mut_ptr(),
MAX_FEATURES as i32,
)
};
Ok(unit_list
.iter()
.filter_map(|&feature_id| {
if feature_id == -1 {
None
} else {
Some(Feature {
ai_id: self.ai_id,
feature_id,
})
}
})
.collect())
}
}
impl Feature {
pub fn feature_def(&self) -> Result<FeatureDef, Box<dyn Error>> {
let get_def_func = get_callback!(self.ai_id, Feature_getDef)?;
Ok(FeatureDef {
ai_id: self.ai_id,
feature_def_id: unsafe { get_def_func(self.ai_id, self.feature_id) },
})
}
pub fn health(&self) -> Result<f32, Box<dyn Error>> {
let get_max_health = get_callback!(self.ai_id, Feature_getHealth)?;
Ok(unsafe { get_max_health(self.ai_id, self.feature_id) })
}
pub fn reclaim_left(&self) -> Result<f32, Box<dyn Error>> {
let get_max_health = get_callback!(self.ai_id, Feature_getReclaimLeft)?;
Ok(unsafe { get_max_health(self.ai_id, self.feature_id) })
}
pub fn position(&self) -> Result<[f32; 3], Box<dyn Error>> {
let get_position_func = get_callback!(self.ai_id, Feature_getPosition)?;
let mut ret = [0.0_f32; 3];
unsafe { get_position_func(self.ai_id, self.feature_id, ret.as_mut_ptr()) };
Ok(ret)
}
pub fn ressurect_def(&self) -> Result<UnitDef, Box<dyn Error>> {
let get_ressurect_def = get_callback!(self.ai_id, Feature_getResurrectDef)?;
let ressurect_def_id = unsafe { get_ressurect_def(self.ai_id, self.feature_id) };
Ok(UnitDef {
ai_id: self.ai_id,
def_id: ressurect_def_id,
})
}
pub fn building_facing(&self) -> Result<Facing, Box<dyn Error>> {
let get_building_facing = get_callback!(self.ai_id, Feature_getBuildingFacing)?;
Ok((unsafe { get_building_facing(self.ai_id, self.feature_id) } as i32).into())
}
pub fn all(&self) -> Result<FeatureAll, Box<dyn Error>> {
Ok(FeatureAll {
feature_def: self.feature_def()?,
health: self.health()?,
reclaim_left: self.reclaim_left()?,
position: self.position()?,
ressurect_def: self.ressurect_def()?,
building_facing: self.building_facing()?,
})
}
}