use super::*;
use bevy_asset::AssetEvent;
use bevy_ecs::message::{MessageReader, MessageWriter};
use bevy_log::{debug, trace};
#[derive(Clone, Debug)]
pub struct StrongScriptHandle(Handle<ScriptAsset>);
impl GetScriptHandle for ScriptAttachedEvent {
fn get_script_handle(&self) -> Handle<ScriptAsset> {
self.0.script()
}
}
impl GetScriptHandle for ScriptDetachedEvent {
fn get_script_handle(&self) -> Handle<ScriptAsset> {
self.0.script()
}
}
impl StrongScriptHandle {
pub fn new(handle: Handle<ScriptAsset>) -> Option<Self> {
if handle.is_strong() {
Some(Self(handle))
} else {
None
}
}
pub fn from_assets(
handle: Handle<ScriptAsset>,
assets: &mut Assets<ScriptAsset>,
) -> Option<Self> {
match handle {
s @ Handle::Strong(_) => Some(Self(s)),
_ => assets.get_strong_handle(handle.id()).map(Self),
}
}
pub fn handle(&self) -> &Handle<ScriptAsset> {
&self.0
}
pub fn get(&self, assets: &Assets<ScriptAsset>) -> ScriptAsset {
assets.get(&self.0).cloned().unwrap_or_default()
}
}
pub fn filter_script_modifications<P: IntoScriptPluginParams>(
mut events: MessageReader<AssetEvent<ScriptAsset>>,
mut filtered: MessageWriter<ForPlugin<ScriptAssetModifiedEvent, P>>,
assets: Res<Assets<ScriptAsset>>,
) {
let mut batch = events.read().filter_map(|e| {
if let AssetEvent::Modified { id } = e
&& let Some(asset) = assets.get(*id)
&& asset.language == P::LANGUAGE
{
Some(ForPlugin::new(ScriptAssetModifiedEvent(*id)))
} else {
None
}
});
if let Some(next) = batch.next() {
filtered.write_batch(std::iter::once(next).chain(batch));
}
}
pub fn filter_script_attachments<P: IntoScriptPluginParams>(
mut events: LoadedWithHandles<ScriptAttachedEvent>,
mut filtered: MessageWriter<ForPlugin<ScriptAttachedEvent, P>>,
) {
let mut batch = events
.get_loaded()
.filter(|(_, _, l)| *l == P::LANGUAGE)
.map(|(mut a, b, _)| {
trace!(
"dispatching script attachment event for: {a:?}, language: {}",
P::LANGUAGE
);
*a.0.script_mut() = b.0;
ForPlugin::new(a)
});
if let Some(next) = batch.next() {
filtered.write_batch(std::iter::once(next).chain(batch));
}
}
pub fn filter_script_detachments<P: IntoScriptPluginParams>(
mut events: MessageReader<ScriptDetachedEvent>,
mut filtered: MessageWriter<ForPlugin<ScriptDetachedEvent, P>>,
contexts: Res<ScriptContext<P>>,
) {
let contexts_guard = contexts.read();
let mut batch = events
.read()
.filter(|e| contexts_guard.contains(&e.0))
.cloned()
.map(ForPlugin::new);
if let Some(next) = batch.next() {
trace!("dispatching script dettachments for plugin");
filtered.write_batch(std::iter::once(next).chain(batch));
}
}
pub fn process_attachments<P: IntoScriptPluginParams>(
mut events: MessageReader<ForPlugin<ScriptAttachedEvent, P>>,
mut machines: ResMut<ActiveMachines<P>>,
mut assets: ResMut<Assets<ScriptAsset>>,
contexts: Res<ScriptContext<P>>,
) {
let contexts = contexts.read();
events.read().for_each(|wrapper| {
let attachment_event = wrapper.event();
debug!("received attachment event: {attachment_event:?}");
let id = attachment_event.0.script();
let mut context = Context {
attachment: attachment_event.0.clone(),
blackboard: Default::default(),
};
if let Some(strong_handle) = StrongScriptHandle::from_assets(id, &mut assets) {
*context.attachment.script_mut() = strong_handle.0.clone();
let content = strong_handle.get(&assets);
if let Some(existing_context) = contexts.get_context(&attachment_event.0) {
machines.queue_machine(
context,
ReloadingInitialized {
source: strong_handle.handle().clone(),
content: content.content,
existing_context,
},
);
} else {
machines.queue_machine(
context,
LoadingInitialized {
source: strong_handle.handle().clone(),
content: content.content,
},
);
}
}
});
}
pub fn process_detachments<P: IntoScriptPluginParams>(
mut events: MessageReader<ForPlugin<ScriptDetachedEvent, P>>,
mut machines: ResMut<ActiveMachines<P>>,
contexts: Res<ScriptContext<P>>,
) {
events.read().for_each(|wrapper| {
let attachment_event = wrapper.event();
let contexts_guard = contexts.read();
contexts_guard
.get_context(&attachment_event.0)
.into_iter()
.for_each(|existing_context| {
machines.queue_machine(
Context {
attachment: attachment_event.0.clone(),
blackboard: Default::default(),
},
UnloadingInitialized { existing_context },
);
})
});
}
pub fn process_asset_modifications<P: IntoScriptPluginParams>(
mut events: MessageReader<ForPlugin<ScriptAssetModifiedEvent, P>>,
mut machines: ResMut<ActiveMachines<P>>,
mut assets: ResMut<Assets<ScriptAsset>>,
contexts: Res<ScriptContext<P>>,
) {
let affected_ids = events.read().map(|e| e.event().0).collect::<HashSet<_>>();
let contexts = contexts.read();
let affected_attachments = contexts
.all_residents()
.filter(|(a, _)| affected_ids.contains(&a.script().id()));
affected_attachments
.into_iter()
.for_each(|(attachment, existing_context)| {
let id = attachment.script();
if let Some(strong_handle) = StrongScriptHandle::from_assets(id, &mut assets) {
let content = strong_handle.get(&assets);
machines.queue_machine(
Context {
attachment,
blackboard: Default::default(),
},
ReloadingInitialized {
source: strong_handle.handle().clone(),
content: content.content,
existing_context,
},
);
}
});
}