rusteal 0.8.0

Rust bindings for Unreal Engine 5.8.2
use bindings::engine::{
    Actor, KismetMaterialLibrary, MaterialInstanceDynamic, MaterialInstanceDynamicExt,
    MaterialInterface, PrimitiveComponentExt, StaticMeshComponent,
};
use bindings::prelude::*;
use rusteal_runtime::runtime::{FName, LinearColor, RustealResult, UObjectRef};
use rusteal_runtime::{uclass, uclass_impl};

use crate::components;

use crate::trigger::TriggerSwitch;

const ON_COLOR: LinearColor = LinearColor {
    r: 0.155_339,
    g: 0.630_208,
    b: 0.029_457,
    a: 2.0,
};

const OFF_COLOR: LinearColor = LinearColor {
    r: 0.713_542,
    g: 0.020_312,
    b: 0.035_173,
    a: 0.4,
};

#[uclass(parent = Actor)]
pub struct TriggerLight {
    #[uproperty(EditAnywhere, BlueprintReadWrite, name = "Trigger", category = "Light")]
    trigger: UObjectRef<TriggerSwitch>,

    #[uproperty(EditAnywhere, BlueprintReadWrite, category = "Light")]
    light_material: UObjectRef<MaterialInterface>,

    #[uproperty(BlueprintReadOnly, name = "MID_LIght", category = "Light")]
    mid_light: UObjectRef<MaterialInstanceDynamic>,

    #[uproperty(BlueprintReadOnly, category = "Light", default = false)]
    is_on: bool,
}

impl TriggerLight {
    fn sphere(&self) -> RustealResult<UObjectRef<StaticMeshComponent>> {
        components::named(self.as_ref().upcast_to(), "Sphere")
    }

    fn sphere1(&self) -> RustealResult<UObjectRef<StaticMeshComponent>> {
        components::named(self.as_ref().upcast_to(), "Sphere1")
    }

    fn cylinder(&self) -> RustealResult<UObjectRef<StaticMeshComponent>> {
        components::named(self.as_ref().upcast_to(), "Cylinder")
    }
}

#[uclass_impl]
impl TriggerLight {
    #[ufunction(Override)]
    fn receive_begin_play(&mut self) {
        if let Err(e) = self.begin_play() {
            log::warn!("[Interactables] light: {e}");
        }
    }

    #[ufunction]
    fn toggle(&mut self) {
        self.set_is_on(!self.is_on());
        let color = if self.is_on() { ON_COLOR } else { OFF_COLOR };

        if let Ok(light) = self.mid_light().checked() {
            light.set_vector_parameter_value(
                FName::new("Col").handle(),
                &FLinearColor::from_linear_color(color),
            );
        }
    }
}

impl TriggerLight {
    fn begin_play(&mut self) -> RustealResult<()> {
        let me = self.as_ref();

        if let Ok(trigger) = TriggerSwitch::from_obj(self.trigger()) {
            trigger.trigger_add_ufunction(&me, "Toggle")?;
        }

        let material = KismetMaterialLibrary::create_dynamic_material_instance(
            me.upcast_to(),
            self.light_material(),
            None,
            None,
        );
        self.set_mid_light(material);

        for mesh in [self.cylinder(), self.sphere(), self.sphere1()] {
            if let Ok(mesh) = mesh.and_then(|m| m.checked()) {
                mesh.set_material(0, material.upcast_to());
            }
        }

        Ok(())
    }
}