Skip to main content

il2cpp_bridge_rs/structs/components/core/
component.rs

1//! Unity `Component` wrapper and conversion trait.
2use super::game_object::GameObject;
3use super::transform::Transform;
4use super::unity_object::UnityObject;
5use crate::structs::core::{Class, Il2cppObject};
6use std::ffi::c_void;
7use std::ops::Deref;
8
9/// Wrapper for a managed `UnityEngine.Component`.
10#[repr(C)]
11#[derive(Debug, Clone, Copy)]
12pub struct Component {
13    /// Base UnityObject structure
14    pub object: UnityObject,
15    /// Cached pointer to the component
16    pub m_cached_ptr: *mut c_void,
17}
18
19/// Trait implemented by Unity component wrappers that can be constructed from a raw pointer.
20pub trait ComponentTrait {
21    /// Creates the wrapper from a raw managed object pointer.
22    fn from_ptr(ptr: *mut c_void) -> Self;
23}
24
25impl ComponentTrait for Component {
26    fn from_ptr(ptr: *mut c_void) -> Self {
27        let object = UnityObject::from_ptr(ptr);
28        let m_cached_ptr = unsafe {
29            let offset = std::mem::size_of::<Il2cppObject>() as isize;
30            *(ptr.offset(offset) as *mut *mut c_void)
31        };
32        Self {
33            object,
34            m_cached_ptr,
35        }
36    }
37}
38
39impl Component {
40    /// Creates a `Component` wrapper from a raw pointer.
41    pub fn from_ptr(ptr: *mut c_void) -> Self {
42        <Self as ComponentTrait>::from_ptr(ptr)
43    }
44
45    /// Returns the raw managed pointer.
46    pub fn as_ptr(&self) -> *mut c_void {
47        self.object.as_ptr()
48    }
49
50    /// Returns the `GameObject` attached to this component.
51    pub fn get_game_object(&self) -> Result<GameObject, String> {
52        unsafe {
53            let ptr = self
54                .method("get_gameObject")
55                .ok_or("Method 'get_gameObject' not found")?
56                .call::<*mut c_void>(&[])?;
57
58            if ptr.is_null() {
59                return Err("Component.gameObject is null".to_string());
60            }
61
62            Ok(GameObject::from_ptr(ptr))
63        }
64    }
65
66    /// Returns the `Transform` attached to this component.
67    pub fn get_transform(&self) -> Result<Transform, String> {
68        unsafe {
69            let ptr = self
70                .method("get_transform")
71                .ok_or("Method 'get_transform' not found")?
72                .call::<*mut c_void>(&[])?;
73
74            if ptr.is_null() {
75                return Err("Component.transform is null".to_string());
76            }
77
78            Ok(Transform::from_ptr(ptr))
79        }
80    }
81
82    /// Resolves another component of the specified class on the same `GameObject`.
83    pub fn get_component<T: ComponentTrait>(&self, class: &Class) -> Result<T, String> {
84        if class.object.is_null() {
85            return Err(format!(
86                "Class '{}' does not have a valid System.Type object",
87                class.name
88            ));
89        }
90
91        unsafe {
92            let ptr = self
93                .method(("GetComponent", ["System.Type"]))
94                .ok_or("Method 'GetComponent' not found")?
95                .call::<*mut c_void>(&[class.object])?;
96
97            if ptr.is_null() {
98                return Err("Component not found".to_string());
99            }
100
101            Ok(T::from_ptr(ptr))
102        }
103    }
104}
105
106impl Deref for Component {
107    type Target = UnityObject;
108
109    fn deref(&self) -> &Self::Target {
110        &self.object
111    }
112}