rusteal-core 0.7.0

Safe Rust runtime for rusteal (object refs, lifecycle, dynamic calls)
Documentation
use rusteal_ffi::{FNameHandle, UClassHandle, UObjectHandle, UStructHandle};

use crate::error::{RustealError, RustealResult, check_ffi};
use crate::ffi_dispatch;

#[track_caller]
pub fn spawn_actor_raw(
    world: UObjectHandle,
    class: UClassHandle,
    transform_buf: &[u8],
    owner: UObjectHandle,
) -> RustealResult<UObjectHandle> {
    let result = unsafe {
        ffi_dispatch::world_spawn_actor(
            world,
            class,
            transform_buf.as_ptr(),
            transform_buf.len() as u32,
            owner,
        )
    };

    if result.is_null() {
        Err(RustealError::invalid_operation("spawn_actor returned null"))
    } else {
        Ok(result)
    }
}

#[track_caller]
pub fn find_object_raw(class: UClassHandle, path: &str) -> RustealResult<UObjectHandle> {
    let result =
        unsafe { ffi_dispatch::world_find_object(class, path.as_ptr(), path.len() as u32) };

    if result.is_null() {
        Err(RustealError::invalid_operation(format!(
            "find_object: not found: {path}"
        )))
    } else {
        Ok(result)
    }
}

#[track_caller]
pub fn load_object_raw(class: UClassHandle, path: &str) -> RustealResult<UObjectHandle> {
    let result =
        unsafe { ffi_dispatch::world_load_object(class, path.as_ptr(), path.len() as u32) };

    if result.is_null() {
        Err(RustealError::invalid_operation(format!(
            "load_object: failed to load: {path}"
        )))
    } else {
        Ok(result)
    }
}

#[track_caller]
pub fn new_object_raw(outer: UObjectHandle, class: UClassHandle) -> RustealResult<UObjectHandle> {
    let result = unsafe { ffi_dispatch::world_new_object(outer, class) };

    if result.is_null() {
        Err(RustealError::invalid_operation("new_object returned null"))
    } else {
        Ok(result)
    }
}

#[track_caller]
pub fn spawn_actor_deferred_raw(
    world: UObjectHandle,
    class: UClassHandle,
    transform_buf: &[u8],
    owner: UObjectHandle,
    instigator: UObjectHandle,
    collision_method: u8,
) -> RustealResult<UObjectHandle> {
    let result = unsafe {
        ffi_dispatch::world_spawn_actor_deferred(
            world,
            class,
            transform_buf.as_ptr(),
            transform_buf.len() as u32,
            owner,
            instigator,
            collision_method,
        )
    };

    if result.is_null() {
        Err(RustealError::invalid_operation(
            "spawn_actor_deferred returned null",
        ))
    } else {
        Ok(result)
    }
}

#[track_caller]
pub fn finish_spawning_raw(actor: UObjectHandle, transform_buf: &[u8]) -> RustealResult<()> {
    check_ffi(unsafe {
        ffi_dispatch::world_finish_spawning(
            actor,
            transform_buf.as_ptr(),
            transform_buf.len() as u32,
        )
    })
}

#[track_caller]
pub fn get_world_raw(object: UObjectHandle) -> RustealResult<UObjectHandle> {
    let result = unsafe { ffi_dispatch::world_get_world(object) };

    if result.is_null() {
        Err(RustealError::invalid_operation("get_world returned null"))
    } else {
        Ok(result)
    }
}

#[track_caller]
pub fn get_all_actors_of_class_raw(
    world: UObjectHandle,
    class: UClassHandle,
) -> RustealResult<Vec<UObjectHandle>> {
    let handle_size = core::mem::size_of::<UObjectHandle>() as u32;

    let mut count: u32 = 0;

    check_ffi(unsafe {
        ffi_dispatch::world_get_all_actors_of_class(
            world,
            class,
            std::ptr::null_mut(),
            0,
            &mut count,
        )
    })?;

    if count == 0 {
        return Ok(Vec::new());
    }

    let byte_size = count * handle_size;
    let mut buf = vec![0u8; byte_size as usize];
    let mut actual_count: u32 = 0;

    check_ffi(unsafe {
        ffi_dispatch::world_get_all_actors_of_class(
            world,
            class,
            buf.as_mut_ptr(),
            byte_size,
            &mut actual_count,
        )
    })?;

    let handles = buf
        .chunks_exact(handle_size as usize)
        .take(actual_count as usize)
        .map(|chunk| {
            let bytes: [u8; 8] = chunk.try_into().expect("handle is 8 bytes");
            let ptr = usize::from_ne_bytes(bytes) as *mut std::ffi::c_void;

            UObjectHandle(ptr)
        })
        .collect();

    Ok(handles)
}

pub fn find_data_table_row_raw(
    table: UObjectHandle,
    row_name: FNameHandle,
    row_struct: UStructHandle,
) -> Option<*mut u8> {
    let row = unsafe { ffi_dispatch::world_find_data_table_row(table, row_name, row_struct) };
    (!row.is_null()).then_some(row)
}