Skip to content

Commit 108e429

Browse files
committed
WIP
1 parent 651bcd3 commit 108e429

File tree

3 files changed

+125
-11
lines changed

3 files changed

+125
-11
lines changed

crates/bevy_mod_scripting_core/src/bindings/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,5 @@ crate::private::export_all_in_modules! {
1212
script_system,
1313
script_value,
1414
world,
15+
script_component,
1516
}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
//! Everything necessary to support scripts registering their own components
2+
3+
use std::{alloc::Layout, mem::needs_drop, sync::Arc};
4+
5+
use bevy::{
6+
ecs::{
7+
component::{Component, ComponentDescriptor, StorageType},
8+
reflect::ReflectComponent,
9+
},
10+
reflect::{GetTypeRegistration, Reflect, TypeRegistration},
11+
utils::HashMap,
12+
};
13+
use parking_lot::RwLock;
14+
15+
use crate::error::InteropError;
16+
17+
use super::{ScriptComponentRegistration, ScriptTypeRegistration, ScriptValue, WorldGuard};
18+
19+
/// A dynamic script component, with script set
20+
#[derive(Reflect, Clone)]
21+
#[reflect(Component)]
22+
pub struct ScriptComponent {
23+
data: ScriptValue,
24+
}
25+
26+
/// Some metadata about dynamic script components
27+
pub struct ScriptComponentInfo {
28+
/// The name of the component
29+
pub name: String,
30+
/// The type registration for the component
31+
pub registration: ScriptComponentRegistration,
32+
}
33+
34+
impl Component for ScriptComponent {
35+
const STORAGE_TYPE: StorageType = StorageType::Table;
36+
}
37+
38+
/// A registry of dynamically registered script components
39+
pub struct AppScriptComponentRegistry(pub Arc<RwLock<ScriptComponentRegistry>>);
40+
41+
pub struct ScriptComponentRegistry {
42+
components: HashMap<String, ScriptComponentInfo>,
43+
}
44+
45+
impl WorldGuard<'_> {
46+
pub fn script_component_registry(&self) -> AppScriptComponentRegistry {
47+
let component_registry =
48+
self.with_resource(|app_component_registry: &AppScriptComponentRegistry| {
49+
app_component_registry.clone()
50+
})?;
51+
}
52+
53+
/// Registers a dynamic script component, and returns a reference to its registration
54+
pub fn register_script_component(
55+
&self,
56+
component_name: String,
57+
) -> Result<ScriptComponentRegistration, InteropError> {
58+
let component_id = self.with_global_access(|w| {
59+
let descriptor = unsafe {
60+
// Safety: same safety guarantees as ComponentDescriptor::new
61+
// we know the type in advance
62+
ComponentDescriptor::new_with_layout(
63+
component_name,
64+
ScriptComponent::STORAGE_TYPE,
65+
Layout::new::<ScriptComponent>(),
66+
needs_drop::<ScriptComponent>().then_some(|x| x.drop_as::<ScriptComponent>()),
67+
)
68+
};
69+
w.register_component_with_descriptor(descriptor)
70+
})?;
71+
72+
// we need to register this as a type in the type registry with this name so its retrievable as any other type
73+
let type_registry = self.type_registry();
74+
let mut type_registry = type_registry.write();
75+
76+
// TODO: we should probably retrieve this from the registry, but I don't see what people would want to register on this type
77+
// in addition to the existing registrations.
78+
Ok(ScriptComponentRegistration::new(
79+
ScriptTypeRegistration::new(Arc::new(
80+
<ScriptComponent as GetTypeRegistration>::get_type_registration(),
81+
)),
82+
component_id,
83+
))
84+
}
85+
}

crates/bevy_mod_scripting_core/src/bindings/world.rs

Lines changed: 39 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,23 @@ use super::{
99
access_map::{
1010
AccessCount, AccessMapKey, AnyAccessMap, DynamicSystemMeta, ReflectAccessId,
1111
ReflectAccessKind, SubsetAccessMap,
12-
}, function::{
12+
},
13+
function::{
1314
namespace::Namespace,
1415
script_function::{AppScriptFunctionRegistry, DynamicScriptFunction, FunctionCallContext},
15-
}, pretty_print::DisplayWithWorld, schedule::AppScheduleRegistry, script_value::ScriptValue, with_global_access, AppReflectAllocator, ReflectBase, ReflectBaseType, ReflectReference, ScriptComponentRegistration, ScriptResourceRegistration, ScriptTypeRegistration, Union
16+
},
17+
pretty_print::DisplayWithWorld,
18+
schedule::AppScheduleRegistry,
19+
script_value::ScriptValue,
20+
with_global_access, AppReflectAllocator, AppScriptComponentRegistry, ReflectBase,
21+
ReflectBaseType, ReflectReference, ScriptComponentRegistration, ScriptResourceRegistration,
22+
ScriptTypeRegistration, Union,
1623
};
1724
use crate::{
18-
bindings::{function::{from::FromScript, from_ref::FromScriptRef}, with_access_read, with_access_write},
25+
bindings::{
26+
function::{from::FromScript, from_ref::FromScriptRef},
27+
with_access_read, with_access_write,
28+
},
1929
error::InteropError,
2030
reflection_extensions::PartialReflectExt,
2131
};
@@ -73,6 +83,8 @@ pub(crate) struct WorldAccessGuardInner<'w> {
7383
function_registry: AppScriptFunctionRegistry,
7484
/// The schedule registry for the world
7585
schedule_registry: AppScheduleRegistry,
86+
/// The registry of script registered components
87+
script_component_registry: AppScriptComponentRegistry,
7688
}
7789

7890
impl std::fmt::Debug for WorldAccessGuardInner<'_> {
@@ -542,7 +554,6 @@ impl<'w> WorldAccessGuard<'w> {
542554
/// Impl block for higher level world methods
543555
#[profiling::all_functions]
544556
impl WorldAccessGuard<'_> {
545-
546557
fn construct_from_script_value(
547558
&self,
548559
descriptor: impl Into<Cow<'static, str>>,
@@ -812,8 +823,16 @@ impl WorldAccessGuard<'_> {
812823
}
813824

814825
/// get a type erased type registration for the type including information about whether it's a component or resource
815-
pub(crate) fn get_type_registration(&self, registration: ScriptTypeRegistration) -> Result<Union<ScriptTypeRegistration, Union<ScriptComponentRegistration, ScriptResourceRegistration>>, InteropError> {
816-
826+
pub(crate) fn get_type_registration(
827+
&self,
828+
registration: ScriptTypeRegistration,
829+
) -> Result<
830+
Union<
831+
ScriptTypeRegistration,
832+
Union<ScriptComponentRegistration, ScriptResourceRegistration>,
833+
>,
834+
InteropError,
835+
> {
817836
let registration = match self.get_resource_type(registration)? {
818837
Ok(res) => {
819838
return Ok(Union::new_right(Union::new_right(res)));
@@ -831,14 +850,23 @@ impl WorldAccessGuard<'_> {
831850
Ok(Union::new_left(registration))
832851
}
833852

834-
/// Similar to [`Self::get_type_by_name`] but returns a type erased [`ScriptTypeRegistration`], [`ScriptComponentRegistration`] or [`ScriptResourceRegistration`]
853+
/// Similar to [`Self::get_type_by_name`] but returns a type erased [`ScriptTypeRegistration`], [`ScriptComponentRegistration`] or [`ScriptResourceRegistration`]
835854
/// depending on the underlying type and state of the world.
836-
pub fn get_type_registration_by_name(&self, type_name: String) -> Result<Option<Union<ScriptTypeRegistration, Union<ScriptComponentRegistration, ScriptResourceRegistration>>>, InteropError> {
855+
pub fn get_type_registration_by_name(
856+
&self,
857+
type_name: String,
858+
) -> Result<
859+
Option<
860+
Union<
861+
ScriptTypeRegistration,
862+
Union<ScriptComponentRegistration, ScriptResourceRegistration>,
863+
>,
864+
>,
865+
InteropError,
866+
> {
837867
let val = self.get_type_by_name(type_name);
838868
Ok(match val {
839-
Some(registration) => {
840-
Some(self.get_type_registration(registration)?)
841-
}
869+
Some(registration) => Some(self.get_type_registration(registration)?),
842870
None => None,
843871
})
844872
}

0 commit comments

Comments
 (0)