1use super::{as_tbl, controller::Controller, cvt_err, group::Group, object::Object, String};
15use crate::{
16 env::miz::UnitId,
17 net::SlotId,
18 object::{DcsObject, DcsOid},
19 record_perf, simple_enum, wrapped_table, LuaEnv, LuaVec2, LuaVec3, MizLua, Position3, Sequence,
20};
21use anyhow::{bail, Result};
22use log::warn;
23use mlua::{prelude::*, Value};
24use na::Vector2;
25use serde_derive::{Deserialize, Serialize};
26use std::{marker::PhantomData, ops::Deref};
27
28simple_enum!(UnitCategory, u8, [
29 Airplane => 0,
30 GroundUnit => 2,
31 Helicopter => 1,
32 Ship => 3,
33 Structure => 4
34]);
35
36wrapped_table!(Ammo, None);
37
38impl<'lua> Ammo<'lua> {
39 pub fn count(&self) -> Result<u32> {
40 Ok(self.t.raw_get("count")?)
41 }
42
43 pub fn type_name(&self) -> Result<String> {
44 Ok(self.t.raw_get::<_, LuaTable>("desc")?.raw_get("typeName")?)
45 }
46
47 pub fn display_name(&self) -> Result<String> {
48 Ok(self
49 .t
50 .raw_get::<_, LuaTable>("desc")?
51 .raw_get("displayName")?)
52 }
53}
54
55wrapped_table!(Unit, Some("Unit"));
56
57impl<'lua> Unit<'lua> {
58 pub fn get_by_name(lua: MizLua<'lua>, name: &str) -> Result<Unit<'lua>> {
59 let globals = lua.inner().globals();
60 let unit = as_tbl("Unit", None, globals.raw_get("Unit")?)?;
61 Ok(record_perf!(
62 unit_get_by_name,
63 unit.call_function("getByName", name)?
64 ))
65 }
66
67 pub fn is_exist(&self) -> Result<bool> {
68 Ok(record_perf!(
69 unit_is_exist,
70 self.t.call_method("isExist", ())?
71 ))
72 }
73
74 pub fn destroy(self) -> Result<()> {
75 Ok(self.t.call_method("destroy", ())?)
76 }
77
78 pub fn get_desc(&self) -> Result<mlua::Table<'lua>> {
79 Ok(self.t.call_method("getDesc", ())?)
80 }
81
82 pub fn as_object(&self) -> Result<Object<'lua>> {
83 Ok(Object::from_lua(Value::Table(self.t.clone()), self.lua)?)
84 }
85
86 pub fn get_type_name(&self) -> Result<String> {
87 Ok(self.t.call_method("getTypeName", ())?)
88 }
89
90 pub fn get_point(&self) -> Result<LuaVec3> {
91 Ok(record_perf!(get_point, self.t.call_method("getPoint", ())?))
92 }
93
94 pub fn get_position(&self) -> Result<Position3> {
95 Ok(record_perf!(
96 get_position,
97 self.t.call_method("getPosition", ())?
98 ))
99 }
100
101 pub fn get_ground_position(&self) -> Result<LuaVec2> {
102 let pos = self.get_point()?;
103 Ok(LuaVec2(Vector2::from(na::Vector2::new(pos.0.x, pos.0.z))))
104 }
105
106 pub fn get_velocity(&self) -> Result<LuaVec3> {
107 Ok(record_perf!(
108 get_velocity,
109 self.t.call_method("getVelocity", ())?
110 ))
111 }
112
113 pub fn in_air(&self) -> Result<bool> {
114 Ok(record_perf!(in_air, self.t.call_method("inAir", ())?))
115 }
116
117 pub fn is_active(&self) -> Result<bool> {
118 Ok(self.t.call_method("isActive", ())?)
119 }
120
121 pub fn get_name(&self) -> Result<String> {
122 Ok(self.t.call_method("getName", ())?)
123 }
124
125 pub fn get_player_name(&self) -> Result<Option<String>> {
126 Ok(self.t.call_method("getPlayerName", ())?)
127 }
128
129 pub fn id(&self) -> Result<UnitId> {
130 Ok(self.t.call_method("getID", ())?)
131 }
132
133 pub fn slot(&self) -> Result<SlotId> {
134 Ok(SlotId::from(self.id()?))
135 }
136
137 pub fn get_number(&self) -> Result<i64> {
138 Ok(self.t.call_method("getNumber", ())?)
139 }
140
141 pub fn get_controller(&self) -> Result<Controller<'lua>> {
142 Ok(self.t.call_method("getController", ())?)
143 }
144
145 pub fn get_group(&self) -> Result<Group<'lua>> {
146 Ok(self.t.call_method("getGroup", ())?)
147 }
148
149 pub fn get_callsign(&self) -> Result<String> {
150 Ok(self.t.call_method("getCallsign", ())?)
151 }
152
153 pub fn get_life(&self) -> Result<i32> {
154 Ok(self.t.call_method("getLife", ())?)
155 }
156
157 pub fn get_life0(&self) -> Result<i32> {
158 Ok(self.t.call_method("getLife0", ())?)
159 }
160
161 pub fn get_fuel(&self) -> Result<f32> {
162 Ok(self.t.call_method("getFuel", ())?)
163 }
164
165 pub fn enable_emission(&self, on: bool) -> Result<()> {
166 Ok(self.t.call_method("enableEmission", on)?)
167 }
168
169 pub fn get_category(&self) -> Result<UnitCategory> {
170 Ok(self.t.call_method("getCategory", ())?)
171 }
172
173 pub fn get_ammo(&self) -> Result<Sequence<'lua, Ammo<'lua>>> {
174 Ok(record_perf!(get_ammo, self.t.call_method("getAmmo", ())?))
175 }
176}
177
178#[derive(Debug, Clone)]
179pub struct ClassUnit;
180
181impl<'lua> DcsObject<'lua> for Unit<'lua> {
182 type Class = ClassUnit;
183
184 fn object_id(&self) -> Result<DcsOid<Self::Class>> {
185 Ok(DcsOid {
186 id: self.raw_get("id_")?,
187 class: "Unit".into(),
188 t: PhantomData,
189 })
190 }
191
192 fn get_instance(lua: MizLua<'lua>, id: &DcsOid<Self::Class>) -> Result<Self> {
193 let t = lua.inner().create_table()?;
194 t.set_metatable(Some(lua.inner().globals().raw_get(&**id.class)?));
195 t.raw_set("id_", id.id)?;
196 let t = Unit {
197 t,
198 lua: lua.inner(),
199 };
200 if !t.is_exist()? {
201 warn!("{} is an invalid unit", id.id);
202 bail!("{} is an invalid unit", id.id)
203 }
204 if t.get_life()? <= 0 {
206 warn!("{} is dead", id.id);
207 bail!("{} is dead", id.id)
208 }
209 Ok(t)
210 }
211
212 fn get_instance_dyn<T>(lua: MizLua<'lua>, id: &DcsOid<T>) -> Result<Self> {
213 id.check_implements(lua, "Unit")?;
214 let id = DcsOid {
215 id: id.id,
216 class: id.class.clone(),
217 t: PhantomData,
218 };
219 Self::get_instance(lua, &id)
220 }
221
222 fn change_instance(self, id: &DcsOid<Self::Class>) -> Result<Self> {
223 self.raw_set("id_", id.id)?;
224 if !self.is_exist()? {
225 warn!("{} is an invalid unit", id.id);
226 bail!("{} is an invalid unit", id.id)
227 }
228 if self.get_life()? <= 0 {
230 warn!("{} is dead", id.id);
231 bail!("{} is dead", id.id)
232 }
233 Ok(self)
234 }
235
236 fn change_instance_dyn<T>(self, id: &DcsOid<T>) -> Result<Self> {
237 id.check_implements(MizLua(self.lua), "Unit")?;
238 self.t.raw_set("id_", id.id)?;
239 if !self.is_exist()? {
240 warn!("{} is an invalid unit", id.id);
241 bail!("{} is an invalid unit", id.id)
242 }
243 if self.get_life()? <= 0 {
245 warn!("{} is dead", id.id);
246 bail!("{} is dead", id.id)
247 }
248 Ok(self)
249 }
250}