silo 0.1.0

多引擎融合框架 - 整合 Bevy、Godot 和 Unity 的跨引擎通信调度平台
Documentation
use bevy_app::prelude::*;
use bevy_ecs::prelude::*;
use bytes::Bytes;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

pub type OnEvent = fn(Bytes, &mut Commands<'_, '_>);

#[derive(Component)]
pub struct NetWorld {
    pub id: u64,
}

#[derive(Resource)]
pub struct Context {
    pub ch: crate::base::Chan,
    events: HashMap<String, OnEvent>,
    entitys: HashMap<Entity, u64>,
}

impl Default for Context {
    fn default() -> Self {
        Self {
            ch: crate::base::RUNTIME.chan(),
            events: HashMap::new(),
            entitys: HashMap::new(),
        }
    }
}

impl Drop for Context {
    fn drop(&mut self) {
        self.ch.close();
    }
}

#[derive(Default)]
pub struct SiloPlugin;

impl Plugin for SiloPlugin {
    fn build(&self, app: &mut App) {
        app.init_resource::<Context>();
        app.add_systems(PreUpdate, update_system);
        app.configure_sets(
            PostUpdate,
            (
                NetSystemSet::Spawn,
                NetSystemSet::Change,
                NetSystemSet::Despawn,
            )
                .chain(),
        );
    }
}

#[derive(Debug, Hash, PartialEq, Eq, Clone, SystemSet)]
enum NetSystemSet {
    Spawn,
    Change,
    Despawn,
}

pub trait SiloApp {
    fn add_net_event<T: Event + for<'a> Deserialize<'a>>(&mut self)
    where
        for<'a> <T as Event>::Trigger<'a>: Default;
    fn add_net_object<T: Component>(&mut self);
    fn add_net_variant<T: Component + Serialize>(&mut self);
}

impl SiloApp for App {
    fn add_net_event<T: Event + for<'a> Deserialize<'a>>(&mut self)
    where
        for<'a> <T as Event>::Trigger<'a>: Default,
    {
        if let Some(mut ctx) = self.world_mut().get_resource_mut::<Context>() {
            ctx.events
                .insert(std::any::type_name::<T>().to_string(), on_event::<T>);
        }
    }
    fn add_net_object<T: Component>(&mut self) {
        self.add_systems(
            PostUpdate,
            (
                reg_object_add::<T>.in_set(NetSystemSet::Spawn),
                reg_object_removed::<T>.in_set(NetSystemSet::Despawn),
            ),
        );
    }
    fn add_net_variant<T: Component + Serialize>(&mut self) {
        self.add_systems(
            PostUpdate,
            reg_variant_change::<T>.in_set(NetSystemSet::Change),
        );
    }
}

fn on_event<T: Event + for<'a> Deserialize<'a>>(v: Bytes, commands: &mut Commands<'_, '_>)
where
    for<'a> <T as Event>::Trigger<'a>: Default,
{
    let mut de = serde_cbor::de::Deserializer::from_slice(&v);
    if let Ok(event) = T::deserialize(&mut de) {
        commands.trigger(event);
    }
}

fn update_system(mut commands: Commands, mut ctx: ResMut<Context>) {
    while let Ok(v) = ctx.ch.rx.try_recv() {
        match v {
            crate::base::Message::Event(e) => match e {
                crate::base::Event::Invoke { t, v, world: _ } => {
                    if let Some(f) = ctx.events.get(&t) {
                        f(v, &mut commands)
                    }
                }
                _ => {}
            },
            _ => {}
        }
    }
}

fn reg_object_add<E: Component>(
    query: Query<(Entity, &NetWorld), Added<E>>,
    mut ctx: ResMut<Context>,
) {
    for (entity, w) in query.iter() {
        let id: u64 = entity.to_bits();
        ctx.entitys.insert(entity, w.id);
        let _ = ctx
            .ch
            .tx
            .send(crate::base::Message::Event(crate::base::Event::Spawn {
                id,
                t: std::any::type_name::<E>().to_string(),
                world: w.id,
            }));
    }
}

fn reg_object_removed<E: Component>(mut removed: RemovedComponents<E>, mut ctx: ResMut<Context>) {
    for entity in removed.read() {
        if let Some(w) = ctx.entitys.remove(&entity) {
            let id: u64 = entity.to_bits();
            let _ = ctx
                .ch
                .tx
                .send(crate::base::Message::Event(crate::base::Event::Despawn {
                    id,
                    world: w,
                }));
        }
    }
}

fn reg_variant_change<V: Component + Serialize>(
    changed: Query<(Entity, &V, &NetWorld), Changed<V>>,
    ctx: Res<Context>,
) {
    for (entity, v, w) in changed.iter() {
        let id: u64 = entity.to_bits();
        if let Ok(v) = serde_cbor::to_vec(v) {
            let _ = ctx
                .ch
                .tx
                .send(crate::base::Message::Event(crate::base::Event::Change {
                    id,
                    t: std::any::type_name::<V>().to_string(),
                    v: Bytes::from(v),
                    world: w.id,
                }));
        }
    }
}