1pub mod events;
2pub mod functions;
3
4use std::ffi::c_void;
5
6use crate::{
7 players::Player,
8 runtime::queue_api_call,
9 types::{colour::Colour, vector::Vector3},
10 vehicles::Vehicle,
11};
12
13pub use functions::load_functions;
14
15pub struct Object {
16 handle: *const c_void,
17}
18
19impl Object {
20 pub fn get_handle(&self) -> *const c_void {
21 self.handle
22 }
23
24 pub fn new(handle: *const c_void) -> Self {
25 Self { handle }
26 }
27
28 pub fn create(
30 modelid: i32,
31 position: Vector3,
32 rotation: Vector3,
33 draw_distance: f32,
34 ) -> Option<Object> {
35 let mut _id = 0;
36 functions::Object_Create(
37 modelid,
38 position.x,
39 position.y,
40 position.z,
41 rotation.x,
42 rotation.y,
43 rotation.z,
44 draw_distance,
45 &mut _id,
46 )
47 }
48
49 pub fn destroy(&self) {
51 self.defer_api_call(Box::new(move |object| {
52 functions::Object_Destroy(&object);
53 }));
54 }
55
56 pub fn attach_to_vehicle(&self, vehicle: &Vehicle, offset: Vector3, rotation: Vector3) -> bool {
58 functions::Object_AttachToVehicle(
59 self, vehicle, offset.x, offset.y, offset.z, rotation.x, rotation.y, rotation.z,
60 )
61 }
62
63 pub fn attach_to_object(
65 &self,
66 obj_attached_to: &Object,
67 offset: Vector3,
68 rotation: Vector3,
69 sync_rotation: bool,
70 ) -> bool {
71 functions::Object_AttachToObject(
72 self,
73 obj_attached_to,
74 offset.x,
75 offset.y,
76 offset.z,
77 rotation.x,
78 rotation.y,
79 rotation.z,
80 sync_rotation,
81 )
82 }
83
84 pub fn attach_to_player(&self, player: &Player, offset: Vector3, rotation: Vector3) -> bool {
86 functions::Object_AttachToPlayer(
87 self, player, offset.x, offset.y, offset.z, rotation.x, rotation.y, rotation.z,
88 )
89 }
90
91 pub fn set_pos(&self, position: Vector3) -> bool {
93 functions::Object_SetPos(self, position.x, position.y, position.z)
94 }
95
96 pub fn get_pos(&self) -> Vector3 {
98 let mut pos = Vector3::default();
99 functions::Object_GetPos(self, &mut pos.x, &mut pos.y, &mut pos.z);
100 pos
101 }
102
103 pub fn set_rotation(&self, rotation: Vector3) -> bool {
105 functions::Object_SetRot(self, rotation.x, rotation.y, rotation.z)
106 }
107
108 pub fn get_rotation(&self) -> Vector3 {
110 let mut rotation = Vector3::default();
111 functions::Object_GetRot(self, &mut rotation.x, &mut rotation.y, &mut rotation.z);
112 rotation
113 }
114
115 pub fn get_model(&self) -> i32 {
117 functions::Object_GetModel(self)
118 }
119
120 pub fn set_no_camera_collision(&self) -> bool {
122 functions::Object_SetNoCameraCollision(self)
123 }
124
125 pub fn move_object(&self, data: ObjectMoveData) -> i32 {
127 self.defer_api_call(Box::new(move |object| {
128 functions::Object_Move(
129 &object,
130 data.targetPos.x,
131 data.targetPos.y,
132 data.targetPos.z,
133 data.speed,
134 data.targetRot.x,
135 data.targetRot.y,
136 data.targetRot.z,
137 );
138 }));
139
140 if data.speed <= 0.0 {
141 return 0; }
143
144 let distance = (data.targetPos - self.get_pos()).length();
145 let time_ms = (distance / data.speed) * 1000.0;
146 time_ms as i32
147 }
148
149 pub fn stop(&self) -> bool {
151 functions::Object_Stop(self)
152 }
153
154 pub fn is_moving(&self) -> bool {
156 functions::Object_IsMoving(self)
157 }
158
159 pub fn set_material(
161 &self,
162 material_index: i32,
163 model_id: i32,
164 texture_library: &str,
165 texture_name: &str,
166 material_colour: Colour,
167 ) -> bool {
168 functions::Object_SetMaterial(
169 self,
170 material_index,
171 model_id,
172 texture_library,
173 texture_name,
174 material_colour.argb(),
175 )
176 }
177
178 pub fn set_material_text(
180 &self,
181 text: &str,
182 material_index: i32,
183 material_size: ObjectMaterialSize,
184 fontface: &str,
185 fontsize: i32,
186 bold: bool,
187 font_colour: Colour,
188 background_colour: Colour,
189 textalignment: ObjectMaterialTextAlign,
190 ) -> bool {
191 functions::Object_SetMaterialText(
192 self,
193 text,
194 material_index,
195 material_size as i32,
196 fontface,
197 fontsize,
198 bold,
199 font_colour.argb(),
200 background_colour.argb(),
201 textalignment as i32,
202 )
203 }
204
205 pub fn set_objects_default_camera_collision(disable: bool) -> bool {
207 functions::Object_SetDefaultCameraCollision(disable)
208 }
209
210 pub fn get_draw_distance(&self) -> f32 {
212 functions::Object_GetDrawDistance(self)
213 }
214
215 pub fn get_move_speed(&self) -> f32 {
217 functions::Object_GetMoveSpeed(self)
218 }
219
220 pub fn get_move_data(&self) -> ObjectMoveData {
222 let mut data = ObjectMoveData {
223 speed: functions::Object_GetMoveSpeed(self),
224 ..Default::default()
225 };
226
227 functions::Object_GetMovingTargetPos(
228 self,
229 &mut data.targetPos.x,
230 &mut data.targetPos.y,
231 &mut data.targetPos.z,
232 );
233 functions::Object_GetMovingTargetPos(
234 self,
235 &mut data.targetRot.x,
236 &mut data.targetRot.y,
237 &mut data.targetRot.z,
238 );
239 data
240 }
241
242 pub fn get_attached_data(&self) -> ObjectAttachmentData {
244 let mut data = ObjectAttachmentData::default();
245 let (mut pid, mut oid, mut vid): (i32, i32, i32) = (-1, -1, -1);
246
247 functions::Object_GetAttachedData(self, &mut pid, &mut oid, &mut vid);
248 if pid != 65535 {
249 data.ID = pid;
250 data.attachment_type = ObjectAttachmentType::Player;
251 } else if oid != 65535 {
252 data.ID = oid;
253 data.attachment_type = ObjectAttachmentType::Object;
254 } else if vid != 65535 {
255 data.ID = vid;
256 data.attachment_type = ObjectAttachmentType::Vehicle;
257 } else {
258 data.attachment_type = ObjectAttachmentType::None;
259 }
260
261 data.syncRotation = functions::Object_GetSyncRotation(self);
262 functions::Object_GetAttachedOffset(
263 self,
264 &mut data.offset.x,
265 &mut data.offset.y,
266 &mut data.offset.z,
267 &mut data.rotation.x,
268 &mut data.rotation.y,
269 &mut data.rotation.z,
270 );
271 data
272 }
273
274 pub fn is_material_slot_used(&self, material_index: i32) -> bool {
276 functions::Object_IsMaterialSlotUsed(self, material_index)
277 }
278
279 pub fn get_material_data(&self, material_index: i32) -> ObjectMaterialData {
281 let (
282 mut modelid,
283 mut texture_library,
284 mut texture_name,
285 mut material_colour,
286 mut text,
287 mut material_size,
288 mut font_face,
289 mut font_size,
290 mut bold,
291 mut font_colour,
292 mut background_colour,
293 mut text_alignment,
294 ): (
295 i32,
296 String,
297 String,
298 i32,
299 String,
300 i32,
301 String,
302 i32,
303 bool,
304 i32,
305 i32,
306 i32,
307 ) = Default::default();
308
309 functions::Object_GetMaterial(
310 self,
311 material_index,
312 &mut modelid,
313 &mut texture_library,
314 16,
315 &mut texture_name,
316 16,
317 &mut material_colour,
318 );
319
320 functions::Object_GetMaterialText(
321 self,
322 material_index,
323 &mut text,
324 16,
325 &mut material_size,
326 &mut font_face,
327 16,
328 &mut font_size,
329 &mut bold,
330 &mut font_colour,
331 &mut background_colour,
332 &mut text_alignment,
333 );
334
335 ObjectMaterialData::new(
336 modelid,
337 texture_library,
338 texture_name,
339 Colour::from_argb(material_colour as u32),
340 text,
341 material_size,
342 font_face,
343 font_size,
344 bold,
345 Colour::from_argb(font_colour as u32),
346 Colour::from_argb(background_colour as u32),
347 text_alignment,
348 )
349 }
350
351 pub fn is_no_camera_collision(&self) -> bool {
353 functions::Object_IsObjectNoCameraCollision(self)
354 }
355
356 pub fn get_id(&self) -> i32 {
358 functions::Object_GetID(self)
359 }
360
361 pub fn from_id(id: i32) -> Option<Object> {
363 functions::Object_FromID(id)
364 }
365
366 fn defer_api_call(&self, callback: Box<dyn FnOnce(Self)>) {
367 let object_id = self.get_id();
368 queue_api_call(Box::new(move || {
369 let object = match Self::from_id(object_id) {
370 Some(object) => object,
371 None => {
372 log::error!("object with id={object_id} not found");
373 return;
374 }
375 };
376 callback(object);
377 }));
378 }
379}
380
381pub struct PlayerObject {
382 handle: *const c_void,
383 pub player: Player,
384}
385
386impl PlayerObject {
387 pub fn get_handle(&self) -> *const c_void {
388 self.handle
389 }
390
391 pub fn new(handle: *const c_void, player: Player) -> Self {
392 Self { handle, player }
393 }
394
395 pub fn attach_player_object_to_vehicle(
397 &self,
398 vehicle: &Vehicle,
399 offset: Vector3,
400 rotation: Vector3,
401 ) -> bool {
402 functions::PlayerObject_AttachToVehicle(
403 &self.player,
404 self,
405 vehicle,
406 offset.x,
407 offset.y,
408 offset.z,
409 rotation.x,
410 rotation.y,
411 rotation.z,
412 )
413 }
414 pub fn attach_player_object_to_player(
416 &self,
417 player_attached_to: &Player,
418 offset: Vector3,
419 rotation: Vector3,
420 ) -> bool {
421 functions::PlayerObject_AttachToPlayer(
422 &self.player,
423 self,
424 player_attached_to,
425 offset.x,
426 offset.y,
427 offset.z,
428 rotation.x,
429 rotation.y,
430 rotation.z,
431 )
432 }
433 pub fn attach_player_object_to_object(
435 &self,
436 attached_to: &PlayerObject,
437 offset: Vector3,
438 rotation: Vector3,
439 ) -> bool {
440 functions::PlayerObject_AttachToObject(
441 &self.player,
442 self,
443 attached_to,
444 offset.x,
445 offset.y,
446 offset.z,
447 rotation.x,
448 rotation.y,
449 rotation.z,
450 )
451 }
452 pub fn set_player_object_pos(&self, position: Vector3) -> bool {
454 functions::PlayerObject_SetPos(&self.player, self, position.x, position.y, position.z)
455 }
456 pub fn get_player_object_pos(&self) -> Vector3 {
458 let mut position = Vector3::default();
459 functions::PlayerObject_GetPos(
460 &self.player,
461 self,
462 &mut position.x,
463 &mut position.y,
464 &mut position.z,
465 );
466 position
467 }
468 pub fn set_player_object_rotation(&self, rotation: Vector3) -> bool {
470 functions::PlayerObject_SetRot(&self.player, self, rotation.x, rotation.y, rotation.z)
471 }
472 pub fn get_player_object_rotation(&self) -> Vector3 {
474 let mut rotation = Vector3::default();
475 functions::PlayerObject_GetRot(
476 &self.player,
477 self,
478 &mut rotation.x,
479 &mut rotation.y,
480 &mut rotation.z,
481 );
482 rotation
483 }
484 pub fn get_player_object_model(&self) -> i32 {
486 functions::PlayerObject_GetModel(&self.player, self)
487 }
488 pub fn set_player_object_no_camera_collision(&self) -> bool {
490 functions::PlayerObject_SetNoCameraCollision(&self.player, self)
491 }
492 pub fn move_player_object(&self, data: ObjectMoveData) -> i32 {
494 functions::PlayerObject_Move(
495 &self.player,
496 self,
497 data.targetPos.x,
498 data.targetPos.y,
499 data.targetPos.z,
500 data.speed,
501 data.targetRot.x,
502 data.targetRot.y,
503 data.targetRot.z,
504 )
505 }
506 pub fn stop_player_object(&self) -> bool {
508 functions::PlayerObject_Stop(&self.player, self)
509 }
510 pub fn is_player_object_moving(&self) -> bool {
512 functions::PlayerObject_IsMoving(&self.player, self)
513 }
514
515 pub fn set_player_object_material(
517 &self,
518 material_index: i32,
519 model_id: i32,
520 texture_library: &str,
521 texture_name: &str,
522 material_colour: Colour,
523 ) -> bool {
524 functions::PlayerObject_SetMaterial(
525 &self.player,
526 self,
527 material_index,
528 model_id,
529 texture_library,
530 texture_name,
531 material_colour.argb(),
532 )
533 }
534 pub fn set_player_object_material_text(
536 &self,
537 text: &str,
538 material_index: i32,
539 material_size: i32,
540 fontface: &str,
541 fontsize: i32,
542 bold: bool,
543 font_colour: Colour,
544 background_colour: Colour,
545 textalignment: ObjectMaterialTextAlign,
546 ) -> bool {
547 functions::PlayerObject_SetMaterialText(
548 &self.player,
549 self,
550 text,
551 material_index,
552 material_size,
553 fontface,
554 fontsize,
555 bold,
556 font_colour.argb(),
557 background_colour.argb(),
558 textalignment as i32,
559 )
560 }
561 pub fn get_player_object_draw_distance(&self) -> f32 {
563 functions::PlayerObject_GetDrawDistance(&self.player, self)
564 }
565 pub fn get_player_object_move_speed(&self) -> f32 {
567 functions::PlayerObject_GetMoveSpeed(&self.player, self)
568 }
569 pub fn get_player_object_moving_data(&self) -> ObjectMoveData {
570 let mut data = ObjectMoveData {
571 speed: functions::PlayerObject_GetMoveSpeed(&self.player, self),
572 ..Default::default()
573 };
574 functions::PlayerObject_GetMovingTargetPos(
575 &self.player,
576 self,
577 &mut data.targetPos.x,
578 &mut data.targetPos.y,
579 &mut data.targetPos.z,
580 );
581 functions::PlayerObject_GetMovingTargetRot(
582 &self.player,
583 self,
584 &mut data.targetRot.x,
585 &mut data.targetRot.y,
586 &mut data.targetRot.z,
587 );
588 data
589 }
590 pub fn get_player_object_attached_data(&self) -> ObjectAttachmentData {
592 let mut data = ObjectAttachmentData::default();
593 let (mut pid, mut oid, mut vid): (i32, i32, i32) = (-1, -1, -1);
594
595 functions::PlayerObject_GetAttachedData(&self.player, self, &mut pid, &mut oid, &mut vid);
596 if pid != 65535 {
597 data.ID = pid;
598 data.attachment_type = ObjectAttachmentType::Player;
599 } else if oid != 65535 {
600 data.ID = oid;
601 data.attachment_type = ObjectAttachmentType::Object;
602 } else if vid != 65535 {
603 data.ID = vid;
604 data.attachment_type = ObjectAttachmentType::Vehicle;
605 } else {
606 data.attachment_type = ObjectAttachmentType::None;
607 }
608
609 data.syncRotation = functions::PlayerObject_GetSyncRotation(&self.player, self);
610 functions::PlayerObject_GetAttachedOffset(
611 &self.player,
612 self,
613 &mut data.offset.x,
614 &mut data.offset.y,
615 &mut data.offset.z,
616 &mut data.rotation.x,
617 &mut data.rotation.y,
618 &mut data.rotation.z,
619 );
620 data
621 }
622 pub fn is_player_object_material_slot_used(&self, material_index: i32) -> bool {
624 functions::PlayerObject_IsMaterialSlotUsed(&self.player, self, material_index)
625 }
626 pub fn get_player_object_material_data(&self, material_index: i32) -> ObjectMaterialData {
627 let (
628 mut modelid,
629 mut texture_library,
630 mut texture_name,
631 mut material_colour,
632 mut text,
633 mut material_size,
634 mut font_face,
635 mut font_size,
636 mut bold,
637 mut font_colour,
638 mut background_colour,
639 mut text_alignment,
640 ): (
641 i32,
642 String,
643 String,
644 i32,
645 String,
646 i32,
647 String,
648 i32,
649 bool,
650 i32,
651 i32,
652 i32,
653 ) = Default::default();
654
655 functions::PlayerObject_GetMaterial(
656 &self.player,
657 self,
658 material_index,
659 &mut modelid,
660 &mut texture_library,
661 16,
662 &mut texture_name,
663 16,
664 &mut material_colour,
665 );
666
667 functions::PlayerObject_GetMaterialText(
668 &self.player,
669 self,
670 material_index,
671 &mut text,
672 16,
673 &mut material_size,
674 &mut font_face,
675 16,
676 &mut font_size,
677 &mut bold,
678 &mut font_colour,
679 &mut background_colour,
680 &mut text_alignment,
681 );
682
683 ObjectMaterialData::new(
684 modelid,
685 texture_library,
686 texture_name,
687 Colour::from_argb(material_colour as u32),
688 text,
689 material_size,
690 font_face,
691 font_size,
692 bold,
693 Colour::from_argb(font_colour as u32),
694 Colour::from_argb(background_colour as u32),
695 text_alignment,
696 )
697 }
698 pub fn is_player_object_no_camera_collision(&self) -> bool {
700 functions::PlayerObject_IsNoCameraCollision(&self.player, self)
701 }
702
703 pub fn get_id(&self) -> i32 {
705 functions::PlayerObject_GetID(&self.player, self)
706 }
707}
708
709#[repr(C)]
711#[derive(Default, Clone, Copy, Debug)]
712pub struct ObjectMoveData {
713 pub targetPos: Vector3,
715 pub targetRot: Vector3,
717 pub speed: f32,
719}
720
721#[repr(C)]
723#[derive(Default, PartialEq, Clone, Copy, Debug)]
724pub enum ObjectAttachmentType {
725 #[default]
726 None,
727 Vehicle,
728 Object,
729 Player,
730}
731
732#[repr(C)]
734#[derive(Default, Clone, Copy, Debug)]
735pub struct ObjectAttachmentData {
736 pub attachment_type: ObjectAttachmentType,
738 pub syncRotation: bool,
740 pub ID: i32,
742 pub offset: Vector3,
744 pub rotation: Vector3,
746}
747
748#[repr(C)]
750#[derive(PartialEq, Clone, Copy, Debug)]
751pub enum ObjectMaterialTextAlign {
752 Left,
753 Center,
754 Right,
755}
756
757#[repr(C)]
759#[derive(PartialEq, Clone, Copy, Debug)]
760pub enum ObjectMaterialSize {
761 Size32x32 = 10,
762 Size64x32 = 20,
763 Size64x64 = 30,
764 Size128x32 = 40,
765 Size128x64 = 50,
766 Size128x128 = 60,
767 Size256x32 = 70,
768 Size256x64 = 80,
769 Size256x128 = 90,
770 Size256x256 = 100,
771 Size512x64 = 110,
772 Size512x128 = 120,
773 Size512x256 = 130,
774 Size512x512 = 140,
775}
776
777#[repr(C)]
779#[derive(PartialEq, Clone, Copy, Debug)]
780pub enum ObjectMaterialType {
781 None,
782 Default,
783 Text,
784}
785
786#[derive(PartialEq, Clone, Debug)]
788pub struct ObjectMaterialData {
789 pub modelid: i32,
790 pub textureLibrary: String,
791 pub textureName: String,
792 pub materialColour: Colour,
793 pub text: String,
794 pub materialSize: i32,
795 pub fontFace: String,
796 pub fontSize: i32,
797 pub bold: bool,
798 pub fontColour: Colour,
799 pub backgroundColour: Colour,
800 pub textAlignment: i32,
801}
802
803impl ObjectMaterialData {
804 pub fn new(
805 modelid: i32,
806 textureLibrary: String,
807 textureName: String,
808 materialColour: Colour,
809 text: String,
810 materialSize: i32,
811 fontFace: String,
812 fontSize: i32,
813 bold: bool,
814 fontColour: Colour,
815 backgroundColour: Colour,
816 textAlignment: i32,
817 ) -> Self {
818 Self {
819 modelid,
820 textureLibrary,
821 textureName,
822 materialColour,
823 text,
824 materialSize,
825 fontFace,
826 fontSize,
827 bold,
828 fontColour,
829 backgroundColour,
830 textAlignment,
831 }
832 }
833}
834
835#[repr(C)]
836#[derive(PartialEq, Clone, Copy, Debug)]
837pub enum ObjectEditResponse {
838 Cancel,
839 Final,
840 Update,
841}
842
843#[repr(C)]
844#[derive(Clone, Copy, Debug, Default)]
845pub struct ObjectAttachmentSlotData {
846 pub model: i32,
847 pub bone: i32,
848 pub offset: Vector3,
849 pub rotation: Vector3,
850 pub scale: Vector3,
851 pub colour1: Colour,
852 pub colour2: Colour,
853}