use uika_ffi::{FPropertyHandle, UFunctionHandle, UObjectHandle};
use crate::api::api;
use crate::error::{check_ffi, UikaError, UikaResult};
use crate::object_ref::UObjectRef;
use crate::traits::UeClass;
pub struct DynamicCall {
obj: UObjectHandle,
func: UFunctionHandle,
params: *mut u8,
}
impl DynamicCall {
pub fn new(obj: &UObjectRef<impl UeClass>, func_name: &str) -> UikaResult<Self> {
let h = obj.checked()?.raw();
let func = unsafe {
((*api().reflection).find_function)(h, func_name.as_ptr(), func_name.len() as u32)
};
if func.0.is_null() {
return Err(UikaError::FunctionNotFound(func_name.to_string()));
}
let params = unsafe { ((*api().reflection).alloc_params)(func) };
Ok(DynamicCall {
obj: h,
func,
params,
})
}
pub fn set<T: Copy>(&mut self, name: &str, value: T) -> UikaResult<()> {
let (prop, offset) = self.find_param(name)?;
let _ = prop; unsafe {
std::ptr::write_unaligned(self.params.add(offset as usize) as *mut T, value);
}
Ok(())
}
pub fn call(mut self) -> UikaResult<DynamicCallResult> {
let code =
unsafe { ((*api().reflection).call_function)(self.obj, self.func, self.params) };
check_ffi(code)?;
let result = DynamicCallResult {
func: self.func,
params: self.params,
};
self.params = std::ptr::null_mut();
Ok(result)
}
fn find_param(&self, name: &str) -> UikaResult<(FPropertyHandle, u32)> {
let prop = unsafe {
((*api().reflection).get_function_param)(self.func, name.as_ptr(), name.len() as u32)
};
if prop.0.is_null() {
return Err(UikaError::PropertyNotFound(name.to_string()));
}
let offset = unsafe { ((*api().reflection).get_property_offset)(prop) };
Ok((prop, offset))
}
}
impl Drop for DynamicCall {
fn drop(&mut self) {
if !self.params.is_null() {
unsafe { ((*api().reflection).free_params)(self.func, self.params) };
}
}
}
pub struct DynamicCallResult {
func: UFunctionHandle,
params: *mut u8,
}
impl DynamicCallResult {
pub fn get<T: Copy>(&self, name: &str) -> UikaResult<T> {
let prop = unsafe {
((*api().reflection).get_function_param)(self.func, name.as_ptr(), name.len() as u32)
};
if prop.0.is_null() {
return Err(UikaError::PropertyNotFound(name.to_string()));
}
let offset = unsafe { ((*api().reflection).get_property_offset)(prop) };
let value = unsafe { std::ptr::read_unaligned(self.params.add(offset as usize) as *const T) };
Ok(value)
}
}
impl Drop for DynamicCallResult {
fn drop(&mut self) {
if !self.params.is_null() {
unsafe { ((*api().reflection).free_params)(self.func, self.params) };
}
}
}