1use rusteal_ffi::{FNameHandle, UClassHandle, UObjectHandle, UStructHandle};
2
3use crate::error::{RustealError, RustealResult, check_ffi};
4use crate::ffi_dispatch;
5
6#[track_caller]
7pub fn spawn_actor_raw(
8 world: UObjectHandle,
9 class: UClassHandle,
10 transform_buf: &[u8],
11 owner: UObjectHandle,
12) -> RustealResult<UObjectHandle> {
13 let result = unsafe {
14 ffi_dispatch::world_spawn_actor(
15 world,
16 class,
17 transform_buf.as_ptr(),
18 transform_buf.len() as u32,
19 owner,
20 )
21 };
22
23 if result.is_null() {
24 Err(RustealError::invalid_operation("spawn_actor returned null"))
25 } else {
26 Ok(result)
27 }
28}
29
30#[track_caller]
31pub fn find_object_raw(class: UClassHandle, path: &str) -> RustealResult<UObjectHandle> {
32 let result =
33 unsafe { ffi_dispatch::world_find_object(class, path.as_ptr(), path.len() as u32) };
34
35 if result.is_null() {
36 Err(RustealError::invalid_operation(format!(
37 "find_object: not found: {path}"
38 )))
39 } else {
40 Ok(result)
41 }
42}
43
44#[track_caller]
45pub fn load_object_raw(class: UClassHandle, path: &str) -> RustealResult<UObjectHandle> {
46 let result =
47 unsafe { ffi_dispatch::world_load_object(class, path.as_ptr(), path.len() as u32) };
48
49 if result.is_null() {
50 Err(RustealError::invalid_operation(format!(
51 "load_object: failed to load: {path}"
52 )))
53 } else {
54 Ok(result)
55 }
56}
57
58#[track_caller]
59pub fn new_object_raw(outer: UObjectHandle, class: UClassHandle) -> RustealResult<UObjectHandle> {
60 let result = unsafe { ffi_dispatch::world_new_object(outer, class) };
61
62 if result.is_null() {
63 Err(RustealError::invalid_operation("new_object returned null"))
64 } else {
65 Ok(result)
66 }
67}
68
69#[track_caller]
70pub fn spawn_actor_deferred_raw(
71 world: UObjectHandle,
72 class: UClassHandle,
73 transform_buf: &[u8],
74 owner: UObjectHandle,
75 instigator: UObjectHandle,
76 collision_method: u8,
77) -> RustealResult<UObjectHandle> {
78 let result = unsafe {
79 ffi_dispatch::world_spawn_actor_deferred(
80 world,
81 class,
82 transform_buf.as_ptr(),
83 transform_buf.len() as u32,
84 owner,
85 instigator,
86 collision_method,
87 )
88 };
89
90 if result.is_null() {
91 Err(RustealError::invalid_operation(
92 "spawn_actor_deferred returned null",
93 ))
94 } else {
95 Ok(result)
96 }
97}
98
99#[track_caller]
100pub fn finish_spawning_raw(actor: UObjectHandle, transform_buf: &[u8]) -> RustealResult<()> {
101 check_ffi(unsafe {
102 ffi_dispatch::world_finish_spawning(
103 actor,
104 transform_buf.as_ptr(),
105 transform_buf.len() as u32,
106 )
107 })
108}
109
110#[track_caller]
111pub fn get_world_raw(object: UObjectHandle) -> RustealResult<UObjectHandle> {
112 let result = unsafe { ffi_dispatch::world_get_world(object) };
113
114 if result.is_null() {
115 Err(RustealError::invalid_operation("get_world returned null"))
116 } else {
117 Ok(result)
118 }
119}
120
121#[track_caller]
122pub fn get_all_actors_of_class_raw(
123 world: UObjectHandle,
124 class: UClassHandle,
125) -> RustealResult<Vec<UObjectHandle>> {
126 let handle_size = core::mem::size_of::<UObjectHandle>() as u32;
127
128 let mut count: u32 = 0;
129
130 check_ffi(unsafe {
131 ffi_dispatch::world_get_all_actors_of_class(
132 world,
133 class,
134 std::ptr::null_mut(),
135 0,
136 &mut count,
137 )
138 })?;
139
140 if count == 0 {
141 return Ok(Vec::new());
142 }
143
144 let byte_size = count * handle_size;
145 let mut buf = vec![0u8; byte_size as usize];
146 let mut actual_count: u32 = 0;
147
148 check_ffi(unsafe {
149 ffi_dispatch::world_get_all_actors_of_class(
150 world,
151 class,
152 buf.as_mut_ptr(),
153 byte_size,
154 &mut actual_count,
155 )
156 })?;
157
158 let handles = buf
159 .chunks_exact(handle_size as usize)
160 .take(actual_count as usize)
161 .map(|chunk| {
162 let bytes: [u8; 8] = chunk.try_into().expect("handle is 8 bytes");
163 let ptr = usize::from_ne_bytes(bytes) as *mut std::ffi::c_void;
164
165 UObjectHandle(ptr)
166 })
167 .collect();
168
169 Ok(handles)
170}
171
172pub fn find_data_table_row_raw(
173 table: UObjectHandle,
174 row_name: FNameHandle,
175 row_struct: UStructHandle,
176) -> Option<*mut u8> {
177 let row = unsafe { ffi_dispatch::world_find_data_table_row(table, row_name, row_struct) };
178 (!row.is_null()).then_some(row)
179}