godot-bevy 0.11.0

Bridge between Bevy ECS and Godot 4 for Rust-powered game development
Documentation
//! Auto-sync bundle system for automatic bundle registration
//!
//! This module provides a trait-based system for automatically discovering and registering
//! Bevy bundle creation functions generated by the `#[derive(BevyBundle)]` macro.
//!
//! ## Overview
//!
//! The auto-sync system eliminates the need to manually register bundle sync plugins in your
//! Bevy app. When you use `#[derive(BevyBundle)]`, the macro automatically
//! generates the necessary bundle creation function and registers it with the global registry.

use bevy_app::App;
use bevy_ecs::{entity::Entity, system::Commands};
use std::sync::OnceLock;
use tracing::trace;

use crate::interop::{GodotAccess, GodotNodeHandle};

/// Function type for creating bundles from Godot nodes
pub type BundleCreatorFn = fn(&mut Commands, Entity, &mut GodotAccess, GodotNodeHandle) -> bool;

/// Registry entry for auto-sync bundles using the inventory crate
pub struct AutoSyncBundleRegistry {
    /// The Godot class name this bundle applies to
    pub godot_class_name: &'static str,
    /// Function to create and add the bundle to an entity
    pub create_bundle_fn: BundleCreatorFn,
}

// Collect all auto-sync bundle registrations
crate::inventory::collect!(AutoSyncBundleRegistry);

// Global registry for fast runtime lookup - initialized once, read many times
static BUNDLE_REGISTRY: OnceLock<Vec<&'static AutoSyncBundleRegistry>> = OnceLock::new();

/// Initialize the global bundle registry
///
/// This function is called automatically by the `GodotPlugin` and will discover
/// all auto-sync bundle registrations that were generated with `autosync=true`.
pub fn register_all_autosync_bundles(_app: &mut App) {
    BUNDLE_REGISTRY.get_or_init(|| {
        let entries: Vec<&'static AutoSyncBundleRegistry> =
            crate::inventory::iter::<AutoSyncBundleRegistry>
                .into_iter()
                .collect();

        tracing::debug!("Registered {} AutoSyncBundle entries", entries.len());
        entries
    });
}

/// Try to add appropriate bundles to an entity based on its Godot node type
pub fn try_add_bundles_for_node(
    commands: &mut Commands,
    entity: Entity,
    godot: &mut GodotAccess,
    node_handle: GodotNodeHandle,
) {
    // OnceLock::get() returns Option<&T> with no locking overhead after initialization
    if let Some(entries) = BUNDLE_REGISTRY.get() {
        for entry in entries {
            // Try to create and add the bundle
            // The function will check if the node is the right type and if the bundle is already added
            if (entry.create_bundle_fn)(commands, entity, godot, node_handle) {
                trace!(
                    "Added bundle for {} to entity {:?}",
                    entry.godot_class_name, entity
                );
            }
        }
    }
}