Skip to main content

il2cpp_bridge_rs/structs/components/core/
game_object.rs

1//! Unity `GameObject` wrapper.
2use super::component::ComponentTrait;
3use super::transform::Transform;
4use super::unity_object::UnityObject;
5use crate::api::cache;
6use crate::structs::components::scene::scene_management::Scene;
7use crate::structs::core::{Class, Il2cppObject};
8use crate::structs::Il2cppString;
9use std::ffi::c_void;
10use std::ops::Deref;
11
12/// Wrapper for a managed `UnityEngine.GameObject`.
13///
14/// This builds on top of [`UnityObject`] and is useful once you already have a
15/// live Unity object or want to find a scene object by name.
16#[repr(transparent)]
17#[derive(Debug, Clone)]
18pub struct GameObject {
19    /// Base UnityObject structure
20    pub object: UnityObject,
21}
22
23impl Deref for GameObject {
24    type Target = UnityObject;
25
26    fn deref(&self) -> &Self::Target {
27        &self.object
28    }
29}
30
31impl GameObject {
32    /// Creates a GameObject from a raw pointer
33    ///
34    /// # Arguments
35    /// * `ptr` - The raw pointer to the GameObject
36    ///
37    /// # Returns
38    /// * `Self` - The created GameObject wrapper
39    pub fn from_ptr(ptr: *mut c_void) -> Self {
40        Self {
41            object: UnityObject::from_ptr(ptr),
42        }
43    }
44
45    /// Internally creates a new GameObject
46    ///
47    /// # Arguments
48    /// * `obj` - The GameObject instance to initialize
49    /// * `name` - The name of the new GameObject
50    ///
51    /// # Returns
52    /// * `Result<(), String>` - Ok if creation succeeds, failure otherwise
53    pub fn internal_create(obj: &mut GameObject, name: &str) -> Result<(), String> {
54        let core_module = cache::coremodule();
55        let game_object_class = core_module
56            .class("GameObject")
57            .ok_or_else(|| "Could not find GameObject class".to_string())?;
58
59        let create_method = game_object_class
60            .method("Internal_CreateGameObject")
61            .ok_or_else(|| {
62                "Could not find GameObject.Internal_CreateGameObject method".to_string()
63            })?;
64
65        unsafe {
66            let name_str = Il2cppString::new(name);
67            create_method.call::<()>(&[obj.as_ptr(), name_str as *mut c_void])?;
68            Ok(())
69        }
70    }
71
72    /// Finds a scene `GameObject` by name.
73    pub fn find(name: &str) -> Result<GameObject, String> {
74        let core_module = cache::coremodule();
75        let game_object_class = core_module
76            .class("GameObject")
77            .ok_or_else(|| "Could not find GameObject class".to_string())?;
78
79        let find_method = game_object_class
80            .method("Find")
81            .ok_or_else(|| "Could not find GameObject.Find method".to_string())?;
82
83        unsafe {
84            let name_str = Il2cppString::new(name);
85            let ptr = find_method.call::<*mut Il2cppObject>(&[name_str as *mut c_void])?;
86
87            if ptr.is_null() {
88                return Err("GameObject not found".to_string());
89            }
90
91            Ok(GameObject::from_ptr(ptr as *mut c_void))
92        }
93    }
94
95    /// Gets a component of the specified class attached to this GameObject
96    ///
97    /// # Type Parameters
98    /// * `T` - The type of component to retrieve (must implement ComponentTrait)
99    ///
100    /// # Arguments
101    /// * `class` - The IL2CPP class of the component
102    ///
103    /// # Returns
104    /// * `Result<T, String>` - The requested component, or error if not found
105    pub fn get_component<T: ComponentTrait>(&self, class: &Class) -> Result<T, String> {
106        if class.object.is_null() {
107            return Err(format!(
108                "Class '{}' does not have a valid System.Type object",
109                class.name
110            ));
111        }
112
113        unsafe {
114            let ptr = self
115                .method(("GetComponent", ["System.Type"]))
116                .ok_or("Method 'GetComponent' not found")?
117                .call::<*mut c_void>(&[class.object])?;
118
119            if ptr.is_null() {
120                return Err("Component not found".to_string());
121            }
122
123            Ok(T::from_ptr(ptr))
124        }
125    }
126
127    /// Gets the Transform attached to this GameObject
128    ///
129    /// # Returns
130    /// * `Result<Transform, String>` - The Transform attached to this GameObject
131    pub fn get_transform(&self) -> Result<Transform, String> {
132        unsafe {
133            let ptr = self
134                .method("get_transform")
135                .ok_or("Method 'get_transform' not found")?
136                .call::<*mut Il2cppObject>(&[])?;
137
138            if ptr.is_null() {
139                return Err("Transform is null".to_string());
140            }
141
142            Ok(Transform::from_ptr(ptr as *mut c_void))
143        }
144    }
145
146    /// Checks if the GameObject is active in the scene
147    ///
148    /// # Returns
149    /// * `Result<bool, String>` - True if active self
150    pub fn get_active_self(&self) -> Result<bool, String> {
151        unsafe {
152            self.method("get_activeSelf")
153                .ok_or("Method 'get_activeSelf' not found")?
154                .call::<bool>(&[])
155        }
156    }
157
158    /// Checks if the GameObject is active in the hierarchy
159    ///
160    /// # Returns
161    /// * `Result<bool, String>` - True if active in hierarchy
162    pub fn get_active_in_hierarchy(&self) -> Result<bool, String> {
163        unsafe {
164            self.method("get_activeInHierarchy")
165                .ok_or("Method 'get_activeInHierarchy' not found")?
166                .call::<bool>(&[])
167        }
168    }
169
170    /// Sets the active state of the GameObject
171    ///
172    /// # Arguments
173    /// * `active` - Whether the GameObject should be active
174    ///
175    /// # Returns
176    /// * `Result<(), String>` - Ok if success
177    pub fn set_active(&self, active: bool) -> Result<(), String> {
178        unsafe {
179            let mut arg = active;
180            self.method("SetActive")
181                .ok_or("Method 'SetActive' not found")?
182                .call::<()>(&[&mut arg as *mut bool as *mut c_void])?;
183            Ok(())
184        }
185    }
186
187    /// Gets the layer of the GameObject
188    ///
189    /// # Returns
190    /// * `Result<i32, String>` - The layer index
191    pub fn get_layer(&self) -> Result<i32, String> {
192        unsafe {
193            self.method("get_layer")
194                .ok_or("Method 'get_layer' not found")?
195                .call::<i32>(&[])
196        }
197    }
198
199    /// Sets the layer of the GameObject
200    ///
201    /// # Arguments
202    /// * `layer` - The layer index to set
203    ///
204    /// # Returns
205    /// * `Result<(), String>` - Ok if success
206    pub fn set_layer(&self, layer: i32) -> Result<(), String> {
207        unsafe {
208            let mut arg = layer;
209            self.method("set_layer")
210                .ok_or("Method 'set_layer' not found")?
211                .call::<()>(&[&mut arg as *mut i32 as *mut c_void])?;
212            Ok(())
213        }
214    }
215
216    /// Checks if the GameObject is static
217    ///
218    /// # Returns
219    /// * `Result<bool, String>` - True if the object is static
220    pub fn get_is_static(&self) -> Result<bool, String> {
221        unsafe {
222            self.method("get_isStatic")
223                .ok_or("Method 'get_isStatic' not found")?
224                .call::<bool>(&[])
225        }
226    }
227
228    /// Gets the scene that the GameObject belongs to
229    ///
230    /// # Returns
231    /// * `Result<Scene, String>` - The scene this GameObject belongs to
232    pub fn get_scene(&self) -> Result<Scene, String> {
233        unsafe {
234            self.method("get_scene")
235                .ok_or("Method 'get_scene' not found")?
236                .call::<Scene>(&[])
237        }
238    }
239}