Skip to content

Commit 0dc0e4d

Browse files
committed
bring back the queue for attachments
1 parent c281f72 commit 0dc0e4d

File tree

3 files changed

+99
-21
lines changed

3 files changed

+99
-21
lines changed

crates/bevy_mod_scripting_core/src/pipeline/mod.rs

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
//! Everything to do with the script lifetime management pipeline
22
3-
use std::{any::Any, marker::PhantomData, sync::Arc};
3+
use std::{any::Any, collections::VecDeque, marker::PhantomData, sync::Arc};
44

55
use bevy_app::{App, Plugin, PostUpdate};
6-
use bevy_asset::{Assets, Handle};
6+
use bevy_asset::{AssetServer, Assets, Handle, LoadState};
77
use bevy_ecs::{
88
event::{Event, EventCursor, EventReader, EventWriter, Events},
99
resource::Resource,
@@ -109,6 +109,59 @@ impl<P: IntoScriptPluginParams> ScriptLoadingPipeline<P> {
109109
}
110110
}
111111

112+
/// A trait describing things containing script handles
113+
pub trait GetScriptHandle {
114+
/// Retrieve the contained script handle
115+
fn get_script_handle(&self) -> Handle<ScriptAsset>;
116+
}
117+
118+
#[derive(SystemParam)]
119+
/// A system param which operates over types implementing [`GetScriptHandle`].
120+
/// Captures incoming "handle" like types, and waits until their asset is in a final state before proceeding, if that final state
121+
/// is loaded, will also guarantee a strong handle, otherwise the whole thing is skipped.
122+
///
123+
/// Think of this as a proxy for "baby'ing" asset handles
124+
pub struct LoadedWithHandles<'w, 's, T: GetScriptHandle + Event + Clone> {
125+
assets: ResMut<'w, Assets<ScriptAsset>>,
126+
asset_server: Res<'w, AssetServer>,
127+
fresh_events: EventReader<'w, 's, T>,
128+
loaded_with_handles: Local<'s, VecDeque<(T, StrongScriptHandle)>>,
129+
loading: Local<'s, VecDeque<T>>,
130+
}
131+
132+
impl<T: GetScriptHandle + Event + Clone> LoadedWithHandles<'_, '_, T> {
133+
/// Retrieves all of the events of type `T`, which have finished loading and have a strong handle,
134+
/// the rest will be discarded.
135+
///
136+
/// This uses a [`EventReader<T>`] underneath, meaning if you don't call this method once every frame (or every other frame).
137+
/// You may miss events.
138+
pub fn get_loaded(&mut self) -> impl Iterator<Item = (T, StrongScriptHandle)> {
139+
// first get all of the fresh_events
140+
self.loading.extend(self.fresh_events.read().cloned());
141+
// now process the loading queue
142+
self.loading.retain(|e| {
143+
let handle = e.get_script_handle();
144+
match self.asset_server.get_load_state(&handle) {
145+
Some(LoadState::Loaded) => {
146+
let strong = StrongScriptHandle::from_assets(handle, &mut self.assets);
147+
if let Some(strong) = strong {
148+
self.loaded_with_handles.push_front((e.clone(), strong));
149+
true
150+
} else {
151+
false
152+
}
153+
}
154+
Some(LoadState::Loading) => true,
155+
Some(_) => false,
156+
None => false,
157+
}
158+
});
159+
160+
// now return loaded with handles elements by draining
161+
self.loaded_with_handles.drain(..)
162+
}
163+
}
164+
112165
// struct StateBuilder<'a, P: IntoScriptPluginParams, M, S> {
113166
// plugin: &'a ScriptLoadingPipeline<P>,
114167
// app: &'a mut App,

crates/bevy_mod_scripting_core/src/pipeline/start.rs

Lines changed: 35 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,24 @@ pub struct ScriptAssetModifiedEvent(pub ScriptId);
1818
#[derive(Clone, Debug)]
1919
pub struct StrongScriptHandle(Handle<ScriptAsset>);
2020

21+
impl GetScriptHandle for ScriptAssetModifiedEvent {
22+
fn get_script_handle(&self) -> Handle<ScriptAsset> {
23+
Handle::Weak(self.0)
24+
}
25+
}
26+
27+
impl GetScriptHandle for ScriptAttachedEvent {
28+
fn get_script_handle(&self) -> Handle<ScriptAsset> {
29+
self.0.script()
30+
}
31+
}
32+
33+
impl GetScriptHandle for ScriptDetachedEvent {
34+
fn get_script_handle(&self) -> Handle<ScriptAsset> {
35+
self.0.script()
36+
}
37+
}
38+
2139
impl StrongScriptHandle {
2240
/// Creates a new strong script handle, only if the given handle is strong itself.
2341
pub fn new(handle: Handle<ScriptAsset>) -> Option<Self> {
@@ -28,6 +46,14 @@ impl StrongScriptHandle {
2846
}
2947
}
3048

49+
/// create a strong script handle using the assets resource and the possibly weak handle.
50+
pub fn from_assets(
51+
handle: Handle<ScriptAsset>,
52+
assets: &mut Assets<ScriptAsset>,
53+
) -> Option<Self> {
54+
assets.get_strong_handle(handle.id()).map(Self)
55+
}
56+
3157
/// Upgrades an asset Id pointing to a script to a strong handle if the asset hasn't been dropped
3258
pub fn upgrade(id: ScriptId, assets: &mut Assets<ScriptAsset>) -> Option<Self> {
3359
assets.get_strong_handle(id).map(Self)
@@ -70,41 +96,32 @@ pub fn filter_script_modifications<P: IntoScriptPluginParams>(
7096

7197
/// Filters incoming [`ScriptAttachedEvent`]'s leaving only those which match the plugin's language
7298
pub fn filter_script_attachments<P: IntoScriptPluginParams>(
73-
mut events: EventReader<ScriptAttachedEvent>,
99+
mut events: LoadedWithHandles<ScriptAttachedEvent>,
74100
mut filtered: EventWriter<ForPlugin<ScriptAttachedEvent, P>>,
75-
assets: Res<Assets<ScriptAsset>>,
76101
mut requests: ResMut<RequestProcessingPipelineRun<P>>,
77102
) {
78-
let mut batch = events
79-
.read()
80-
.filter(|e| {
81-
assets
82-
.get(&e.0.script())
83-
.is_some_and(|asset| asset.language == P::LANGUAGE)
84-
})
85-
.cloned()
86-
.map(ForPlugin::new);
103+
let mut batch = events.get_loaded().map(|(mut a, b)| {
104+
*a.0.script_mut() = b.0;
105+
ForPlugin::new(a)
106+
});
87107

88108
if let Some(next) = batch.next() {
89109
requests.request_run();
90110
filtered.write_batch(std::iter::once(next).chain(batch));
91111
}
92112
}
93113

94-
/// Filters incoming [`ScriptDetachedEvent`]'s leaving only those which match the plugin's language
114+
/// Filters incoming [`ScriptDetachedEvent`]'s leaving only those which are currently attached
95115
pub fn filter_script_detachments<P: IntoScriptPluginParams>(
96116
mut events: EventReader<ScriptDetachedEvent>,
97117
mut filtered: EventWriter<ForPlugin<ScriptDetachedEvent, P>>,
98-
assets: Res<Assets<ScriptAsset>>,
118+
contexts: Res<ScriptContext<P>>,
99119
mut requests: ResMut<RequestProcessingPipelineRun<P>>,
100120
) {
121+
let contexts_guard = contexts.read();
101122
let mut batch = events
102123
.read()
103-
.filter(|e| {
104-
assets
105-
.get(&e.0.script())
106-
.is_some_and(|asset| asset.language == P::LANGUAGE)
107-
})
124+
.filter(|e| contexts_guard.contains(&e.0))
108125
.cloned()
109126
.map(ForPlugin::new);
110127

crates/bevy_mod_scripting_core/src/script/context_key.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,14 +33,22 @@ impl std::fmt::Display for ScriptAttachment {
3333
}
3434

3535
impl ScriptAttachment {
36-
/// Returns the script handle if it exists.
36+
/// Returns the script handle.
3737
pub fn script(&self) -> Handle<ScriptAsset> {
3838
match self {
3939
ScriptAttachment::EntityScript(_, script) => script.clone(),
4040
ScriptAttachment::StaticScript(script) => script.clone(),
4141
}
4242
}
4343

44+
/// Returns a mutable reference to the underlying script handle.
45+
pub fn script_mut(&mut self) -> &mut Handle<ScriptAsset> {
46+
match self {
47+
ScriptAttachment::EntityScript(_, script) => script,
48+
ScriptAttachment::StaticScript(script) => script,
49+
}
50+
}
51+
4452
/// Returns the entity if it exists.
4553
pub fn entity(&self) -> Option<Entity> {
4654
match self {

0 commit comments

Comments
 (0)