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 delegate: FPropertyHandle,
29}
30
31impl DynamicCall {
32 pub fn new(obj: &UObjectRef<impl UeClass>, func_name: &str) -> RustealResult<Self> {
34 let h = obj.checked()?.raw();
35 let func = unsafe {
36 ffi_dispatch::reflection_find_function(h, func_name.as_ptr(), func_name.len() as u32)
37 };
38 if func.is_null() {
39 return Err(RustealError::FunctionNotFound(func_name.to_string()));
40 }
41 let params = unsafe { ffi_dispatch::reflection_alloc_params(func) };
42 Ok(DynamicCall {
43 obj: h,
44 func,
45 params,
46 delegate: FPropertyHandle::null(),
47 })
48 }
49
50 pub fn for_delegate(obj: &UObjectRef<impl UeClass>, delegate: FPropertyHandle) -> RustealResult<Self> {
59 let h = obj.checked()?.raw();
60 if delegate.is_null() {
61 return Err(RustealError::PropertyNotFound("delegate".to_string()));
62 }
63 let func = unsafe { ffi_dispatch::reflection_get_delegate_signature(delegate) };
64 if func.is_null() {
65 return Err(RustealError::TypeMismatch);
66 }
67 let params = unsafe { ffi_dispatch::reflection_alloc_params(func) };
68 Ok(DynamicCall { obj: h, func, params, delegate })
69 }
70
71 pub fn set<T: Copy>(&mut self, name: &str, value: T) -> RustealResult<()> {
72 let (prop, offset) = self.find_param(name)?;
73 let _ = prop; unsafe {
77 ffi_dispatch::native_mem_write(self.params, offset as usize, value);
78 }
79 Ok(())
80 }
81
82 pub fn set_struct<T: crate::traits::UeStruct>(
84 &mut self,
85 name: &str,
86 value: &crate::containers::OwnedStruct<T>,
87 ) -> RustealResult<()> {
88 let (_, offset) = self.find_param(name)?;
89 check_ffi(unsafe {
90 ffi_dispatch::reflection_copy_struct(
91 T::static_struct(),
92 self.params.add(offset as usize),
93 value.as_bytes().as_ptr(),
94 )
95 })
96 }
97
98 pub fn broadcast(self) -> RustealResult<()> {
103 if self.delegate.is_null() {
104 return Err(RustealError::InvalidOperation("not a delegate call".into()));
105 }
106 check_ffi(unsafe { ffi_dispatch::delegate_broadcast_multicast(self.obj, self.delegate, self.params) })
107 }
108
109 pub fn call(mut self) -> RustealResult<DynamicCallResult> {
110 let code =
111 unsafe { ffi_dispatch::reflection_call_function(self.obj, self.func, self.params) };
112 check_ffi(code)?;
113 let result = DynamicCallResult {
115 func: self.func,
116 params: self.params,
117 };
118 self.params = NATIVE_PTR_NULL;
120 Ok(result)
121 }
122
123 fn find_param(&self, name: &str) -> RustealResult<(FPropertyHandle, u32)> {
125 let prop = unsafe {
126 ffi_dispatch::reflection_get_function_param(self.func, name.as_ptr(), name.len() as u32)
127 };
128 if prop.is_null() {
129 return Err(RustealError::PropertyNotFound(name.to_string()));
130 }
131 let offset = unsafe { ffi_dispatch::reflection_get_property_offset(prop) };
132 Ok((prop, offset))
133 }
134}
135
136impl Drop for DynamicCall {
137 fn drop(&mut self) {
138 if !native_ptr_is_null(self.params) {
139 unsafe { ffi_dispatch::reflection_free_params(self.func, self.params) };
140 }
141 }
142}
143
144pub struct DynamicCallResult {
147 func: UFunctionHandle,
148 params: NativePtr,
149}
150
151impl DynamicCallResult {
152 pub fn get<T: Copy>(&self, name: &str) -> RustealResult<T> {
157 let prop = unsafe {
158 ffi_dispatch::reflection_get_function_param(self.func, name.as_ptr(), name.len() as u32)
159 };
160 if prop.is_null() {
161 return Err(RustealError::PropertyNotFound(name.to_string()));
162 }
163 let offset = unsafe { ffi_dispatch::reflection_get_property_offset(prop) };
164 let value = unsafe { ffi_dispatch::native_mem_read(self.params, offset as usize) };
167 Ok(value)
168 }
169}
170
171impl Drop for DynamicCallResult {
172 fn drop(&mut self) {
173 if !native_ptr_is_null(self.params) {
174 unsafe { ffi_dispatch::reflection_free_params(self.func, self.params) };
175 }
176 }
177}