Skip to main content

godot_bevy/plugins/transforms/
plugin.rs

1use bevy_app::{App, Last, Plugin, PreUpdate};
2use bevy_ecs::{schedule::IntoScheduleConfigs, system::Res};
3use bevy_transform::components::Transform;
4use godot::classes::{Node2D, Node3D};
5
6use crate::plugins::core::AppSceneTreeExt;
7use crate::plugins::transforms::IntoBevyTransform;
8use crate::plugins::transforms::{GodotTransformConfig, TransformSyncMode};
9
10use super::change_filter::TransformSyncMetadata;
11use super::sync_systems::{post_update_godot_transforms, pre_update_godot_transforms};
12
13pub struct GodotTransformSyncPlugin {
14    /// The mode for syncing transforms between Godot and Bevy.
15    /// Note: This setting is only relevant when `auto_sync` is true.
16    /// When `auto_sync` is false, this value is ignored since no automatic sync systems run.
17    pub sync_mode: TransformSyncMode,
18    /// When true (default), enables automatic transform syncing systems.
19    /// When false, still registers Transform and TransformSyncMetadata components
20    /// but allows defining custom sync systems using the add_transform_sync_systems_*! macros.
21    pub auto_sync: bool,
22}
23
24impl Default for GodotTransformSyncPlugin {
25    fn default() -> Self {
26        Self {
27            sync_mode: TransformSyncMode::default(),
28            auto_sync: true,
29        }
30    }
31}
32
33impl Plugin for GodotTransformSyncPlugin {
34    fn build(&self, app: &mut App) {
35        // Register Transform component with custom initialization that reads from Godot
36        app.register_scene_tree_component_with_init::<Transform, _>(|entity, node| {
37            if let Some(node3d) = node.try_get::<Node3D>() {
38                entity.insert(node3d.get_transform().to_bevy_transform());
39            } else if let Some(node2d) = node.try_get::<Node2D>() {
40                entity.insert(node2d.get_transform().to_bevy_transform());
41            }
42        })
43        // Register metadata component with default - this avoids the 1-frame delay
44        .register_scene_tree_component::<TransformSyncMetadata>();
45
46        // Register the transform configuration resource with the plugin's config
47        app.insert_resource(GodotTransformConfig {
48            sync_mode: self.sync_mode,
49        });
50
51        // Only add automatic sync systems if auto_sync is enabled
52        if self.auto_sync {
53            // Add systems that sync godot -> bevy transforms when two-way syncing enabled
54            app.add_systems(
55                PreUpdate,
56                pre_update_godot_transforms.run_if(transform_sync_twoway_enabled),
57            );
58
59            // Add systems that sync bevy -> godot transforms when one or two-way syncing enabled
60            app.add_systems(
61                Last,
62                post_update_godot_transforms.run_if(transform_sync_enabled),
63            );
64        }
65    }
66}
67
68fn transform_sync_enabled(config: Res<GodotTransformConfig>) -> bool {
69    // aka one way or two way
70    config.sync_mode != TransformSyncMode::Disabled
71}
72
73fn transform_sync_twoway_enabled(config: Res<GodotTransformConfig>) -> bool {
74    config.sync_mode == TransformSyncMode::TwoWay
75}