rusteal-codegen 0.8.0

Code generator: UHT JSON to Rust bindings and C++ wrappers for rusteal
Documentation
use rusteal_core::{OwnedStruct, RustealError, RustealResult, SubclassOf, UObjectRef, UeClass};

use crate::core_ue::FTransform;
use crate::engine::{Actor, ActorExt, Pawn, World};

fn warn_no_root_component(handle: rusteal_ffi::UObjectHandle) {
    let actor_ref: UObjectRef<Actor> = unsafe { UObjectRef::from_raw(handle) };

    if let Ok(actual_class) = actor_ref.get_class() {
        if actual_class == Actor::static_class()
            || actual_class == Pawn::static_class()
        {
            return;
        }
    }

    if let Ok(checked) = actor_ref.checked() {
        let root = checked.k2_get_root_component();

        if !root.is_valid() {
            rusteal_core::ulog!(rusteal_core::LOG_WARNING,
                "[Rusteal] spawn_actor: spawned actor has no RootComponent — \
                 spawn transform will be ignored and set_actor_location will fail. \
                 Consider inheriting from a class with a default RootComponent."
            );
        }
    }
}

#[repr(u8)]
#[derive(Clone, Copy, Debug, Default)]
pub enum SpawnCollisionMethod {
    #[default]
    Undefined = 0,
    AlwaysSpawn = 1,
    AdjustIfPossibleButAlwaysSpawn = 2,
    AdjustIfPossibleButDontSpawnIfColliding = 3,
    DontSpawnIfColliding = 4,
}

pub trait ObjectWorldExt {
    fn get_world(&self) -> RustealResult<UObjectRef<World>>;
}

impl<T: UeClass> ObjectWorldExt for UObjectRef<T> {
    fn get_world(&self) -> RustealResult<UObjectRef<World>> {
        let handle = rusteal_core::world::get_world_raw(self.checked()?.raw())?;

        Ok(unsafe { UObjectRef::from_raw(handle) })
    }
}

#[derive(Clone, Copy, Debug, Default)]
pub struct SpawnParams {
    pub owner: Option<UObjectRef<Actor>>,
    pub instigator: Option<UObjectRef<Pawn>>,
    pub collision: SpawnCollisionMethod,
}

impl SpawnParams {
    fn owner_handle(&self) -> RustealResult<rusteal_ffi::UObjectHandle> {
        match self.owner {
            Some(owner) if !owner.raw().is_null() => Ok(owner.checked()?.raw()),
            _ => Ok(rusteal_ffi::UObjectHandle::null()),
        }
    }

    fn instigator_handle(&self) -> RustealResult<rusteal_ffi::UObjectHandle> {
        match self.instigator {
            Some(instigator) if !instigator.raw().is_null() => Ok(instigator.checked()?.raw()),
            _ => Ok(rusteal_ffi::UObjectHandle::null()),
        }
    }
}

pub trait WorldSpawnExt {
    fn spawn_actor<T: UeClass>(
        &self,
        transform: &OwnedStruct<FTransform>,
    ) -> RustealResult<UObjectRef<T>>;

    fn spawn_actor_with_owner<T: UeClass>(
        &self,
        transform: &OwnedStruct<FTransform>,
        owner: &UObjectRef<Actor>,
    ) -> RustealResult<UObjectRef<T>>;

    fn spawn_actor_of_class<T: UeClass>(
        &self,
        class: SubclassOf<T>,
        transform: &OwnedStruct<FTransform>,
    ) -> RustealResult<UObjectRef<T>>;

    fn spawn_actor_deferred<T: UeClass>(
        &self,
        transform: &OwnedStruct<FTransform>,
    ) -> RustealResult<UObjectRef<T>>;

    fn spawn_actor_deferred_full<T: UeClass>(
        &self,
        transform: &OwnedStruct<FTransform>,
        params: SpawnParams,
    ) -> RustealResult<UObjectRef<T>>;

    fn spawn_actor_deferred_of_class<T: UeClass>(
        &self,
        class: SubclassOf<T>,
        transform: &OwnedStruct<FTransform>,
        params: SpawnParams,
    ) -> RustealResult<UObjectRef<T>>;

    fn finish_spawning(
        &self,
        actor: &UObjectRef<Actor>,
        transform: &OwnedStruct<FTransform>,
    ) -> RustealResult<()>;

    fn get_all_actors_of_class<T: UeClass>(&self) -> RustealResult<Vec<UObjectRef<T>>>;
}

impl WorldSpawnExt for UObjectRef<World> {
    fn spawn_actor<T: UeClass>(
        &self,
        transform: &OwnedStruct<FTransform>,
    ) -> RustealResult<UObjectRef<T>> {
        let world = self.checked()?.raw();
        let class = T::static_class();
        let null_owner = rusteal_ffi::UObjectHandle::null();

        let handle = rusteal_core::world::spawn_actor_raw(
            world,
            class,
            &transform.to_bytes(),
            null_owner,
        )?;

        warn_no_root_component(handle);

        Ok(unsafe { UObjectRef::from_raw(handle) })
    }

    fn spawn_actor_with_owner<T: UeClass>(
        &self,
        transform: &OwnedStruct<FTransform>,
        owner: &UObjectRef<Actor>,
    ) -> RustealResult<UObjectRef<T>> {
        let world = self.checked()?.raw();
        let class = T::static_class();
        let owner_handle = owner.checked()?.raw();

        let handle = rusteal_core::world::spawn_actor_raw(
            world,
            class,
            &transform.to_bytes(),
            owner_handle,
        )?;

        warn_no_root_component(handle);

        Ok(unsafe { UObjectRef::from_raw(handle) })
    }

    fn spawn_actor_of_class<T: UeClass>(
        &self,
        class: SubclassOf<T>,
        transform: &OwnedStruct<FTransform>,
    ) -> RustealResult<UObjectRef<T>> {
        let world = self.checked()?.raw();

        if class.is_null() {
            return Err(RustealError::null_argument());
        }

        let handle = rusteal_core::world::spawn_actor_raw(
            world,
            class.raw(),
            &transform.to_bytes(),
            rusteal_ffi::UObjectHandle::null(),
        )?;

        warn_no_root_component(handle);

        Ok(unsafe { UObjectRef::from_raw(handle) })
    }

    fn spawn_actor_deferred<T: UeClass>(
        &self,
        transform: &OwnedStruct<FTransform>,
    ) -> RustealResult<UObjectRef<T>> {
        let world = self.checked()?.raw();
        let class = T::static_class();
        let null = rusteal_ffi::UObjectHandle::null();

        let handle = rusteal_core::world::spawn_actor_deferred_raw(
            world, class, &transform.to_bytes(), null, null, 0,
        )?;

        warn_no_root_component(handle);

        Ok(unsafe { UObjectRef::from_raw(handle) })
    }

    fn spawn_actor_deferred_full<T: UeClass>(
        &self,
        transform: &OwnedStruct<FTransform>,
        params: SpawnParams,
    ) -> RustealResult<UObjectRef<T>> {
        self.spawn_actor_deferred_of_class(SubclassOf::base(), transform, params)
    }

    fn spawn_actor_deferred_of_class<T: UeClass>(
        &self,
        class: SubclassOf<T>,
        transform: &OwnedStruct<FTransform>,
        params: SpawnParams,
    ) -> RustealResult<UObjectRef<T>> {
        let world = self.checked()?.raw();

        if class.is_null() {
            return Err(RustealError::null_argument());
        }

        let handle = rusteal_core::world::spawn_actor_deferred_raw(
            world,
            class.raw(),
            &transform.to_bytes(),
            params.owner_handle()?,
            params.instigator_handle()?,
            params.collision as u8,
        )?;

        warn_no_root_component(handle);

        Ok(unsafe { UObjectRef::from_raw(handle) })
    }

    fn finish_spawning(
        &self,
        actor: &UObjectRef<Actor>,
        transform: &OwnedStruct<FTransform>,
    ) -> RustealResult<()> {
        let actor_handle = actor.checked()?.raw();

        rusteal_core::world::finish_spawning_raw(actor_handle, &transform.to_bytes())
    }

    fn get_all_actors_of_class<T: UeClass>(&self) -> RustealResult<Vec<UObjectRef<T>>> {
        let world = self.checked()?.raw();
        let class = T::static_class();
        let handles = rusteal_core::world::get_all_actors_of_class_raw(world, class)?;

        Ok(handles
            .into_iter()
            .map(|h| unsafe { UObjectRef::from_raw(h) })
            .collect())
    }
}

pub fn find_object<T: UeClass>(path: &str) -> RustealResult<UObjectRef<T>> {
    let class = T::static_class();
    let handle = rusteal_core::world::find_object_raw(class, path)?;
    Ok(unsafe { UObjectRef::from_raw(handle) })
}

pub fn load_object<T: UeClass>(path: &str) -> RustealResult<UObjectRef<T>> {
    let class = T::static_class();
    let handle = rusteal_core::world::load_object_raw(class, path)?;
    Ok(unsafe { UObjectRef::from_raw(handle) })
}

pub fn load_class<T: UeClass>(path: &str) -> RustealResult<SubclassOf<T>> {
    let class = crate::core_ue::Class::static_class();
    let handle = rusteal_core::world::load_object_raw(class, path)?;
    SubclassOf::from_class(rusteal_ffi::UClassHandle(handle.0))
}

pub fn new_object<T: UeClass>(outer: &UObjectRef<impl UeClass>) -> RustealResult<UObjectRef<T>> {
    let outer_handle = outer.checked()?.raw();
    let class = T::static_class();
    let handle = rusteal_core::world::new_object_raw(outer_handle, class)?;
    Ok(unsafe { UObjectRef::from_raw(handle) })
}

pub fn new_object_transient<T: UeClass>() -> RustealResult<UObjectRef<T>> {
    let class = T::static_class();
    let null_outer = rusteal_ffi::UObjectHandle::null();
    let handle = rusteal_core::world::new_object_raw(null_outer, class)?;
    Ok(unsafe { UObjectRef::from_raw(handle) })
}

pub fn spawn_actor_dynamic(
    world: &UObjectRef<World>,
    class: rusteal_ffi::UClassHandle,
    transform: &OwnedStruct<FTransform>,
) -> RustealResult<rusteal_ffi::UObjectHandle> {
    let world_handle = world.checked()?.raw();
    let null_owner = rusteal_ffi::UObjectHandle::null();
    rusteal_core::world::spawn_actor_raw(world_handle, class, &transform.to_bytes(), null_owner)
}

pub fn new_object_dynamic(
    outer: rusteal_ffi::UObjectHandle,
    class: rusteal_ffi::UClassHandle,
) -> RustealResult<rusteal_ffi::UObjectHandle> {
    rusteal_core::world::new_object_raw(outer, class)
}