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
46impl 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 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}