Skip to content

Commit 65042d1

Browse files
authored
feat: overhaul mdbook preprocessor, prettify generated docs, support dummy globals (makspll#377)
# Summary - Completely overhauls the mdbook preprocessor. - Adds `dummy` globals to the globals registry for the purposes of documenting `entity`, `world`, etc. - Moves all of the manually written docs into the generated docs, and removes the `WIP` section - Type and instance lists are formatted better now - Adds markings in the LAD format for `importance` and `generated` types - Types in the generated docs are ordered according to their importance, core types are placed ahead of most types, and user marked `significant` types are placed even higher - Non reflected types are supported by the lad builder - Links in generic `TypedThrough` types are generated at each non generic type ![image](https://github.com/user-attachments/assets/a4bfa889-771d-4faf-825d-29143851aeb6) ![image](https://github.com/user-attachments/assets/0abadcd9-e0c4-4b4c-a7da-3f46029ad530) ![image](https://github.com/user-attachments/assets/b3fbca0b-1564-4523-bfb9-b88e624c32ae) ![image](https://github.com/user-attachments/assets/dab70e3c-e531-44ec-a1ff-ddba6e12f42c)
1 parent 651bcd3 commit 65042d1

File tree

41 files changed

+2275
-1620
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

41 files changed

+2275
-1620
lines changed

crates/bevy_api_gen/templates/footer.tera

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ pub struct {{ "ScriptingPlugin" | prefix_cratename | convert_case(case="upper_ca
1111
#[script_bindings(
1212
remote,
1313
name = "{{ item.ident | convert_case(case="snake") }}_functions",
14-
bms_core_path="bevy_mod_scripting_core"
14+
bms_core_path="bevy_mod_scripting_core",
15+
generated
1516
)]
1617
impl {{item.import_path}} {
1718
{% for function in item.functions %}

crates/bevy_mod_scripting_core/src/bindings/globals/core.rs

Lines changed: 58 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,21 @@
22
33
use std::{collections::HashMap, sync::Arc};
44

5-
use bevy::{app::Plugin, ecs::reflect::AppTypeRegistry};
5+
use bevy::{
6+
app::Plugin,
7+
ecs::{entity::Entity, reflect::AppTypeRegistry, world::World},
8+
};
69
use bevy_mod_scripting_derive::script_globals;
710

8-
use crate::{bindings::{function::from::{Union, Val}, ScriptComponentRegistration, ScriptResourceRegistration, ScriptTypeRegistration, WorldGuard}, docgen::into_through_type_info, error::InteropError};
11+
use crate::{
12+
bindings::{
13+
function::from::{Union, Val},
14+
ScriptComponentRegistration, ScriptResourceRegistration, ScriptTypeRegistration,
15+
WorldGuard,
16+
},
17+
docgen::into_through_type_info,
18+
error::InteropError,
19+
};
920

1021
use super::AppScriptGlobalsRegistry;
1122

@@ -22,54 +33,67 @@ impl Plugin for CoreScriptGlobalsPlugin {
2233

2334
fn register_static_core_globals(world: &mut bevy::ecs::world::World) {
2435
let global_registry = world
25-
.get_resource_or_init::<AppScriptGlobalsRegistry>()
26-
.clone();
27-
let type_registry = world
28-
.get_resource_or_init::<AppTypeRegistry>()
29-
.clone();
30-
let mut global_registry = global_registry.write();
31-
let type_registry = type_registry.read();
36+
.get_resource_or_init::<AppScriptGlobalsRegistry>()
37+
.clone();
38+
let type_registry = world.get_resource_or_init::<AppTypeRegistry>().clone();
39+
let mut global_registry = global_registry.write();
40+
let type_registry = type_registry.read();
3241

33-
// find all reflectable types without generics
34-
for registration in type_registry.iter() {
35-
if !registration.type_info().generics().is_empty() {
36-
continue;
37-
}
42+
// find all reflectable types without generics
43+
for registration in type_registry.iter() {
44+
if !registration.type_info().generics().is_empty() {
45+
continue;
46+
}
3847

39-
if let Some(global_name) = registration.type_info().type_path_table().ident() {
40-
let documentation = "A reference to the type, allowing you to call static methods.";
41-
let type_info = registration.type_info();
42-
global_registry.register_static_documented_dynamic(
43-
registration.type_id(),
44-
into_through_type_info(type_info),
45-
global_name.into(),
46-
documentation.into(),
47-
);
48-
}
48+
if let Some(global_name) = registration.type_info().type_path_table().ident() {
49+
let documentation = "A reference to the type, allowing you to call static methods.";
50+
let type_info = registration.type_info();
51+
global_registry.register_static_documented_dynamic(
52+
registration.type_id(),
53+
into_through_type_info(type_info),
54+
global_name.into(),
55+
documentation.into(),
56+
);
4957
}
58+
}
59+
60+
// register basic globals
61+
global_registry.register_dummy::<World>("world", "The current ECS world.");
62+
global_registry
63+
.register_dummy::<Entity>("entity", "The entity this script is attached to if any.");
64+
global_registry.register_dummy::<String>("script_id", "the name/id of this script");
5065
}
5166

52-
#[script_globals(
53-
bms_core_path = "crate",
54-
name = "core_globals",
55-
)]
67+
#[script_globals(bms_core_path = "crate", name = "core_globals")]
5668
impl CoreGlobals {
5769
/// A cache of types normally available through the `world.get_type_by_name` function.
58-
///
70+
///
5971
/// You can use this to avoid having to store type references.
60-
fn types(guard: WorldGuard) -> Result<HashMap<String, Union<Val<ScriptTypeRegistration>, Union<Val<ScriptComponentRegistration>, Val<ScriptResourceRegistration>>>>, InteropError> {
72+
fn types(
73+
guard: WorldGuard,
74+
) -> Result<
75+
HashMap<
76+
String,
77+
Union<
78+
Val<ScriptTypeRegistration>,
79+
Union<Val<ScriptComponentRegistration>, Val<ScriptResourceRegistration>>,
80+
>,
81+
>,
82+
InteropError,
83+
> {
6184
let type_registry = guard.type_registry();
6285
let type_registry = type_registry.read();
6386
let mut type_cache = HashMap::<String, _>::default();
64-
for registration in type_registry.iter(){
87+
for registration in type_registry.iter() {
6588
if let Some(ident) = registration.type_info().type_path_table().ident() {
6689
let registration = ScriptTypeRegistration::new(Arc::new(registration.clone()));
6790
let registration = guard.clone().get_type_registration(registration)?;
68-
let registration = registration.map_both(Val::from, |u| u.map_both(Val::from, Val::from));
91+
let registration =
92+
registration.map_both(Val::from, |u| u.map_both(Val::from, Val::from));
6993
type_cache.insert(ident.to_string(), registration);
7094
}
7195
}
72-
96+
7397
Ok(type_cache)
7498
}
75-
}
99+
}

crates/bevy_mod_scripting_core/src/bindings/globals/mod.rs

Lines changed: 43 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,15 @@ use super::{
55
script_value::ScriptValue,
66
WorldGuard,
77
};
8-
use crate::{docgen::{into_through_type_info, typed_through::ThroughTypeInfo}, error::InteropError};
8+
use crate::{
9+
docgen::{into_through_type_info, typed_through::ThroughTypeInfo},
10+
error::InteropError,
11+
};
912
use bevy::{ecs::system::Resource, reflect::Typed, utils::hashbrown::HashMap};
1013
use parking_lot::{RwLock, RwLockReadGuard, RwLockWriteGuard};
1114
use std::{any::TypeId, borrow::Cow, sync::Arc};
1215

13-
crate::private::export_all_in_modules!{
16+
crate::private::export_all_in_modules! {
1417
core
1518
}
1619

@@ -48,10 +51,22 @@ pub struct ScriptGlobal {
4851
pub type_information: ThroughTypeInfo,
4952
}
5053

54+
/// A dummy global variable that documents globals set via alternative ways.
55+
pub struct ScriptGlobalDummy {
56+
/// The type ID of the global variable.
57+
pub type_id: TypeId,
58+
/// Rich type information the global variable.
59+
pub type_information: Option<ThroughTypeInfo>,
60+
61+
/// The documentation for the global dummy variable.
62+
pub documentation: Option<Cow<'static, str>>,
63+
}
64+
5165
/// A registry of global variables that can be exposed to scripts.
5266
#[derive(Default)]
5367
pub struct ScriptGlobalsRegistry {
5468
globals: HashMap<Cow<'static, str>, ScriptGlobal>,
69+
dummies: HashMap<Cow<'static, str>, ScriptGlobalDummy>,
5570
}
5671

5772
impl ScriptGlobalsRegistry {
@@ -85,6 +100,11 @@ impl ScriptGlobalsRegistry {
85100
self.globals.iter_mut()
86101
}
87102

103+
/// Iterates over the dummies in the registry
104+
pub fn iter_dummies(&self) -> impl Iterator<Item = (&Cow<'static, str>, &ScriptGlobalDummy)> {
105+
self.dummies.iter()
106+
}
107+
88108
fn type_erase_maker<
89109
T: ScriptReturn,
90110
F: Fn(WorldGuard) -> Result<T, InteropError> + Send + Sync + 'static,
@@ -114,6 +134,26 @@ impl ScriptGlobalsRegistry {
114134
)
115135
}
116136

137+
/// Registers a dummy global into the registry.
138+
/// Dummies are not actually exposed to languages but exist purely for the purpose of documentation.
139+
/// This can be useful for globals which you cannot expose normally.
140+
///
141+
/// Dummy globals are stored as non-static instances, i.e. they're expected to be values not type references.
142+
pub fn register_dummy<T: 'static>(
143+
&mut self,
144+
name: impl Into<Cow<'static, str>>,
145+
documentation: impl Into<Cow<'static, str>>,
146+
) {
147+
self.dummies.insert(
148+
name.into(),
149+
ScriptGlobalDummy {
150+
documentation: Some(documentation.into()),
151+
type_id: TypeId::of::<T>(),
152+
type_information: None,
153+
},
154+
);
155+
}
156+
117157
/// Inserts a global into the registry, returns the previous value if it existed.
118158
///
119159
/// This is a version of [`Self::register`] which stores type information regarding the global.
@@ -153,7 +193,7 @@ impl ScriptGlobalsRegistry {
153193
/// Registers a static global into the registry.
154194
///
155195
/// This is a version of [`Self::register_static`] which stores rich type information regarding the global.
156-
pub fn register_static_documented<T: TypedScriptReturn +'static>(
196+
pub fn register_static_documented<T: TypedScriptReturn + 'static>(
157197
&mut self,
158198
name: Cow<'static, str>,
159199
documentation: Cow<'static, str>,

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+
type_data
1516
}

crates/bevy_mod_scripting_core/src/bindings/query.rs

Lines changed: 27 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,24 +14,28 @@ use bevy::{
1414
};
1515
use std::{any::TypeId, collections::VecDeque, sync::Arc};
1616

17-
/// A wrapper around a `TypeRegistration` that provides additional information about the type.
17+
/// A reference to a type which is not a `Resource` or `Component`.
1818
///
19-
/// This is used as a hook to a rust type from a scripting language. We should be able to easily convert between a type name and a [`ScriptTypeRegistration`].
19+
/// In general think of this as a handle to a type.
2020
#[derive(Clone, Reflect)]
2121
#[reflect(opaque)]
2222
pub struct ScriptTypeRegistration {
2323
pub(crate) registration: Arc<TypeRegistration>,
2424
}
2525

2626
#[derive(Clone, Reflect, Debug)]
27-
/// A registration for a component type.
27+
/// A reference to a component type's reflection registration.
28+
///
29+
/// In general think of this as a handle to a type.
2830
pub struct ScriptComponentRegistration {
2931
pub(crate) registration: ScriptTypeRegistration,
3032
pub(crate) component_id: ComponentId,
3133
}
3234

3335
#[derive(Clone, Reflect, Debug)]
34-
/// A registration for a resource type.
36+
/// A reference to a resource type's reflection registration.
37+
///
38+
/// In general think of this as a handle to a type.
3539
pub struct ScriptResourceRegistration {
3640
pub(crate) registration: ScriptTypeRegistration,
3741
pub(crate) resource_id: ComponentId,
@@ -134,7 +138,25 @@ impl std::fmt::Display for ScriptTypeRegistration {
134138

135139
#[derive(Clone, Default, Reflect)]
136140
#[reflect(opaque)]
137-
/// A builder for a query.
141+
/// The query builder is used to build ECS queries which retrieve spefific components filtered by specific conditions.
142+
///
143+
/// For example:
144+
/// ```rust,ignore
145+
/// builder.component(componentA)
146+
/// .component(componentB)
147+
/// .with(componentC)
148+
/// .without(componentD)
149+
/// ```
150+
///
151+
/// Will retrieve entities which:
152+
/// - Have componentA
153+
/// - Have componentB
154+
/// - Have componentC
155+
/// - Do not have componentD
156+
///
157+
/// As well as references to components:
158+
/// - componentA
159+
/// - componentB
138160
pub struct ScriptQueryBuilder {
139161
pub(crate) components: Vec<ScriptComponentRegistration>,
140162
with: Vec<ScriptComponentRegistration>,

crates/bevy_mod_scripting_core/src/bindings/reference.rs

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,13 @@ use bevy::{
2222
};
2323
use std::{any::TypeId, fmt::Debug};
2424

25-
/// An accessor to a `dyn PartialReflect` struct, stores a base ID of the type and a reflection path
26-
/// safe to build but to reflect on the value inside you need to ensure aliasing rules are upheld
25+
/// A reference to an arbitrary reflected instance.
26+
///
27+
/// The reference can point to either the ECS, or to the allocator.
28+
///
29+
/// References are composed of two parts:
30+
/// - The base kind, which specifies where the reference points to
31+
/// - The path, which specifies how to access the value from the base
2732
#[derive(Debug, Clone, PartialEq, Eq, Reflect)]
2833
#[reflect(Default, opaque)]
2934
pub struct ReflectReference {
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
//! Contains various `Reflect` type data we use in BMS.
2+
3+
use bevy::reflect::FromType;
4+
5+
/// A marker type to indicate that a type is generated.
6+
///
7+
/// To mark a type as generated use:
8+
/// ```rust,ignore
9+
/// registry.register_type_data::<T, MarkAsGenerated>();
10+
/// ```
11+
#[derive(Clone, Copy)]
12+
pub struct MarkAsGenerated;
13+
14+
impl<T> FromType<T> for MarkAsGenerated {
15+
fn from_type() -> Self {
16+
Self
17+
}
18+
}
19+
20+
/// A marker type to indicate that a type is significant.
21+
///
22+
/// Significant types appear "before" core types in documentation
23+
#[derive(Clone, Copy)]
24+
pub struct MarkAsSignificant;
25+
26+
impl<T> FromType<T> for MarkAsSignificant {
27+
fn from_type() -> Self {
28+
Self
29+
}
30+
}
31+
32+
/// A marker type to indicate that a type is core to BMS.
33+
///
34+
/// core types appear before insignificant types in documentation.
35+
#[derive(Clone, Copy)]
36+
pub struct MarkAsCore;
37+
38+
impl<T> FromType<T> for MarkAsCore {
39+
fn from_type() -> Self {
40+
Self
41+
}
42+
}

0 commit comments

Comments
 (0)