1use std::{
2 error::Error,
3 ffi::{CStr, CString},
4};
5
6use slog::{trace, Logger};
7use spring_ai_sys::{
8 SCommandFinishedEvent, SInitEvent, SLoadEvent, SLuaMessageEvent, SMessageEvent,
9 SPlayerCommandEvent, SReleaseEvent, SSaveEvent, SSeismicPingEvent, SUpdateEvent,
10 SWeaponFiredEvent,
11};
12
13use crate::{
14 ai_interface::{
15 callback::{
16 command::command_topic::CommandTopic,
17 group::{init_group_unit_defs, init_group_units},
18 unit::Unit,
19 weapon_def::WeaponDef,
20 },
21 AIInterface,
22 },
23 event::void_to_event,
24 skirmish_ai::{remove_skirmish_ai, set_skirmish_ai, SkirmishAI},
25};
26
27pub struct InitWrapper {
28 pub init_func: InitFuncType,
29}
30
31impl InitWrapper {
32 pub const fn new(init_func: InitFuncType) -> Self {
33 Self { init_func }
34 }
35}
36
37inventory::collect!(InitWrapper);
38
39pub type InitFuncType = fn(&Logger, AIInterface) -> Result<(), Box<dyn Error>>;
40
41pub fn init_wrapper(
42 logger: &Logger,
43 skirmish_ai_id: libc::c_int,
44 data: *const libc::c_void,
45 init_func: &InitFuncType,
46) -> Result<(), Box<dyn Error>> {
47 let init_data = void_to_event::<SInitEvent>(data as *mut libc::c_void)?;
48
49 set_skirmish_ai(skirmish_ai_id, SkirmishAI::new(init_data.callback)?);
50
51 trace!(logger, "AI EVENT INIT");
52
53 trace!(logger, "ID: {}; {:?}", skirmish_ai_id, init_data,);
54
55 init_group_unit_defs(skirmish_ai_id)?;
56 init_group_units(skirmish_ai_id)?;
57
58 init_func(logger, AIInterface::new(skirmish_ai_id))
59}
60
61pub struct ReleaseWrapper {
62 pub release_func: ReleaseFuncType,
63}
64
65impl ReleaseWrapper {
66 pub const fn new(release_func: ReleaseFuncType) -> Self {
67 Self { release_func }
68 }
69}
70
71inventory::collect!(ReleaseWrapper);
72
73pub type ReleaseFuncType = fn(&Logger, AIInterface) -> Result<(), Box<dyn Error>>;
74
75pub fn release_wrapper(
76 logger: &Logger,
77 skirmish_ai_id: libc::c_int,
78 data: *const libc::c_void,
79 release_func: &ReleaseFuncType,
80) -> Result<(), Box<dyn Error>> {
81 let release_data = void_to_event::<SReleaseEvent>(data as *mut libc::c_void)?;
82
83 trace!(logger, "ID: {}; {:?}", skirmish_ai_id, release_data,);
84
85 let ret = release_func(logger, AIInterface::new(skirmish_ai_id));
86
87 remove_skirmish_ai(skirmish_ai_id);
88
89 ret
90}
91
92pub struct MessageWrapper {
93 pub message_func: MessageFuncType,
94}
95
96impl MessageWrapper {
97 pub const fn new(message_func: MessageFuncType) -> Self {
98 Self { message_func }
99 }
100}
101
102inventory::collect!(MessageWrapper);
103
104pub type MessageFuncType = fn(&Logger, AIInterface, i32, &str) -> Result<(), Box<dyn Error>>;
105
106pub fn message_wrapper(
107 logger: &Logger,
108 skirmish_ai_id: libc::c_int,
109 data: *const libc::c_void,
110 message_func: &MessageFuncType,
111) -> Result<(), Box<dyn Error>> {
112 let message_data = void_to_event::<SMessageEvent>(data as *mut libc::c_void)?;
113
114 trace!(logger, "ID: {}; {:?}", skirmish_ai_id, message_data,);
115
116 message_func(
117 logger,
118 AIInterface::new(skirmish_ai_id),
119 message_data.player,
120 unsafe { CStr::from_ptr(message_data.message) }.to_str()?,
121 )
122}
123
124pub struct CommandFinishedWrapper {
125 pub command_finished_func: CommandFinishedFuncType,
126}
127
128impl CommandFinishedWrapper {
129 pub const fn new(command_finished_func: CommandFinishedFuncType) -> Self {
130 Self {
131 command_finished_func,
132 }
133 }
134}
135
136inventory::collect!(CommandFinishedWrapper);
137
138pub type CommandFinishedFuncType =
139 fn(&Logger, AIInterface, Unit, i32, CommandTopic) -> Result<(), Box<dyn Error>>;
140
141pub fn command_finished_wrapper(
142 logger: &Logger,
143 skirmish_ai_id: libc::c_int,
144 data: *const libc::c_void,
145 command_finished_func: &CommandFinishedFuncType,
146) -> Result<(), Box<dyn Error>> {
147 let command_finished_data = void_to_event::<SCommandFinishedEvent>(data as *mut libc::c_void)?;
148
149 trace!(
150 logger,
151 "ID: {}; {:?}",
152 skirmish_ai_id,
153 command_finished_data,
154 );
155
156 command_finished_func(
157 logger,
158 AIInterface::new(skirmish_ai_id),
159 Unit {
160 unit_id: command_finished_data.unitId,
161 ai_id: skirmish_ai_id,
162 },
163 command_finished_data.commandId,
164 CommandTopic::from(command_finished_data.commandTopicId),
165 )
166}
167
168pub struct LoadWrapper {
169 pub load_func: LoadFuncType,
170}
171
172impl LoadWrapper {
173 pub const fn new(load_func: LoadFuncType) -> Self {
174 Self { load_func }
175 }
176}
177
178inventory::collect!(LoadWrapper);
179
180pub type LoadFuncType = fn(&Logger, AIInterface, &str) -> Result<(), Box<dyn Error>>;
181
182pub fn load_wrapper(
183 logger: &Logger,
184 skirmish_ai_id: libc::c_int,
185 data: *const libc::c_void,
186 load_func: &LoadFuncType,
187) -> Result<(), Box<dyn Error>> {
188 let load_data = void_to_event::<SLoadEvent>(data as *mut libc::c_void)?;
189
190 trace!(logger, "ID: {}; {:?}", skirmish_ai_id, load_data);
191
192 load_func(
193 logger,
194 AIInterface::new(skirmish_ai_id),
195 &unsafe { CString::from_raw(load_data.file as *mut _) }.to_string_lossy(),
196 )
197}
198
199pub struct LuaMessageWrapper {
200 pub lua_message_func: LuaMessageFuncType,
201}
202
203impl LuaMessageWrapper {
204 pub const fn new(lua_message_func: LuaMessageFuncType) -> Self {
205 Self { lua_message_func }
206 }
207}
208
209inventory::collect!(LuaMessageWrapper);
210
211pub type LuaMessageFuncType = fn(&Logger, AIInterface, &str) -> Result<(), Box<dyn Error>>;
212
213pub fn lua_message_wrapper(
214 logger: &Logger,
215 skirmish_ai_id: libc::c_int,
216 data: *const libc::c_void,
217 lua_message_func: &LuaMessageFuncType,
218) -> Result<(), Box<dyn Error>> {
219 let lua_message_data = void_to_event::<SLuaMessageEvent>(data as *mut libc::c_void)?;
220
221 trace!(logger, "ID: {}; {:?}", skirmish_ai_id, lua_message_data);
222
223 lua_message_func(
224 logger,
225 AIInterface::new(skirmish_ai_id),
226 &unsafe { CString::from_raw(lua_message_data.inData as *mut _) }.to_string_lossy(),
227 )
228}
229
230pub struct NullWrapper {
231 pub null_func: NullFuncType,
232}
233
234impl NullWrapper {
235 pub const fn new(null_func: NullFuncType) -> Self {
236 Self { null_func }
237 }
238}
239
240inventory::collect!(NullWrapper);
241
242pub type NullFuncType = fn(&Logger, AIInterface) -> Result<(), Box<dyn Error>>;
243
244pub fn null_wrapper(
245 logger: &Logger,
246 skirmish_ai_id: libc::c_int,
247 null_func: &NullFuncType,
248) -> Result<(), Box<dyn Error>> {
249 trace!(logger, "ID: {}", skirmish_ai_id,);
250
251 null_func(logger, AIInterface::new(skirmish_ai_id))
252}
253
254pub struct PlayerCommandWrapper {
255 pub player_command_func: PlayerCommandFuncType,
256}
257
258impl PlayerCommandWrapper {
259 pub const fn new(player_command_func: PlayerCommandFuncType) -> Self {
260 Self {
261 player_command_func,
262 }
263 }
264}
265
266inventory::collect!(PlayerCommandWrapper);
267
268pub type PlayerCommandFuncType =
269 fn(&Logger, AIInterface, &[i32], CommandTopic, i32) -> Result<(), Box<dyn Error>>;
270
271pub fn player_command_wrapper(
272 logger: &Logger,
273 skirmish_ai_id: libc::c_int,
274 data: *const libc::c_void,
275 player_command_func: &PlayerCommandFuncType,
276) -> Result<(), Box<dyn Error>> {
277 let player_command_data = void_to_event::<SPlayerCommandEvent>(data as *mut libc::c_void)?;
278
279 trace!(logger, "ID: {}; {:?}", skirmish_ai_id, player_command_data);
280
281 player_command_func(
282 logger,
283 AIInterface::new(skirmish_ai_id),
284 &unsafe {
285 Vec::from_raw_parts(
286 player_command_data.unitIds,
287 player_command_data.unitIds_size as usize,
288 player_command_data.unitIds_size as usize,
289 )
290 },
291 CommandTopic::from(player_command_data.commandTopicId),
292 player_command_data.playerId,
293 )
294}
295
296pub struct SaveWrapper {
297 pub save_func: SaveFuncType,
298}
299
300impl SaveWrapper {
301 pub const fn new(save_func: SaveFuncType) -> Self {
302 Self { save_func }
303 }
304}
305
306inventory::collect!(SaveWrapper);
307
308pub type SaveFuncType = fn(&Logger, AIInterface, &str) -> Result<(), Box<dyn Error>>;
309
310pub fn save_wrapper(
311 logger: &Logger,
312 skirmish_ai_id: libc::c_int,
313 data: *const libc::c_void,
314 save_func: &SaveFuncType,
315) -> Result<(), Box<dyn Error>> {
316 let save_data = void_to_event::<SSaveEvent>(data as *mut libc::c_void)?;
317
318 trace!(logger, "ID: {}; {:?}", skirmish_ai_id, save_data);
319
320 save_func(
321 logger,
322 AIInterface::new(skirmish_ai_id),
323 &unsafe { CString::from_raw(save_data.file as *mut _) }.to_string_lossy(),
324 )
325}
326
327pub struct SeismicPingWrapper {
328 pub seismic_ping_func: SeismicPingFuncType,
329}
330
331impl SeismicPingWrapper {
332 pub const fn new(seismic_ping_func: SeismicPingFuncType) -> Self {
333 Self { seismic_ping_func }
334 }
335}
336
337inventory::collect!(SeismicPingWrapper);
338
339pub type SeismicPingFuncType =
340 fn(&Logger, AIInterface, [f32; 3], f32) -> Result<(), Box<dyn Error>>;
341
342pub fn seismic_ping_wrapper(
343 logger: &Logger,
344 skirmish_ai_id: libc::c_int,
345 data: *const libc::c_void,
346 seismic_ping_func: &SeismicPingFuncType,
347) -> Result<(), Box<dyn Error>> {
348 let seismic_ping_data = void_to_event::<SSeismicPingEvent>(data as *mut libc::c_void)?;
349
350 trace!(logger, "ID: {}; {:?}", skirmish_ai_id, seismic_ping_data,);
351 let position = unsafe { Vec::from_raw_parts(seismic_ping_data.pos_posF3, 3, 3) };
352
353 seismic_ping_func(
354 logger,
355 AIInterface::new(skirmish_ai_id),
356 [position[0], position[1], position[2]],
357 seismic_ping_data.strength,
358 )
359}
360
361pub struct UpdateWrapper {
362 pub update_func: UpdateFuncType,
363}
364
365impl UpdateWrapper {
366 pub const fn new(update_func: UpdateFuncType) -> Self {
367 Self { update_func }
368 }
369}
370
371inventory::collect!(UpdateWrapper);
372
373pub type UpdateFuncType = fn(&Logger, AIInterface, i32) -> Result<(), Box<dyn Error>>;
374
375pub fn update_wrapper(
376 logger: &Logger,
377 skirmish_ai_id: libc::c_int,
378 data: *const libc::c_void,
379 update_func: &UpdateFuncType,
380) -> Result<(), Box<dyn Error>> {
381 let update_data = void_to_event::<SUpdateEvent>(data as *mut libc::c_void)?;
382
383 trace!(logger, "ID: {}; {:?}", skirmish_ai_id, update_data,);
384
385 update_func(logger, AIInterface::new(skirmish_ai_id), update_data.frame)
386}
387
388pub struct WeaponFiredWrapper {
389 pub weapon_fired_func: WeaponFiredFuncType,
390}
391
392impl WeaponFiredWrapper {
393 pub const fn new(weapon_fired_func: WeaponFiredFuncType) -> Self {
394 Self { weapon_fired_func }
395 }
396}
397
398inventory::collect!(WeaponFiredWrapper);
399
400pub type WeaponFiredFuncType =
401 fn(&Logger, AIInterface, Unit, WeaponDef) -> Result<(), Box<dyn Error>>;
402
403pub fn weapon_fired_wrapper(
404 logger: &Logger,
405 skirmish_ai_id: libc::c_int,
406 data: *const libc::c_void,
407 weapon_fired_func: &WeaponFiredFuncType,
408) -> Result<(), Box<dyn Error>> {
409 let weapon_fired_data = void_to_event::<SWeaponFiredEvent>(data as *mut libc::c_void)?;
410
411 trace!(logger, "ID: {}; {:?}", skirmish_ai_id, weapon_fired_data,);
412
413 weapon_fired_func(
414 logger,
415 AIInterface::new(skirmish_ai_id),
416 Unit {
417 unit_id: weapon_fired_data.unitId,
418 ai_id: skirmish_ai_id,
419 },
420 WeaponDef {
421 weapon_def_id: weapon_fired_data.weaponDefId,
422 ai_id: skirmish_ai_id,
423 },
424 )
425}