bevy_mod_scripting_bindings/
script_component.rs1use super::{ScriptComponentRegistration, ScriptValue};
4use ::{
5 bevy_app::{App, Plugin},
6 bevy_ecs::component::{Component, Mutable, StorageType},
7 bevy_reflect::Reflect,
8};
9use bevy_ecs::resource::Resource;
10use bevy_platform::collections::HashMap;
11use bevy_reflect::std_traits::ReflectDefault;
12use parking_lot::RwLock;
13use std::sync::Arc;
14#[derive(Reflect, Clone, Default)]
16#[reflect(Default)]
17pub struct DynamicComponent {
18 data: ScriptValue,
19}
20
21pub struct DynamicComponentInfo {
23 pub name: String,
25 pub registration: ScriptComponentRegistration,
27}
28
29impl Component for DynamicComponent {
30 const STORAGE_TYPE: StorageType = StorageType::Table;
31 type Mutability = Mutable;
32}
33
34#[derive(Clone, Resource, Default)]
36pub struct AppScriptComponentRegistry(pub Arc<RwLock<ScriptComponentRegistry>>);
37
38#[profiling::all_functions]
39impl AppScriptComponentRegistry {
40 pub fn read(&self) -> parking_lot::RwLockReadGuard<'_, ScriptComponentRegistry> {
42 self.0.read()
43 }
44
45 pub fn write(&self) -> parking_lot::RwLockWriteGuard<'_, ScriptComponentRegistry> {
47 self.0.write()
48 }
49}
50
51#[derive(Default)]
52pub struct ScriptComponentRegistry {
54 components: HashMap<String, DynamicComponentInfo>,
55}
56
57#[profiling::all_functions]
58impl ScriptComponentRegistry {
59 pub fn register(&mut self, info: DynamicComponentInfo) {
61 self.components.insert(info.name.clone(), info);
62 }
63
64 pub fn get(&self, name: &str) -> Option<&DynamicComponentInfo> {
66 self.components.get(name)
67 }
68}
69
70pub struct DynamicScriptComponentPlugin;
72
73impl Plugin for DynamicScriptComponentPlugin {
74 fn build(&self, app: &mut App) {
75 app.init_resource::<AppScriptComponentRegistry>()
76 .register_type::<DynamicComponent>();
77 }
78}
79
80#[cfg(test)]
81mod test {
82 use bevy_ecs::world::World;
83 use bevy_mod_scripting_world::{WorldAccessGuard, WorldGuard};
84
85 use crate::{CurrentScriptAttachment, WorldExtensions};
86
87 use super::*;
88
89 #[test]
90 fn test_script_component() {
91 let mut world = World::new();
92 world.init_resource::<AppScriptComponentRegistry>();
93 let cache = WorldGuard::setup_cache(&world, CurrentScriptAttachment::default());
94 let registration = {
95 let guard = WorldAccessGuard::new_exclusive(&mut world, cache);
96
97 guard
98 .register_script_component("ScriptTest".to_string())
99 .unwrap()
100 };
101
102 let registry = world.get_resource::<AppScriptComponentRegistry>().unwrap();
103
104 let registry = registry.read();
105 let info = registry.get("ScriptTest").unwrap();
106 assert_eq!(info.registration.component_id, registration.component_id);
107 assert_eq!(info.name, "ScriptTest");
108
109 let component = world
111 .components()
112 .get_info(info.registration.component_id)
113 .unwrap();
114
115 assert_eq!(component.name(), "ScriptTest".into());
116 }
117}