silo 0.1.0

多引擎融合框架 - 整合 Bevy、Godot 和 Unity 的跨引擎通信调度平台
Documentation
use godot::{
    classes::{
        AnimationPlayer, Label, Node, Node2D, Node3D, Sprite2D,
        class_macros::private::virtuals::Os::{Color, Transform2D, Transform3D, Vector2},
    },
    obj::{GdMut, WithBaseField},
    prelude::{Basis, EulerOrder, Gd, Vector3},
};

impl From<&crate::view::Transform2D> for Transform2D {
    fn from(v: &crate::view::Transform2D) -> Self {
        Self::from_angle_scale_skew_origin(
            v.rotation,
            Vector2::from(&v.scale),
            v.skew,
            Vector2::from(&v.position),
        )
    }
}

impl From<&crate::view::Vec2> for Vector2 {
    fn from(v: &crate::view::Vec2) -> Self {
        Self::new(v.x, v.y)
    }
}

fn set_transform_2d(
    _world: &crate::godot::nodes::SiloWorld,
    s: GdMut<crate::godot::nodes::SiloVariant>,
    v: &crate::view::Transform2D,
) {
    if let Some(p) = s.base().get_parent() {
        if let Ok(mut p) = p.try_cast::<Node2D>() {
            p.set_transform(Transform2D::from(v));
        }
    }
}

impl From<&crate::view::Vec3> for Vector3 {
    fn from(v: &crate::view::Vec3) -> Self {
        Self::new(v.x, v.y, v.z)
    }
}

impl From<&crate::view::Transform3D> for Transform3D {
    fn from(v: &crate::view::Transform3D) -> Self {
        // Create basis from rotation
        let basis = Basis::from_euler(EulerOrder::XYZ, Vector3::from(&v.rotation));
        // Apply scale to basis
        let scaled_basis = basis.scaled(Vector3::from(&v.scale));
        // Create transform with basis and origin
        Self::new(scaled_basis, Vector3::from(&v.position))
    }
}

fn set_transform_3d(
    _world: &crate::godot::nodes::SiloWorld,
    s: GdMut<crate::godot::nodes::SiloVariant>,
    v: &crate::view::Transform3D,
) {
    if let Some(p) = s.base().get_parent() {
        if let Ok(mut p) = p.try_cast::<Node3D>() {
            p.set_transform(Transform3D::from(v));
        }
    }
}

impl From<&crate::view::Color> for Color {
    fn from(v: &crate::view::Color) -> Self {
        Self::from_rgba(v.r, v.g, v.b, v.a)
    }
}

fn set_color(
    _world: &crate::godot::nodes::SiloWorld,
    s: GdMut<crate::godot::nodes::SiloVariant>,
    v: &crate::view::Color,
) {
    if let Some(p) = s.base().get_parent() {
        if let Ok(mut p) = p.try_cast::<Sprite2D>() {
            p.set_modulate(Color::from(v));
        }
    }
}

fn set_skin_str(
    world: &crate::godot::nodes::SiloWorld,
    mut s: Gd<Node>,
    skin: &str,
) -> Option<Gd<Node>> {
    if let Some(v) = s.find_child(skin) {
        return Some(v);
    } else {
        if let Some(skin_scene) = world.get_skin(&skin.to_string()) {
            let mut v = skin_scene
                .instantiate()
                .expect("Failed to instantiate skin");
            v.set_name(skin);
            s.add_child(&v);
            return Some(v);
        }
    }
    None
}

fn set_text(
    world: &crate::godot::nodes::SiloWorld,
    s: GdMut<crate::godot::nodes::SiloVariant>,
    v: &crate::view::Text,
) {
    if let Some(p) = s.base().get_parent() {
        if let Some(skin) = &v.skin {
            if let Some(node) = set_skin_str(world, p.clone(), skin) {
                if let Ok(mut label) = node.try_cast::<Label>() {
                    label.set_text(&v.text);
                }
            }
        } else if let Ok(mut label) = p.try_cast::<Label>() {
            label.set_text(&v.text);
        }
    }
}

fn find_child<T>(node: &Gd<Node>) -> Option<Gd<T>>
where
    T: godot::prelude::GodotClass + godot::prelude::Inherits<godot::prelude::Node>,
{
    for child in node.get_children().iter_shared() {
        if let Ok(found) = child.try_cast::<T>() {
            return Some(found);
        }
    }
    None
}

fn set_skin(
    world: &crate::godot::nodes::SiloWorld,
    s: GdMut<crate::godot::nodes::SiloVariant>,
    v: &crate::view::Skin,
) {
    if let Some(p) = s.base().get_parent() {
        if let Some(node) = set_skin_str(world, p.clone(), &v.skin) {
            if let Some(s) = &v.state {
                if let Some(mut ap_node) = find_child::<AnimationPlayer>(&node) {
                    ap_node.set_current_animation(s);
                    ap_node.play();
                }
            }
        }
    }
}

pub fn initialize() {
    crate::godot::reg::add_variant::<crate::view::Transform2D>(set_transform_2d);
    crate::godot::reg::add_variant::<crate::view::Transform3D>(set_transform_3d);
    crate::godot::reg::add_variant::<crate::view::Color>(set_color);
    crate::godot::reg::add_variant::<crate::view::Text>(set_text);
    crate::godot::reg::add_variant::<crate::view::Skin>(set_skin);
}