use std::{
collections::{HashMap, HashSet},
error::Error,
sync::RwLock,
};
use lazy_static::lazy_static;
use serde::{Deserialize, Serialize};
use crate::{
ai_interface::{
callback::{
group::{command_info::GroupSupportedCommand, order_preview::GroupOrderPreview},
unit::Unit,
unit_def::UnitDef,
},
AIInterface,
},
get_callback,
};
mod command;
pub mod command_info;
pub mod order_preview;
lazy_static! {
static ref GROUP_UNIT_DEFS: RwLock<HashMap<i32, HashMap<i32, HashMap<i32, i32>>>> =
RwLock::new(HashMap::new());
static ref GROUP_UNITS: RwLock<HashMap<i32, HashMap<i32, HashSet<i32>>>> =
RwLock::new(HashMap::new());
}
pub(crate) fn init_group_unit_defs(ai_id: i32) -> Result<(), Box<dyn Error>> {
GROUP_UNIT_DEFS.try_write()?.insert(ai_id, HashMap::new());
Ok(())
}
pub(crate) fn init_group_units(ai_id: i32) -> Result<(), Box<dyn Error>> {
GROUP_UNITS.try_write()?.insert(ai_id, HashMap::new());
Ok(())
}
#[derive(Debug, Copy, Clone)]
pub struct GroupInterface {
ai_id: i32,
}
#[derive(Debug, Copy, Clone)]
pub struct GroupInterfaceAll {}
#[derive(Debug, Copy, PartialEq, Eq, Hash, Clone, Serialize, Deserialize)]
pub struct Group {
pub ai_id: i32,
pub group_id: i32,
}
#[derive(Debug, Clone)]
pub struct GroupAll {
supported_commands: Vec<GroupSupportedCommand>,
order_preview: GroupOrderPreview,
is_selected: bool,
}
impl AIInterface {
pub fn group_interface(&self) -> GroupInterface {
GroupInterface { ai_id: self.ai_id }
}
}
const MAX_GROUPS: usize = 64;
impl GroupInterface {
pub fn get_groups(&self) -> Result<HashMap<i32, Group>, Box<dyn Error>> {
let get_groups_func = get_callback!(self.ai_id, getGroups)?;
let mut groups = [-1_i32; MAX_GROUPS];
unsafe { get_groups_func(self.ai_id, groups.as_mut_ptr(), MAX_GROUPS as i32) };
Ok(groups
.iter()
.filter_map(|&group_id| {
if group_id == -1 {
None
} else {
Some((
group_id,
Group {
ai_id: self.ai_id,
group_id,
},
))
}
})
.collect())
}
}
impl Group {
pub fn supported_commands(&self) -> Result<Vec<GroupSupportedCommand>, Box<dyn Error>> {
let get_supported_commands_func = get_callback!(self.ai_id, Group_getSupportedCommands)?;
let number_of_commands = unsafe { get_supported_commands_func(self.ai_id, self.group_id) };
Ok((0..number_of_commands)
.map(|supported_command_index| GroupSupportedCommand {
ai_id: self.ai_id,
group_id: self.group_id,
supported_command_index,
})
.collect())
}
pub fn unit_defs(&self) -> Result<Vec<UnitDef>, Box<dyn Error>> {
let mut group_unit_defs_lock = GROUP_UNIT_DEFS.try_write()?;
let ai_group_unit_defs = &mut group_unit_defs_lock.get_mut(&self.ai_id).unwrap();
let group_unit_defs = ai_group_unit_defs
.entry(self.group_id)
.or_insert(HashMap::new());
Ok(group_unit_defs
.keys()
.map(|&id| UnitDef {
ai_id: self.ai_id,
def_id: id,
})
.collect())
}
pub fn units(&self) -> Result<Vec<Unit>, Box<dyn Error>> {
let mut group_units_lock = GROUP_UNITS.try_write()?;
let ai_group_units = &mut group_units_lock.get_mut(&self.ai_id).unwrap();
let group_units = ai_group_units
.entry(self.group_id)
.or_insert(HashSet::new());
Ok(group_units
.iter()
.map(|&id| Unit {
ai_id: self.ai_id,
unit_id: id,
})
.collect())
}
pub fn order_preview(&self) -> Result<GroupOrderPreview, Box<dyn Error>> {
let get_group_order_preview_id_func = get_callback!(self.ai_id, Group_OrderPreview_getId)?;
Ok(GroupOrderPreview {
ai_id: self.ai_id,
group_id: self.group_id,
group_order_preview_id: unsafe {
get_group_order_preview_id_func(self.ai_id, self.group_id)
},
})
}
pub fn is_selected(&self) -> Result<bool, Box<dyn Error>> {
let is_selected_func = get_callback!(self.ai_id, Group_isSelected)?;
Ok(unsafe { is_selected_func(self.ai_id, self.group_id) })
}
pub fn all(&self) -> Result<GroupAll, Box<dyn Error>> {
Ok(GroupAll {
supported_commands: self.supported_commands()?,
order_preview: self.order_preview()?,
is_selected: self.is_selected()?,
})
}
}