silo 0.1.0

多引擎融合框架 - 整合 Bevy、Godot 和 Unity 的跨引擎通信调度平台
Documentation
use std::collections::HashMap;

use godot::classes::*;
use godot::prelude::*;

use crate::godot::reg::set_variant;

#[derive(GodotClass)]
#[class(base=Node)]
pub struct SiloWorld {
    #[base]
    base: Base<Node>,
    #[export]
    pub world: i64,
    #[export]
    pub def_entries: Dictionary<GString, Option<Gd<PackedScene>>>,
    #[export]
    pub def_skins: Dictionary<GString, Option<Gd<PackedScene>>>,
    ch: crate::base::Chan,
    entitys: HashMap<u64, HashMap<u64, Gd<SiloObject>>>,
}

impl SiloWorld {
    pub fn get_skin(&self, t: &String) -> Option<Gd<PackedScene>> {
        self.def_skins.get(t.as_str()).flatten()
    }

    fn spawn(&mut self, id: u64, t: &String, world: u64) {
        godot_print!("spawn {} {} {}", id, t, world);

        let entity_to_instantiate: Option<Gd<PackedScene>> =
            self.def_entries.get(t.as_str()).flatten();

        if let Some(entity) = entity_to_instantiate {
            let mut object: Gd<Node> = entity.instantiate().expect("Failed to instantiate entity");
            let name = format!("{}#{}", t.replace("::", "#"), id);
            object.set_name(&name);
            // Try to cast to SiloObject and set properties
            match object.try_cast::<SiloObject>() {
                Ok(mut silo_object) => {
                    {
                        // New scope to drop the mutable borrow before add_child
                        let mut silo_object_mut = silo_object.bind_mut();
                        silo_object_mut.t = t.to_string();
                        silo_object_mut.id = id;
                        silo_object_mut.world = world;
                    }
                    // Add the SiloObject as a child
                    self.base_mut().add_child(&silo_object);
                    self.entitys
                        .entry(world)
                        .or_default()
                        .insert(id, silo_object);
                }
                Err(_) => {}
            }
        }
    }

    fn despawn(&mut self, id: u64, world: u64) {
        godot_print!("despawn {} {}", id, world);
        if let Some(object) = self.entitys.get_mut(&world).and_then(|map| map.remove(&id)) {
            self.base_mut().remove_child(&object);
        }
    }

    fn change(&self, id: u64, world: u64, t: &String, v: &bytes::Bytes) {
        godot_print!("change {} {} {} size:{}", id, world, t, v.len());
        if let Some(object) = self.entitys.get(&world).and_then(|map| map.get(&id)) {
            object.bind().set_value(self, t, v);
        }
    }
}

#[godot_api]
impl INode for SiloWorld {
    fn init(base: Base<Node>) -> Self {
        Self {
            base,
            def_entries: Dictionary::new(),
            def_skins: Dictionary::new(),
            ch: crate::base::RUNTIME.chan(),
            entitys: HashMap::new(),
            world: 0,
        }
    }

    fn ready(&mut self) {
        godot_print!("ready");
    }

    fn physics_process(&mut self, _delta: f64) {
        while let Ok(v) = self.ch.rx.try_recv() {
            match v {
                crate::base::Message::Event(event) => match event {
                    crate::base::Event::Spawn { id, t, world } => {
                        if self.world as u64 == world {
                            self.spawn(id, &t, world);
                        }
                    }
                    crate::base::Event::Despawn { id, world } => {
                        if self.world as u64 == world {
                            self.despawn(id, world);
                        }
                    }
                    crate::base::Event::Change { id, world, t, v } => {
                        if self.world as u64 == world {
                            self.change(id, world, &t, &v);
                        }
                    }
                    _ => {}
                },
                _ => {}
            }
        }
    }
}

#[derive(GodotClass)]
#[class(base=Node)]
pub struct SiloObject {
    #[base]
    base: Base<Node>,
    t: String,
    id: u64,
    world: u64,
}

impl SiloObject {
    fn set_value(&self, world: &crate::godot::nodes::SiloWorld, t: &String, v: &bytes::Bytes) {
        let pattern = t.replace("::", "#");
        let vs = self.base().find_children(&pattern);
        for i in 0..vs.len() {
            if let Some(node) = vs.get(i) {
                // Try to cast to SiloVariant and call set_value
                if let Ok(mut silo_variant) = node.try_cast::<SiloVariant>() {
                    set_variant(world, silo_variant.bind_mut(), t, v);
                }
            }
        }
    }
}

#[godot_api]
impl INode for SiloObject {
    fn init(base: Base<Node>) -> Self {
        Self {
            base,
            t: String::new(),
            id: 0,
            world: 0,
        }
    }
}

#[derive(GodotClass)]
#[class(init,base=Node)]
pub struct SiloVariant {
    #[base]
    base: Base<Node>,
}

#[godot_api]
impl INode for SiloVariant {}