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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
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()?,
        })
    }
}