rusteal_core/
dynamic_call.rs1use rusteal_ffi::{FPropertyHandle, UFunctionHandle, UObjectHandle};
8
9use crate::error::{check_ffi, RustealError, RustealResult};
10use crate::ffi_dispatch::{self, NativePtr, NATIVE_PTR_NULL, native_ptr_is_null};
11use crate::object_ref::UObjectRef;
12use crate::traits::UeClass;
13
14pub struct DynamicCall {
24 obj: UObjectHandle,
25 func: UFunctionHandle,
26 params: NativePtr,
27}
28
29impl DynamicCall {
30 pub fn new(obj: &UObjectRef<impl UeClass>, func_name: &str) -> RustealResult<Self> {
32 let h = obj.checked()?.raw();
33 let func = unsafe {
34 ffi_dispatch::reflection_find_function(h, func_name.as_ptr(), func_name.len() as u32)
35 };
36 if func.is_null() {
37 return Err(RustealError::FunctionNotFound(func_name.to_string()));
38 }
39 let params = unsafe { ffi_dispatch::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) -> RustealResult<()> {
54 let (prop, offset) = self.find_param(name)?;
55 let _ = prop; unsafe {
59 ffi_dispatch::native_mem_write(self.params, offset as usize, value);
60 }
61 Ok(())
62 }
63
64 pub fn set_struct<T: crate::traits::UeStruct>(
66 &mut self,
67 name: &str,
68 value: &crate::containers::OwnedStruct<T>,
69 ) -> RustealResult<()> {
70 let (_, offset) = self.find_param(name)?;
71 check_ffi(unsafe {
72 ffi_dispatch::reflection_copy_struct(
73 T::static_struct(),
74 self.params.add(offset as usize),
75 value.as_bytes().as_ptr(),
76 )
77 })
78 }
79
80 pub fn call(mut self) -> RustealResult<DynamicCallResult> {
83 let code =
84 unsafe { ffi_dispatch::reflection_call_function(self.obj, self.func, self.params) };
85 check_ffi(code)?;
86 let result = DynamicCallResult {
88 func: self.func,
89 params: self.params,
90 };
91 self.params = NATIVE_PTR_NULL;
93 Ok(result)
94 }
95
96 fn find_param(&self, name: &str) -> RustealResult<(FPropertyHandle, u32)> {
98 let prop = unsafe {
99 ffi_dispatch::reflection_get_function_param(self.func, name.as_ptr(), name.len() as u32)
100 };
101 if prop.is_null() {
102 return Err(RustealError::PropertyNotFound(name.to_string()));
103 }
104 let offset = unsafe { ffi_dispatch::reflection_get_property_offset(prop) };
105 Ok((prop, offset))
106 }
107}
108
109impl Drop for DynamicCall {
110 fn drop(&mut self) {
111 if !native_ptr_is_null(self.params) {
112 unsafe { ffi_dispatch::reflection_free_params(self.func, self.params) };
113 }
114 }
115}
116
117pub struct DynamicCallResult {
120 func: UFunctionHandle,
121 params: NativePtr,
122}
123
124impl DynamicCallResult {
125 pub fn get<T: Copy>(&self, name: &str) -> RustealResult<T> {
130 let prop = unsafe {
131 ffi_dispatch::reflection_get_function_param(self.func, name.as_ptr(), name.len() as u32)
132 };
133 if prop.is_null() {
134 return Err(RustealError::PropertyNotFound(name.to_string()));
135 }
136 let offset = unsafe { ffi_dispatch::reflection_get_property_offset(prop) };
137 let value = unsafe { ffi_dispatch::native_mem_read(self.params, offset as usize) };
140 Ok(value)
141 }
142}
143
144impl Drop for DynamicCallResult {
145 fn drop(&mut self) {
146 if !native_ptr_is_null(self.params) {
147 unsafe { ffi_dispatch::reflection_free_params(self.func, self.params) };
148 }
149 }
150}