unrust/
unity.rs

1use std::{sync::Arc, time::Duration};
2
3use bevy::{
4    app::PluginGroupBuilder,
5    asset::{AssetPlugin, ChangeWatcher},
6    prelude::*,
7    tasks::tick_global_task_pools_on_main_thread,
8    time::TimePlugin,
9};
10use inbuilt::*;
11
12pub type UpdateFn = extern "C" fn(data: *const InbuiltEntityData, len: usize);
13pub type CreateFn = extern "C" fn(data: *const InbuiltEntityData, len: usize);
14pub type DestroyFn = extern "C" fn(entity: *const UnityEntity, len: usize);
15
16#[derive(Component, Copy, Clone)]
17pub struct InstantiateEntity {
18    pub entity: UnityEntity,
19}
20
21#[derive(Component, Copy, Clone)]
22pub struct DestroyEntity {
23    pub entity: UnityEntity,
24}
25
26#[derive(Component)]
27pub struct PrefabComponent {
28    pub ref_id: i32,
29    pub guid: UnityEntity,
30}
31
32#[repr(C)]
33pub struct PrefabData {
34    pub ref_id: i32,
35    pub guids: *mut UnityEntity,
36    pub len: usize,
37}
38
39#[derive(Resource)]
40pub struct CallbacksNonSend {
41    create_fn: Arc<CreateFn>,
42    update_fn: Arc<UpdateFn>,
43    destroy_fn: Arc<DestroyFn>,
44}
45
46pub(crate) struct UnityPlugins {
47    base_path: String,
48    update_fn: Arc<UpdateFn>,
49    create_fn: Arc<CreateFn>,
50    destroy_fn: Arc<DestroyFn>,
51}
52
53impl UnityPlugins {
54    pub(crate) fn new(
55        base_path: String,
56        create_fn: CreateFn,
57        update_fn: UpdateFn,
58        destroy_fn: DestroyFn,
59    ) -> UnityPlugins {
60        UnityPlugins {
61            base_path,
62            update_fn: Arc::new(update_fn),
63            create_fn: Arc::new(create_fn),
64            destroy_fn: Arc::new(destroy_fn),
65        }
66    }
67}
68
69impl Plugin for UnityPlugins {
70    fn build(&self, app: &mut App) {
71        let update_fn = self.update_fn.clone();
72        let create_fn = self.create_fn.clone();
73        let destroy_fn = self.destroy_fn.clone();
74        app.add_plugins(BasePlugins)
75            .add_plugins(AssetPlugin {
76                asset_folder: self.base_path.clone(),
77                watch_for_changes: ChangeWatcher::with_delay(Duration::from_millis(200)),
78            })
79            .insert_non_send_resource(CallbacksNonSend {
80                create_fn,
81                update_fn,
82                destroy_fn,
83            })
84            .add_systems(
85                PostUpdate,
86                (
87                    create_unity_system,
88                    update_unity_system,
89                    destroy_unity_system,
90                ),
91            );
92    }
93}
94
95fn create_unity_system(
96    callbacks_res: NonSend<CallbacksNonSend>,
97    mut commands: Commands,
98    created: Query<(Entity, &InstantiateEntity, &Transform)>,
99) {
100    let mut creates = vec![];
101    let mut counts = vec![];
102    created.iter().for_each(|(_, _, transform)| {
103        let mut count = 0;
104        creates.push(InbuiltData {
105            ty: InbuiltTypes::UnityTransform,
106            value: InbuiltComponents {
107                UnityTransform: transform.into(),
108            },
109        });
110
111        count += 1;
112        counts.push(count);
113    });
114
115    let mut count = 0;
116    let creates = created
117        .iter()
118        .enumerate()
119        .map(|(index, (entity, guid, _))| {
120            let comp_count = counts[index];
121            let ptr = creates[count..(count + comp_count)].as_ptr();
122            count += comp_count;
123
124            let mut comm = commands.entity(entity);
125            comm.despawn();
126
127            InbuiltEntityData {
128                entity: guid.entity,
129                data: ptr,
130                len: comp_count,
131            }
132        })
133        .collect::<Vec<InbuiltEntityData>>();
134
135    let ptr = creates.as_ptr();
136
137    (callbacks_res.create_fn)(ptr, creates.len());
138}
139
140fn update_unity_system(
141    callbacks_res: NonSend<CallbacksNonSend>,
142    entities: Query<(&UnityEntity, &GlobalTransform), Changed<GlobalTransform>>, // add more inbuilt components here
143) {
144    let mut updates = vec![];
145    let mut counts = vec![];
146    entities.iter().for_each(|(_, transform)| {
147        let mut count = 0;
148        updates.push(InbuiltData {
149            ty: InbuiltTypes::UnityTransform,
150            value: InbuiltComponents {
151                UnityTransform: transform.into(),
152            },
153        });
154
155        count += 1;
156        counts.push(count);
157    });
158
159    let mut count = 0;
160    let updates = entities
161        .iter()
162        .enumerate()
163        .map(|(index, (unity_entity, _))| {
164            let comp_count = counts[index];
165            let ptr = updates[count..(count + comp_count)].as_ptr();
166            count += comp_count;
167
168            InbuiltEntityData {
169                entity: *unity_entity,
170                data: ptr,
171                len: comp_count,
172            }
173        })
174        .collect::<Vec<InbuiltEntityData>>();
175
176    let ptr = updates.as_ptr();
177    (callbacks_res.update_fn)(ptr, updates.len());
178}
179
180fn destroy_unity_system(
181    mut commands: Commands,
182    callbacks_res: NonSend<CallbacksNonSend>,
183    destroyed: Query<(Entity, &DestroyEntity)>,
184) {
185    let destroyed_entities = destroyed
186        .iter()
187        .map(|(entity, v)| {
188            let mut comm = commands.entity(entity);
189            comm.despawn();
190
191            v.entity
192        })
193        .collect::<Vec<UnityEntity>>();
194
195    (callbacks_res.destroy_fn)(destroyed_entities.as_ptr(), destroyed_entities.len());
196}
197
198pub(crate) fn start_app(app: &mut App) {
199    // copy of schedule
200    while !app.ready() {
201        #[cfg(not(target_arch = "wasm32"))]
202        tick_global_task_pools_on_main_thread();
203    }
204    app.finish();
205    app.cleanup();
206}
207
208struct BasePlugins;
209
210impl PluginGroup for BasePlugins {
211    fn build(self) -> PluginGroupBuilder {
212        PluginGroupBuilder::start::<Self>()
213            .add(TaskPoolPlugin::default())
214            .add(TypeRegistrationPlugin)
215            .add(FrameCountPlugin)
216            .add(TransformPlugin)
217            .add(HierarchyPlugin)
218            .add(TimePlugin)
219    }
220}