spring_ai_rs/ai_interface/callback/group/
command.rs

1use std::{
2    collections::{HashMap, HashSet},
3    error::Error,
4};
5
6use spring_ai_sys::COMMAND_TO_ID_ENGINE;
7
8use crate::ai_interface::callback::{
9    command::{
10        command_data::{
11            group::GroupAddUnitCommandData,
12            unit::{
13                AiSelectUnitCommandData, AttackAreaUnitCommandData, AttackUnitCommandData,
14                BuildUnitCommandData, CaptureAreaUnitCommanddData, CaptureUnitCommanddData,
15                CloakUnitCommandData, CustomUnitCommanddData, DGunUnitCommandData,
16                FightUnitCommandData, GuardUnitCommandData, LoadOntoUnitCommandData,
17                LoadUnitsAreaCommandData, LoadUnitsUnitCommandData, MoveUnitCommandData,
18                PatrolUnitCommandData, ReclaimAreaUnitCommandData, ReclaimFeatureUnitCommandData,
19                ReclaimUnitUnitCommandData, RepairUnitCommandData, RestoreAreaUnitCommandData,
20                ResurrectAreaUnitCommandData, ResurrectUnitCommandData, SelfDestroyUnitCommandData,
21                SetAutoRepairLevelUnitCommandData, SetBaseUnitCommandData, SetFireUnitCommandData,
22                SetIdleModeCommandData, SetMoveStateCommandData, SetUnitOnOffCommandData,
23                SetUnitRepeatCommandData, SetUnitStockpileCommandData, SetUnitStopCommandData,
24                SetUnitTrajectoryCommandData, SetUnitUnloadAreaCommandData,
25                SetUnitUnloadCommandData, SetUnitWaitCommandData, SetUnitWaitGatherCommandData,
26                SetUnitWaitSquadCommandData, SetUnitWaitTimeCommandData,
27            },
28            CommandData,
29        },
30        command_topic::CommandTopic,
31        options::UnitCommandOptions,
32    },
33    engine::handle_command,
34    facing::Facing,
35    feature::Feature,
36    fire_state::FireState,
37    group::{Group, GROUP_UNITS, GROUP_UNIT_DEFS},
38    idle_mode::IdleMode,
39    move_state::MoveState,
40    position::Position,
41    trajectory::Trajectory,
42    unit::Unit,
43    unit_def::UnitDef,
44};
45
46// impl AIInterface {
47//     pub fn create_group(&self) -> Result<Group, String> {
48//         Group::create(self.ai_id)
49//     }
50// }
51
52impl Group {
53    pub fn add_unit(
54        &mut self,
55        unit: Unit,
56        options: Vec<UnitCommandOptions>,
57        timeout: Option<i32>,
58    ) -> Result<(), Box<dyn Error>> {
59        let mut command_c_data = GroupAddUnitCommandData {
60            unit_id: unit.unit_id,
61            group_id: -1,
62            options,
63            timeout: timeout.unwrap_or(i32::MAX),
64            to_group_id: self.group_id,
65        }
66        .c_data();
67
68        handle_command(
69            self.ai_id,
70            COMMAND_TO_ID_ENGINE,
71            -1,
72            CommandTopic::UnitGroupAdd.into(),
73            &mut command_c_data,
74        )?;
75
76        {
77            let mut group_units_lock = GROUP_UNITS.try_write()?;
78            let ai_group_units = &mut group_units_lock.get_mut(&self.ai_id).unwrap();
79            let group_units = ai_group_units
80                .entry(self.group_id)
81                .or_insert(HashSet::new());
82            group_units.insert(unit.unit_id);
83        }
84
85        {
86            let mut group_unit_defs_lock = GROUP_UNIT_DEFS.try_write()?;
87            let ai_group_unit_defs = &mut group_unit_defs_lock.get_mut(&self.ai_id).unwrap();
88            let group_unit_defs = ai_group_unit_defs
89                .entry(self.group_id)
90                .or_insert(HashMap::new());
91            *group_unit_defs.entry(unit.unit_def()?.def_id).or_insert(0) += 1;
92        }
93
94        Ok(())
95    }
96
97    // fn create(ai_id: i32) -> Result<Group, String> {
98    //     let mut command_c_data = CreateGroupCommandData {}.c_data();
99    //
100    //     handle_command(
101    //         ai_id,
102    //         COMMAND_TO_ID_ENGINE,
103    //         -1,
104    //         CommandTopic::GroupCreate.into(),
105    //         &mut command_c_data,
106    //     )?;
107    //
108    //     Ok(Group {
109    //         ai_id,
110    //         group_id: command_c_data.ret_groupId,
111    //     })
112    // }
113    //
114    // pub fn erase(self) -> Result<(), Box<dyn Error>> {
115    //     let mut command_c_data = EraseGroupCommandData {
116    //         group_id: self.group_id,
117    //     }
118    //     .c_data();
119    //
120    //     handle_command(
121    //         self.ai_id,
122    //         COMMAND_TO_ID_ENGINE,
123    //         -1,
124    //         CommandTopic::GroupErase.into(),
125    //         &mut command_c_data,
126    //     )?;
127    //
128    //     {
129    //         let mut group_units_lock = GROUP_UNITS.try_write()?;
130    //         let ai_group_units = &mut group_units_lock.get_mut(&self.ai_id).unwrap();
131    //         ai_group_units.remove(&self.group_id);
132    //     }
133    //
134    //     {
135    //         let mut group_unit_defs_lock = GROUP_UNIT_DEFS.try_write()?;
136    //         let ai_group_unit_defs = &mut group_unit_defs_lock.get_mut(&self.ai_id).unwrap();
137    //         ai_group_unit_defs.remove(&self.group_id);
138    //     }
139    //
140    //     Ok(())
141    // }
142    //
143    // pub fn clear_unit(
144    //     &mut self,
145    //     unit: Unit,
146    //     options: Vec<UnitCommandOptions>,
147    //     timeout: Option<i32>,
148    // ) -> Result<(), Box<dyn Error>> {
149    //     let mut command_c_data = GroupClearUnitCommandData {
150    //         unit_id: unit.unit_id,
151    //         group_id: -1,
152    //         options,
153    //         timeout: timeout.unwrap_or(i32::MAX),
154    //     }
155    //     .c_data();
156    //
157    //     handle_command(
158    //         self.ai_id,
159    //         COMMAND_TO_ID_ENGINE,
160    //         -1,
161    //         CommandTopic::UnitGroupClear.into(),
162    //         &mut command_c_data,
163    //     )?;
164    //
165    //     {
166    //         let mut group_units_lock = GROUP_UNITS.try_write()?;
167    //         let ai_group_units = &mut group_units_lock.get_mut(&self.ai_id).unwrap();
168    //         let group_units = ai_group_units
169    //             .entry(self.group_id)
170    //             .or_insert(HashSet::new())
171    //             .remove(&unit.unit_id);
172    //     }
173    //
174    //     {
175    //         let mut group_unit_defs_lock = GROUP_UNIT_DEFS.try_write()?;
176    //         let ai_group_unit_defs = &mut group_unit_defs_lock.get_mut(&self.ai_id).unwrap();
177    //         let group_unit_defs = ai_group_unit_defs
178    //             .entry(self.group_id)
179    //             .or_insert(HashMap::new());
180    //         let group_def_count = group_unit_defs.entry(unit.unit_def()?.def_id).or_insert(1);
181    //         if *group_def_count == 1 {
182    //             group_unit_defs.remove(&unit.unit_def()?.def_id);
183    //         } else {
184    //             *group_def_count -= 1;
185    //         }
186    //     }
187    //
188    //     Ok(())
189    // }
190
191    pub fn select(
192        &self,
193        options: &[UnitCommandOptions],
194        timeout: Option<i32>,
195    ) -> Result<(), &'static str> {
196        let mut command_data = AiSelectUnitCommandData {
197            unit_id: -1,
198            group_id: self.group_id,
199            options: options.to_vec(),
200            timeout: timeout.unwrap_or(i32::MAX),
201        };
202
203        handle_command(
204            self.ai_id,
205            COMMAND_TO_ID_ENGINE,
206            -1,
207            CommandTopic::UnitAISelect.into(),
208            &mut command_data.c_data(),
209        )
210    }
211
212    pub fn attack(
213        &self,
214        options: &[UnitCommandOptions],
215        timeout: Option<i32>,
216        target: Unit,
217    ) -> Result<(), &'static str> {
218        let mut command_data = AttackUnitCommandData {
219            unit_id: -1,
220            group_id: self.group_id,
221            options: options.to_vec(),
222            timeout: timeout.unwrap_or(i32::MAX),
223            target_unit_id: target.unit_id,
224        };
225
226        handle_command(
227            self.ai_id,
228            COMMAND_TO_ID_ENGINE,
229            -1,
230            CommandTopic::UnitAttack.into(),
231            &mut command_data.c_data(),
232        )
233    }
234
235    pub fn attack_area(
236        &self,
237        options: &[UnitCommandOptions],
238        timeout: Option<i32>,
239        position: [f32; 3],
240        radius: f32,
241    ) -> Result<(), &'static str> {
242        let mut command_data = AttackAreaUnitCommandData {
243            unit_id: -1,
244            group_id: self.group_id,
245            options: options.to_vec(),
246            timeout: timeout.unwrap_or(i32::MAX),
247            attack_position: position,
248            radius,
249        };
250
251        handle_command(
252            self.ai_id,
253            COMMAND_TO_ID_ENGINE,
254            -1,
255            CommandTopic::UnitAttackArea.into(),
256            &mut command_data.c_data(),
257        )
258    }
259
260    pub fn build<P: Position>(
261        &self,
262        options: &[UnitCommandOptions],
263        timeout: Option<i32>,
264        to_build_unit_def_id: UnitDef,
265        position: P,
266        facing: Facing,
267    ) -> Result<(), Box<dyn Error>> {
268        let mut command_data = BuildUnitCommandData {
269            unit_id: -1,
270            group_id: self.group_id,
271            options: options.to_vec(),
272            timeout: timeout.unwrap_or(i32::MAX),
273            to_build_unit_def_id: to_build_unit_def_id.def_id,
274            build_position: position.to_f32_array(self.ai_id)?,
275            facing,
276        };
277
278        handle_command(
279            self.ai_id,
280            COMMAND_TO_ID_ENGINE,
281            -1,
282            CommandTopic::UnitBuild.into(),
283            &mut command_data.c_data(),
284        )?;
285
286        Ok(())
287    }
288
289    pub fn capture(
290        &self,
291        options: &[UnitCommandOptions],
292        timeout: Option<i32>,
293        target: Unit,
294    ) -> Result<(), &'static str> {
295        let mut command_data = CaptureUnitCommanddData {
296            unit_id: -1,
297            group_id: self.group_id,
298            options: options.to_vec(),
299            timeout: timeout.unwrap_or(i32::MAX),
300            to_capture_unit_id: target.unit_id,
301        };
302
303        handle_command(
304            self.ai_id,
305            COMMAND_TO_ID_ENGINE,
306            -1,
307            CommandTopic::UnitCapture.into(),
308            &mut command_data.c_data(),
309        )
310    }
311
312    pub fn capture_area(
313        &self,
314        options: &[UnitCommandOptions],
315        timeout: Option<i32>,
316        position: [f32; 3],
317        radius: f32,
318    ) -> Result<(), &'static str> {
319        let mut command_data = CaptureAreaUnitCommanddData {
320            unit_id: -1,
321            group_id: self.group_id,
322            options: options.to_vec(),
323            timeout: timeout.unwrap_or(i32::MAX),
324            position,
325            radius,
326        };
327
328        handle_command(
329            self.ai_id,
330            COMMAND_TO_ID_ENGINE,
331            -1,
332            CommandTopic::UnitCaptureArea.into(),
333            &mut command_data.c_data(),
334        )
335    }
336
337    pub fn cloak(
338        &self,
339        options: &[UnitCommandOptions],
340        timeout: Option<i32>,
341        cloak: bool,
342    ) -> Result<(), &'static str> {
343        let mut command_data = CloakUnitCommandData {
344            unit_id: -1,
345            group_id: self.group_id,
346            options: options.to_vec(),
347            timeout: timeout.unwrap_or(i32::MAX),
348            cloak,
349        };
350
351        handle_command(
352            self.ai_id,
353            COMMAND_TO_ID_ENGINE,
354            -1,
355            CommandTopic::UnitCloak.into(),
356            &mut command_data.c_data(),
357        )
358    }
359
360    pub fn custom_command(
361        &self,
362        options: &[UnitCommandOptions],
363        timeout: Option<i32>,
364        command_id: i32,
365        parameters: Vec<f32>,
366    ) -> Result<(), &'static str> {
367        let mut command_data = CustomUnitCommanddData {
368            unit_id: -1,
369            group_id: self.group_id,
370            options: options.to_vec(),
371            timeout: timeout.unwrap_or(i32::MAX),
372            command_id,
373            parameters,
374        };
375
376        handle_command(
377            self.ai_id,
378            COMMAND_TO_ID_ENGINE,
379            -1,
380            CommandTopic::UnitCustom.into(),
381            &mut command_data.c_data(),
382        )
383    }
384
385    pub fn dgun_unit(
386        &self,
387        options: &[UnitCommandOptions],
388        timeout: Option<i32>,
389        target: Unit,
390    ) -> Result<(), &'static str> {
391        let mut command_data = DGunUnitCommandData {
392            unitId: -1,
393            groupId: self.group_id,
394            options: options.to_vec(),
395            timeOut: timeout.unwrap_or(i32::MAX),
396            toAttackUnitId: target.unit_id,
397        };
398
399        handle_command(
400            self.ai_id,
401            COMMAND_TO_ID_ENGINE,
402            -1,
403            CommandTopic::UnitDGun.into(),
404            &mut command_data.c_data(),
405        )
406    }
407
408    pub fn fight(
409        &self,
410        options: &[UnitCommandOptions],
411        timeout: Option<i32>,
412        position: [f32; 3],
413    ) -> Result<(), &'static str> {
414        let mut command_data = FightUnitCommandData {
415            unitId: -1,
416            groupId: self.group_id,
417            options: options.to_vec(),
418            timeOut: timeout.unwrap_or(i32::MAX),
419            position,
420        };
421
422        handle_command(
423            self.ai_id,
424            COMMAND_TO_ID_ENGINE,
425            -1,
426            CommandTopic::UnitFight.into(),
427            &mut command_data.c_data(),
428        )
429    }
430
431    pub fn guard(
432        &self,
433        options: &[UnitCommandOptions],
434        timeout: Option<i32>,
435        target: Unit,
436    ) -> Result<(), &'static str> {
437        let mut command_data = GuardUnitCommandData {
438            unitId: -1,
439            groupId: self.group_id,
440            options: options.to_vec(),
441            timeOut: timeout.unwrap_or(i32::MAX),
442            to_guard_unit_id: target.unit_id,
443        };
444
445        handle_command(
446            self.ai_id,
447            COMMAND_TO_ID_ENGINE,
448            -1,
449            CommandTopic::UnitGuard.into(),
450            &mut command_data.c_data(),
451        )
452    }
453
454    pub fn load_onto(
455        &self,
456        options: &[UnitCommandOptions],
457        timeout: Option<i32>,
458        target: Unit,
459    ) -> Result<(), &'static str> {
460        let mut command_data = LoadOntoUnitCommandData {
461            unitId: -1,
462            groupId: self.group_id,
463            options: options.to_vec(),
464            timeOut: timeout.unwrap_or(i32::MAX),
465            transporter_unit_id: target.unit_id,
466        };
467
468        handle_command(
469            self.ai_id,
470            COMMAND_TO_ID_ENGINE,
471            -1,
472            CommandTopic::UnitLoadOnto.into(),
473            &mut command_data.c_data(),
474        )
475    }
476
477    pub fn load_units(
478        &self,
479        options: &[UnitCommandOptions],
480        timeout: Option<i32>,
481        targets: &[Unit],
482    ) -> Result<(), &'static str> {
483        let mut command_data = LoadUnitsUnitCommandData {
484            unitId: -1,
485            groupId: self.group_id,
486            options: options.to_vec(),
487            timeOut: timeout.unwrap_or(i32::MAX),
488            to_load_unit_ids: targets.iter().map(|t| t.unit_id).collect(),
489        };
490
491        handle_command(
492            self.ai_id,
493            COMMAND_TO_ID_ENGINE,
494            -1,
495            CommandTopic::UnitLoadUnits.into(),
496            &mut command_data.c_data(),
497        )
498    }
499
500    pub fn load_units_area(
501        &self,
502        options: &[UnitCommandOptions],
503        timeout: Option<i32>,
504        position: [f32; 3],
505        radius: f32,
506    ) -> Result<(), &'static str> {
507        let mut command_data = LoadUnitsAreaCommandData {
508            unitId: -1,
509            groupId: self.group_id,
510            options: options.to_vec(),
511            timeOut: timeout.unwrap_or(i32::MAX),
512            position,
513            radius,
514        };
515
516        handle_command(
517            self.ai_id,
518            COMMAND_TO_ID_ENGINE,
519            -1,
520            CommandTopic::UnitLoadUnitsArea.into(),
521            &mut command_data.c_data(),
522        )
523    }
524
525    pub fn move_unit(
526        &self,
527        options: &[UnitCommandOptions],
528        timeout: Option<i32>,
529        to_pos: [f32; 3],
530    ) -> Result<(), &'static str> {
531        let mut command_data = MoveUnitCommandData {
532            unit_id: -1,
533            group_id: self.group_id,
534            options: options.to_vec(),
535            timeout: timeout.unwrap_or(i32::MAX),
536            to_pos,
537        };
538
539        handle_command(
540            self.ai_id,
541            COMMAND_TO_ID_ENGINE,
542            -1,
543            CommandTopic::UnitMove.into(),
544            &mut command_data.c_data(),
545        )
546    }
547
548    pub fn patrol(
549        &self,
550        options: &[UnitCommandOptions],
551        timeout: Option<i32>,
552        to_pos: [f32; 3],
553    ) -> Result<(), &'static str> {
554        let mut command_data = PatrolUnitCommandData {
555            unit_id: -1,
556            group_id: self.group_id,
557            options: options.to_vec(),
558            timeout: timeout.unwrap_or(i32::MAX),
559            to_pos,
560        };
561
562        handle_command(
563            self.ai_id,
564            COMMAND_TO_ID_ENGINE,
565            -1,
566            CommandTopic::UnitPatrol.into(),
567            &mut command_data.c_data(),
568        )
569    }
570
571    pub fn reclaim_area(
572        &self,
573        options: &[UnitCommandOptions],
574        timeout: Option<i32>,
575        position: [f32; 3],
576        radius: f32,
577    ) -> Result<(), &'static str> {
578        let mut command_data = ReclaimAreaUnitCommandData {
579            unit_id: -1,
580            group_id: self.group_id,
581            options: options.to_vec(),
582            timeout: timeout.unwrap_or(i32::MAX),
583            position,
584            radius,
585        };
586
587        handle_command(
588            self.ai_id,
589            COMMAND_TO_ID_ENGINE,
590            -1,
591            CommandTopic::UnitReclaimArea.into(),
592            &mut command_data.c_data(),
593        )
594    }
595
596    pub fn reclaim_feature(
597        &self,
598        options: &[UnitCommandOptions],
599        timeout: Option<i32>,
600        target: Feature,
601    ) -> Result<(), &'static str> {
602        let mut command_data = ReclaimFeatureUnitCommandData {
603            unit_id: -1,
604            group_id: self.group_id,
605            options: options.to_vec(),
606            timeout: timeout.unwrap_or(i32::MAX),
607            to_reclaim_feature_id: target.feature_id,
608        };
609
610        handle_command(
611            self.ai_id,
612            COMMAND_TO_ID_ENGINE,
613            -1,
614            CommandTopic::UnitReclaimFeature.into(),
615            &mut command_data.c_data(),
616        )
617    }
618
619    pub fn reclaim_unit(
620        &self,
621        options: &[UnitCommandOptions],
622        timeout: Option<i32>,
623        target: Unit,
624    ) -> Result<(), &'static str> {
625        let mut command_data = ReclaimUnitUnitCommandData {
626            unit_id: -1,
627            group_id: self.group_id,
628            options: options.to_vec(),
629            timeout: timeout.unwrap_or(i32::MAX),
630            to_reclaim_unit_id: target.unit_id,
631        };
632
633        handle_command(
634            self.ai_id,
635            COMMAND_TO_ID_ENGINE,
636            -1,
637            CommandTopic::UnitReclaimFeature.into(),
638            &mut command_data.c_data(),
639        )
640    }
641
642    pub fn repair_unit(
643        &self,
644        options: &[UnitCommandOptions],
645        timeout: Option<i32>,
646        target: Unit,
647    ) -> Result<(), &'static str> {
648        let mut command_data = RepairUnitCommandData {
649            unit_id: -1,
650            group_id: self.group_id,
651            options: options.to_vec(),
652            timeout: timeout.unwrap_or(i32::MAX),
653            to_repair_unit_id: target.unit_id,
654        };
655
656        handle_command(
657            self.ai_id,
658            COMMAND_TO_ID_ENGINE,
659            -1,
660            CommandTopic::UnitRepair.into(),
661            &mut command_data.c_data(),
662        )
663    }
664
665    pub fn restore_area(
666        &self,
667        options: &[UnitCommandOptions],
668        timeout: Option<i32>,
669        position: [f32; 3],
670        radius: f32,
671    ) -> Result<(), &'static str> {
672        let mut command_data = RestoreAreaUnitCommandData {
673            unit_id: -1,
674            group_id: self.group_id,
675            options: options.to_vec(),
676            timeout: timeout.unwrap_or(i32::MAX),
677            position,
678            radius,
679        };
680
681        handle_command(
682            self.ai_id,
683            COMMAND_TO_ID_ENGINE,
684            -1,
685            CommandTopic::UnitRestoreArea.into(),
686            &mut command_data.c_data(),
687        )
688    }
689
690    pub fn resurrect_unit(
691        &self,
692        options: &[UnitCommandOptions],
693        timeout: Option<i32>,
694        target: Unit,
695    ) -> Result<(), &'static str> {
696        let mut command_data = ResurrectUnitCommandData {
697            unit_id: -1,
698            group_id: self.group_id,
699            options: options.to_vec(),
700            timeout: timeout.unwrap_or(i32::MAX),
701            to_resurrect_feature_id: target.unit_id,
702        };
703
704        handle_command(
705            self.ai_id,
706            COMMAND_TO_ID_ENGINE,
707            -1,
708            CommandTopic::UnitResurrect.into(),
709            &mut command_data.c_data(),
710        )
711    }
712
713    pub fn resurrect_area(
714        &self,
715        options: &[UnitCommandOptions],
716        timeout: Option<i32>,
717        position: [f32; 3],
718        radius: f32,
719    ) -> Result<(), &'static str> {
720        let mut command_data = ResurrectAreaUnitCommandData {
721            unit_id: -1,
722            group_id: self.group_id,
723            options: options.to_vec(),
724            timeout: timeout.unwrap_or(i32::MAX),
725            position,
726            radius,
727        };
728
729        handle_command(
730            self.ai_id,
731            COMMAND_TO_ID_ENGINE,
732            -1,
733            CommandTopic::UnitResurrectArea.into(),
734            &mut command_data.c_data(),
735        )
736    }
737
738    pub fn self_destruct(
739        &self,
740        options: &[UnitCommandOptions],
741        timeout: Option<i32>,
742    ) -> Result<(), &'static str> {
743        let mut command_data = SelfDestroyUnitCommandData {
744            unit_id: -1,
745            group_id: self.group_id,
746            options: options.to_vec(),
747            timeout: timeout.unwrap_or(i32::MAX),
748        };
749
750        handle_command(
751            self.ai_id,
752            COMMAND_TO_ID_ENGINE,
753            -1,
754            CommandTopic::UnitSelfDestroy.into(),
755            &mut command_data.c_data(),
756        )
757    }
758
759    pub fn set_auto_repair_level(
760        &self,
761        options: &[UnitCommandOptions],
762        timeout: Option<i32>,
763        auto_repair_level: i32,
764    ) -> Result<(), &'static str> {
765        let mut command_data = SetAutoRepairLevelUnitCommandData {
766            unit_id: -1,
767            group_id: self.group_id,
768            options: options.to_vec(),
769            timeout: timeout.unwrap_or(i32::MAX),
770            auto_repair_level,
771        };
772
773        handle_command(
774            self.ai_id,
775            COMMAND_TO_ID_ENGINE,
776            -1,
777            CommandTopic::UnitSetAutoRepairLevel.into(),
778            &mut command_data.c_data(),
779        )
780    }
781
782    pub fn set_base_command(
783        &self,
784        options: &[UnitCommandOptions],
785        timeout: Option<i32>,
786        base_position: [f32; 3],
787    ) -> Result<(), &'static str> {
788        let mut command_data = SetBaseUnitCommandData {
789            unit_id: -1,
790            group_id: self.group_id,
791            options: options.to_vec(),
792            timeout: timeout.unwrap_or(i32::MAX),
793            base_position,
794        };
795
796        handle_command(
797            self.ai_id,
798            COMMAND_TO_ID_ENGINE,
799            -1,
800            CommandTopic::UnitSetBase.into(),
801            &mut command_data.c_data(),
802        )
803    }
804
805    pub fn set_fire_state(
806        &self,
807        options: &[UnitCommandOptions],
808        timeout: Option<i32>,
809        fire_state: FireState,
810    ) -> Result<(), &'static str> {
811        let mut command_data = SetFireUnitCommandData {
812            unit_id: -1,
813            group_id: self.group_id,
814            options: options.to_vec(),
815            timeout: timeout.unwrap_or(i32::MAX),
816            fire_state,
817        };
818
819        handle_command(
820            self.ai_id,
821            COMMAND_TO_ID_ENGINE,
822            -1,
823            CommandTopic::UnitSetFireState.into(),
824            &mut command_data.c_data(),
825        )
826    }
827
828    pub fn set_idle_mode(
829        &self,
830        options: &[UnitCommandOptions],
831        timeout: Option<i32>,
832        idle_mode: IdleMode,
833    ) -> Result<(), &'static str> {
834        let mut command_data = SetIdleModeCommandData {
835            unit_id: -1,
836            group_id: self.group_id,
837            options: options.to_vec(),
838            timeout: timeout.unwrap_or(i32::MAX),
839            idle_mode,
840        };
841
842        handle_command(
843            self.ai_id,
844            COMMAND_TO_ID_ENGINE,
845            -1,
846            CommandTopic::UnitSetIdleMode.into(),
847            &mut command_data.c_data(),
848        )
849    }
850
851    pub fn set_move_state(
852        &self,
853        options: &[UnitCommandOptions],
854        timeout: Option<i32>,
855        move_state: MoveState,
856    ) -> Result<(), &'static str> {
857        let mut command_data = SetMoveStateCommandData {
858            unit_id: -1,
859            group_id: self.group_id,
860            options: options.to_vec(),
861            timeout: timeout.unwrap_or(i32::MAX),
862            move_state,
863        };
864
865        handle_command(
866            self.ai_id,
867            COMMAND_TO_ID_ENGINE,
868            -1,
869            CommandTopic::UnitSetMoveState.into(),
870            &mut command_data.c_data(),
871        )
872    }
873
874    pub fn set_on_off(
875        &self,
876        options: &[UnitCommandOptions],
877        timeout: Option<i32>,
878        on: bool,
879    ) -> Result<(), &'static str> {
880        let mut command_data = SetUnitOnOffCommandData {
881            unit_id: -1,
882            group_id: self.group_id,
883            options: options.to_vec(),
884            timeout: timeout.unwrap_or(i32::MAX),
885            on,
886        };
887
888        handle_command(
889            self.ai_id,
890            COMMAND_TO_ID_ENGINE,
891            -1,
892            CommandTopic::UnitSetOnOff.into(),
893            &mut command_data.c_data(),
894        )
895    }
896
897    pub fn set_repeat(
898        &self,
899        options: &[UnitCommandOptions],
900        timeout: Option<i32>,
901        repeat: bool,
902    ) -> Result<(), &'static str> {
903        let mut command_data = SetUnitRepeatCommandData {
904            unit_id: -1,
905            group_id: self.group_id,
906            options: options.to_vec(),
907            timeout: timeout.unwrap_or(i32::MAX),
908            repeat,
909        };
910
911        handle_command(
912            self.ai_id,
913            COMMAND_TO_ID_ENGINE,
914            -1,
915            CommandTopic::UnitSetRepeat.into(),
916            &mut command_data.c_data(),
917        )
918    }
919
920    pub fn set_trajectory(
921        &self,
922        options: &[UnitCommandOptions],
923        timeout: Option<i32>,
924        trajectory: Trajectory,
925    ) -> Result<(), &'static str> {
926        let mut command_data = SetUnitTrajectoryCommandData {
927            unit_id: -1,
928            group_id: self.group_id,
929            options: options.to_vec(),
930            timeout: timeout.unwrap_or(i32::MAX),
931            trajectory,
932        };
933
934        handle_command(
935            self.ai_id,
936            COMMAND_TO_ID_ENGINE,
937            -1,
938            CommandTopic::UnitSetTrajectory.into(),
939            &mut command_data.c_data(),
940        )
941    }
942
943    pub fn stockpile(
944        &self,
945        options: &[UnitCommandOptions],
946        timeout: Option<i32>,
947    ) -> Result<(), &'static str> {
948        let mut command_data = SetUnitStockpileCommandData {
949            unit_id: -1,
950            group_id: self.group_id,
951            options: options.to_vec(),
952            timeout: timeout.unwrap_or(i32::MAX),
953        };
954
955        handle_command(
956            self.ai_id,
957            COMMAND_TO_ID_ENGINE,
958            -1,
959            CommandTopic::UnitStockpile.into(),
960            &mut command_data.c_data(),
961        )
962    }
963
964    pub fn stop(
965        &self,
966        options: &[UnitCommandOptions],
967        timeout: Option<i32>,
968    ) -> Result<(), &'static str> {
969        let mut command_data = SetUnitStopCommandData {
970            unit_id: -1,
971            group_id: self.group_id,
972            options: options.to_vec(),
973            timeout: timeout.unwrap_or(i32::MAX),
974        };
975
976        handle_command(
977            self.ai_id,
978            COMMAND_TO_ID_ENGINE,
979            -1,
980            CommandTopic::UnitStop.into(),
981            &mut command_data.c_data(),
982        )
983    }
984
985    pub fn unload(
986        &self,
987        options: &[UnitCommandOptions],
988        timeout: Option<i32>,
989        position: [f32; 3],
990        to_unload_unit: Unit,
991    ) -> Result<(), &'static str> {
992        let mut command_data = SetUnitUnloadCommandData {
993            unit_id: -1,
994            group_id: self.group_id,
995            options: options.to_vec(),
996            timeout: timeout.unwrap_or(i32::MAX),
997            position,
998            to_unload_unit_id: to_unload_unit.unit_id,
999        };
1000
1001        handle_command(
1002            self.ai_id,
1003            COMMAND_TO_ID_ENGINE,
1004            -1,
1005            CommandTopic::UnitUnloadUnit.into(),
1006            &mut command_data.c_data(),
1007        )
1008    }
1009
1010    pub fn unload_area(
1011        &self,
1012        options: &[UnitCommandOptions],
1013        timeout: Option<i32>,
1014        position: [f32; 3],
1015        radius: f32,
1016    ) -> Result<(), &'static str> {
1017        let mut command_data = SetUnitUnloadAreaCommandData {
1018            unit_id: -1,
1019            group_id: self.group_id,
1020            options: options.to_vec(),
1021            timeout: timeout.unwrap_or(i32::MAX),
1022            position,
1023            radius,
1024        };
1025
1026        handle_command(
1027            self.ai_id,
1028            COMMAND_TO_ID_ENGINE,
1029            -1,
1030            CommandTopic::UnitUnloadUnitsArea.into(),
1031            &mut command_data.c_data(),
1032        )
1033    }
1034
1035    pub fn wait(
1036        &self,
1037        options: &[UnitCommandOptions],
1038        timeout: Option<i32>,
1039    ) -> Result<(), &'static str> {
1040        let mut command_data = SetUnitWaitCommandData {
1041            unit_id: -1,
1042            group_id: self.group_id,
1043            options: options.to_vec(),
1044            timeout: timeout.unwrap_or(i32::MAX),
1045        };
1046
1047        handle_command(
1048            self.ai_id,
1049            COMMAND_TO_ID_ENGINE,
1050            -1,
1051            CommandTopic::UnitWait.into(),
1052            &mut command_data.c_data(),
1053        )
1054    }
1055
1056    pub fn wait_death(
1057        &self,
1058        options: &[UnitCommandOptions],
1059        timeout: Option<i32>,
1060    ) -> Result<(), &'static str> {
1061        let mut command_data = SetUnitWaitCommandData {
1062            unit_id: -1,
1063            group_id: self.group_id,
1064            options: options.to_vec(),
1065            timeout: timeout.unwrap_or(i32::MAX),
1066        };
1067
1068        handle_command(
1069            self.ai_id,
1070            COMMAND_TO_ID_ENGINE,
1071            -1,
1072            CommandTopic::UnitWaitDeath.into(),
1073            &mut command_data.c_data(),
1074        )
1075    }
1076
1077    pub fn wait_gather(
1078        &self,
1079        options: &[UnitCommandOptions],
1080        timeout: Option<i32>,
1081    ) -> Result<(), &'static str> {
1082        let mut command_data = SetUnitWaitGatherCommandData {
1083            unit_id: -1,
1084            group_id: self.group_id,
1085            options: options.to_vec(),
1086            timeout: timeout.unwrap_or(i32::MAX),
1087        };
1088
1089        handle_command(
1090            self.ai_id,
1091            COMMAND_TO_ID_ENGINE,
1092            -1,
1093            CommandTopic::UnitWaitGather.into(),
1094            &mut command_data.c_data(),
1095        )
1096    }
1097
1098    pub fn wait_squad(
1099        &self,
1100        options: &[UnitCommandOptions],
1101        timeout: Option<i32>,
1102        num_units: i32,
1103    ) -> Result<(), &'static str> {
1104        let mut command_data = SetUnitWaitSquadCommandData {
1105            unit_id: -1,
1106            group_id: self.group_id,
1107            options: options.to_vec(),
1108            timeout: timeout.unwrap_or(i32::MAX),
1109            num_units,
1110        };
1111
1112        handle_command(
1113            self.ai_id,
1114            COMMAND_TO_ID_ENGINE,
1115            -1,
1116            CommandTopic::UnitWaitSquad.into(),
1117            &mut command_data.c_data(),
1118        )
1119    }
1120
1121    pub fn wait_time(
1122        &self,
1123        options: &[UnitCommandOptions],
1124        timeout: Option<i32>,
1125        time: i32,
1126    ) -> Result<(), &'static str> {
1127        let mut command_data = SetUnitWaitTimeCommandData {
1128            unit_id: -1,
1129            group_id: self.group_id,
1130            options: options.to_vec(),
1131            timeout: timeout.unwrap_or(i32::MAX),
1132            time,
1133        };
1134
1135        handle_command(
1136            self.ai_id,
1137            COMMAND_TO_ID_ENGINE,
1138            -1,
1139            CommandTopic::UnitWaitTime.into(),
1140            &mut command_data.c_data(),
1141        )
1142    }
1143}