Skip to main content

il2cpp_bridge_rs/structs/components/core/
mono_behaviour.rs

1//! Unity MonoBehaviour wrapper
2//!
3//! This module provides a wrapper for Unity's MonoBehaviour class,
4//! with support for starting and stopping coroutines.
5
6use super::component::{Component, ComponentTrait};
7use crate::structs::core::runtime::coroutine::Coroutine;
8use crate::structs::Il2cppString;
9use std::ffi::c_void;
10use std::ops::Deref;
11
12/// Wrapper around Unity's MonoBehaviour component
13///
14/// MonoBehaviour is the base class from which every Unity script derives.
15/// This wrapper provides access to coroutine functionality.
16#[repr(C)]
17#[derive(Debug, Clone, Copy)]
18pub struct MonoBehaviour {
19    /// Base Component structure
20    pub component: Component,
21}
22
23impl ComponentTrait for MonoBehaviour {
24    fn from_ptr(ptr: *mut c_void) -> Self {
25        Self {
26            component: Component::from_ptr(ptr),
27        }
28    }
29}
30
31impl MonoBehaviour {
32    /// Creates a MonoBehaviour from a raw pointer
33    ///
34    /// # Arguments
35    /// * `ptr` - The raw pointer to the MonoBehaviour
36    ///
37    /// # Returns
38    /// * `Self` - The created MonoBehaviour wrapper
39    pub fn from_ptr(ptr: *mut c_void) -> Self {
40        <Self as ComponentTrait>::from_ptr(ptr)
41    }
42
43    /// Returns the raw pointer to the MonoBehaviour
44    ///
45    /// # Returns
46    /// * `*mut c_void` - The raw pointer
47    pub fn as_ptr(&self) -> *mut c_void {
48        self.component.as_ptr()
49    }
50
51    /// Starts a coroutine with the given IEnumerator
52    ///
53    /// This calls `MonoBehaviour.StartCoroutine(IEnumerator routine)` on the
54    /// Unity side. The IEnumerator should be created from a method that
55    /// returns IEnumerator (e.g., a generator method).
56    ///
57    /// # Arguments
58    /// * `enumerator` - Pointer to the IEnumerator object
59    ///
60    /// # Returns
61    /// * `Result<Coroutine, String>` - The started Coroutine, or an error
62    pub fn start_coroutine(&self, enumerator: *mut c_void) -> Result<Coroutine, String> {
63        if enumerator.is_null() {
64            return Err("Enumerator is null".to_string());
65        }
66
67        unsafe {
68            let method = self
69                .method(("StartCoroutine", ["System.Collections.IEnumerator"]))
70                .ok_or("Method 'StartCoroutine(IEnumerator)' not found")?;
71
72            let result = method.call::<*mut c_void>(&[enumerator])?;
73
74            if result.is_null() {
75                return Err("StartCoroutine returned null".to_string());
76            }
77
78            Ok(Coroutine::from_ptr(result))
79        }
80    }
81
82    /// Starts a coroutine by method name
83    ///
84    /// This calls `MonoBehaviour.StartCoroutine(string methodName)` on the
85    /// Unity side.
86    ///
87    /// # Arguments
88    /// * `method_name` - The name of the coroutine method to start
89    ///
90    /// # Returns
91    /// * `Result<Coroutine, String>` - The started Coroutine, or an error
92    pub fn start_coroutine_by_name(&self, method_name: &str) -> Result<Coroutine, String> {
93        unsafe {
94            let name_str = Il2cppString::new(method_name);
95
96            let method = self
97                .method(("StartCoroutine", ["System.String"]))
98                .ok_or("Method 'StartCoroutine(String)' not found")?;
99
100            let result = method.call::<*mut c_void>(&[name_str as *mut c_void])?;
101
102            if result.is_null() {
103                return Err("StartCoroutine returned null".to_string());
104            }
105
106            Ok(Coroutine::from_ptr(result))
107        }
108    }
109
110    /// Stops a specific coroutine
111    ///
112    /// # Arguments
113    /// * `coroutine` - The Coroutine to stop
114    ///
115    /// # Returns
116    /// * `Result<(), String>` - Ok if successful, or an error
117    pub fn stop_coroutine(&self, coroutine: Coroutine) -> Result<(), String> {
118        if coroutine.is_null() {
119            return Err("Coroutine is null".to_string());
120        }
121
122        unsafe {
123            let method = self
124                .method(("StopCoroutine", ["UnityEngine.Coroutine"]))
125                .ok_or("Method 'StopCoroutine(Coroutine)' not found")?;
126
127            method.call::<()>(&[coroutine.as_ptr()])?;
128
129            Ok(())
130        }
131    }
132
133    /// Stops a coroutine by method name
134    ///
135    /// # Arguments
136    /// * `method_name` - The name of the coroutine method to stop
137    ///
138    /// # Returns
139    /// * `Result<(), String>` - Ok if successful, or an error
140    pub fn stop_coroutine_by_name(&self, method_name: &str) -> Result<(), String> {
141        unsafe {
142            let name_str = Il2cppString::new(method_name);
143
144            let method = self
145                .method(("StopCoroutine", ["System.String"]))
146                .ok_or("Method 'StopCoroutine(String)' not found")?;
147
148            method.call::<()>(&[name_str as *mut c_void])?;
149
150            Ok(())
151        }
152    }
153
154    /// Stops all coroutines running on this MonoBehaviour
155    ///
156    /// # Returns
157    /// * `Result<(), String>` - Ok if successful, or an error
158    pub fn stop_all_coroutines(&self) -> Result<(), String> {
159        unsafe {
160            let method = self
161                .method("StopAllCoroutines")
162                .ok_or("Method 'StopAllCoroutines' not found")?;
163
164            method.call::<()>(&[])?;
165
166            Ok(())
167        }
168    }
169
170    /// Checks if the MonoBehaviour is enabled
171    ///
172    /// # Returns
173    /// * `Result<bool, String>` - True if enabled
174    pub fn get_enabled(&self) -> Result<bool, String> {
175        unsafe {
176            self.method("get_enabled")
177                .ok_or("Method 'get_enabled' not found")?
178                .call::<bool>(&[])
179        }
180    }
181
182    /// Sets the enabled state of the MonoBehaviour
183    ///
184    /// # Arguments
185    /// * `enabled` - Whether the MonoBehaviour should be enabled
186    ///
187    /// # Returns
188    /// * `Result<(), String>` - Ok if successful
189    pub fn set_enabled(&self, enabled: bool) -> Result<(), String> {
190        unsafe {
191            let mut arg = enabled;
192            self.method("set_enabled")
193                .ok_or("Method 'set_enabled' not found")?
194                .call::<()>(&[&mut arg as *mut bool as *mut c_void])?;
195
196            Ok(())
197        }
198    }
199}
200
201impl Deref for MonoBehaviour {
202    type Target = Component;
203
204    fn deref(&self) -> &Self::Target {
205        &self.component
206    }
207}