uika_runtime/
dynamic_call.rs1use uika_ffi::{FPropertyHandle, UFunctionHandle, UObjectHandle};
8
9use crate::api::api;
10use crate::error::{check_ffi, UikaError, UikaResult};
11use crate::object_ref::UObjectRef;
12use crate::traits::UeClass;
13
14pub struct DynamicCall {
24 obj: UObjectHandle,
25 func: UFunctionHandle,
26 params: *mut u8,
27}
28
29impl DynamicCall {
30 pub fn new(obj: &UObjectRef<impl UeClass>, func_name: &str) -> UikaResult<Self> {
32 let h = obj.checked()?.raw();
33 let func = unsafe {
34 ((*api().reflection).find_function)(h, func_name.as_ptr(), func_name.len() as u32)
35 };
36 if func.0.is_null() {
37 return Err(UikaError::FunctionNotFound(func_name.to_string()));
38 }
39 let params = unsafe { ((*api().reflection).alloc_params)(func) };
40 Ok(DynamicCall {
41 obj: h,
42 func,
43 params,
44 })
45 }
46
47 pub fn set<T: Copy>(&mut self, name: &str, value: T) -> UikaResult<()> {
54 let (prop, offset) = self.find_param(name)?;
55 let _ = prop; unsafe {
59 std::ptr::write_unaligned(self.params.add(offset as usize) as *mut T, value);
60 }
61 Ok(())
62 }
63
64 pub fn call(mut self) -> UikaResult<DynamicCallResult> {
67 let code =
68 unsafe { ((*api().reflection).call_function)(self.obj, self.func, self.params) };
69 check_ffi(code)?;
70 let result = DynamicCallResult {
72 func: self.func,
73 params: self.params,
74 };
75 self.params = std::ptr::null_mut();
77 Ok(result)
78 }
79
80 fn find_param(&self, name: &str) -> UikaResult<(FPropertyHandle, u32)> {
82 let prop = unsafe {
83 ((*api().reflection).get_function_param)(self.func, name.as_ptr(), name.len() as u32)
84 };
85 if prop.0.is_null() {
86 return Err(UikaError::PropertyNotFound(name.to_string()));
87 }
88 let offset = unsafe { ((*api().reflection).get_property_offset)(prop) };
89 Ok((prop, offset))
90 }
91}
92
93impl Drop for DynamicCall {
94 fn drop(&mut self) {
95 if !self.params.is_null() {
96 unsafe { ((*api().reflection).free_params)(self.func, self.params) };
97 }
98 }
99}
100
101pub struct DynamicCallResult {
104 func: UFunctionHandle,
105 params: *mut u8,
106}
107
108impl DynamicCallResult {
109 pub fn get<T: Copy>(&self, name: &str) -> UikaResult<T> {
114 let prop = unsafe {
115 ((*api().reflection).get_function_param)(self.func, name.as_ptr(), name.len() as u32)
116 };
117 if prop.0.is_null() {
118 return Err(UikaError::PropertyNotFound(name.to_string()));
119 }
120 let offset = unsafe { ((*api().reflection).get_property_offset)(prop) };
121 let value = unsafe { std::ptr::read_unaligned(self.params.add(offset as usize) as *const T) };
124 Ok(value)
125 }
126}
127
128impl Drop for DynamicCallResult {
129 fn drop(&mut self) {
130 if !self.params.is_null() {
131 unsafe { ((*api().reflection).free_params)(self.func, self.params) };
132 }
133 }
134}