Skip to content

Commit 324f9f3

Browse files
committed
feature: Handle static scripts.
1 parent c3a7d96 commit 324f9f3

File tree

2 files changed

+84
-21
lines changed

2 files changed

+84
-21
lines changed

crates/bevy_mod_scripting_core/src/asset.rs

Lines changed: 67 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,26 @@
11
//! Systems and resources for handling script assets and events
22
33
use crate::{
4+
StaticScripts,
5+
ScriptComponent,
46
commands::{CreateOrUpdateScript, DeleteScript},
57
error::ScriptError,
68
script::ScriptId,
79
IntoScriptPluginParams, ScriptingSystemSet,
810
};
911
use bevy::{
1012
app::{App, PreUpdate},
11-
asset::{Asset, AssetEvent, AssetId, AssetLoader, AssetPath, Assets},
13+
asset::{Asset, AssetEvent, AssetId, AssetLoader, AssetPath, Assets, LoadState},
1214
ecs::system::Resource,
1315
log::{debug, info, trace, warn},
1416
prelude::{
1517
Commands, Event, EventReader, EventWriter, IntoSystemConfigs, IntoSystemSetConfigs, Res,
16-
ResMut,
18+
ResMut, Added, Query, Local, Handle, AssetServer,
1719
},
1820
reflect::TypePath,
1921
utils::hashbrown::HashMap,
2022
};
21-
use std::borrow::Cow;
23+
use std::{borrow::Cow, collections::VecDeque};
2224

2325
/// Represents a scripting language. Languages which compile into another language should use the target language as their language.
2426
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Default)]
@@ -300,6 +302,7 @@ pub(crate) fn remove_script_metadata(
300302
pub(crate) fn sync_script_data<P: IntoScriptPluginParams>(
301303
mut events: EventReader<ScriptAssetEvent>,
302304
script_assets: Res<Assets<ScriptAsset>>,
305+
static_scripts: Res<StaticScripts>,
303306
mut commands: Commands,
304307
) {
305308
for event in events.read() {
@@ -326,14 +329,16 @@ pub(crate) fn sync_script_data<P: IntoScriptPluginParams>(
326329
continue;
327330
}
328331

329-
info!("{}: Loading Script: {:?}", P::LANGUAGE, metadata.asset_id,);
330332

331-
if let Some(asset) = script_assets.get(metadata.asset_id) {
332-
commands.queue(CreateOrUpdateScript::<P>::new(
333-
metadata.asset_id.clone(),
334-
asset.content.clone(),
335-
Some(script_assets.reserve_handle().clone_weak()),
336-
));
333+
if static_scripts.iter().any(|handle| handle.id() == metadata.asset_id) {
334+
info!("{}: Loading static script: {:?}", P::LANGUAGE, metadata.asset_id,);
335+
if let Some(asset) = script_assets.get(metadata.asset_id) {
336+
commands.queue(CreateOrUpdateScript::<P>::new(
337+
metadata.asset_id.clone(),
338+
asset.content.clone(),
339+
Some(script_assets.reserve_handle().clone_weak()),
340+
));
341+
}
337342
}
338343
}
339344
ScriptAssetEvent::Removed(_) => {
@@ -344,6 +349,57 @@ pub(crate) fn sync_script_data<P: IntoScriptPluginParams>(
344349
}
345350
}
346351

352+
pub(crate) fn eval_script<P: IntoScriptPluginParams>(
353+
script_comps: Query<&ScriptComponent, Added<ScriptComponent>>,
354+
mut script_queue: Local<VecDeque<ScriptId>>,
355+
script_assets: Res<Assets<ScriptAsset>>,
356+
asset_server: Res<AssetServer>,
357+
mut commands: Commands,
358+
) {
359+
for script_comp in &script_comps {
360+
for handle in &script_comp.0 {
361+
script_queue.push_back(handle.id());
362+
}
363+
}
364+
while ! script_queue.is_empty() {
365+
let script_ready = script_queue.front().map(|script_id| match asset_server.load_state(*script_id) {
366+
LoadState::Failed(e) => {
367+
warn!("Failed to load script {}", &script_id);
368+
true
369+
}
370+
LoadState::Loaded => true,
371+
_ => false
372+
}).unwrap_or(false);
373+
if ! script_ready {
374+
break;
375+
}
376+
// NOTE: Maybe once pop_front_if is stabalized.
377+
// if let Some(script_id) = script_queue.pop_front_if(|script_id| match asset_server.load_state(script_id) {
378+
// LoadState::Failed(e) => {
379+
// warn!("Failed to load script {}", &script_id);
380+
// true
381+
// }
382+
// LoadState::Loaded => true,
383+
// _ => false
384+
// }) {
385+
if let Some(script_id) = script_queue.pop_front() {
386+
if let Some(asset) = script_assets.get(script_id) {
387+
commands.queue(CreateOrUpdateScript::<P>::new(
388+
script_id,
389+
asset.content.clone(),
390+
Some(Handle::Weak(script_id)),
391+
));
392+
} else {
393+
// This is probably a load failure. What to do? We've already
394+
// provided a warning on failure. Doing nothing is fine then we
395+
// process the next one.
396+
}
397+
} else {
398+
break;
399+
}
400+
}
401+
}
402+
347403
/// Setup all the asset systems for the scripting plugin and the dependencies
348404
#[profiling::function]
349405
pub(crate) fn configure_asset_systems(app: &mut App) -> &mut App {
@@ -379,7 +435,7 @@ pub(crate) fn configure_asset_systems_for_plugin<P: IntoScriptPluginParams>(
379435
) -> &mut App {
380436
app.add_systems(
381437
PreUpdate,
382-
sync_script_data::<P>.in_set(ScriptingSystemSet::ScriptCommandDispatch),
438+
(eval_script::<P>, sync_script_data::<P>).in_set(ScriptingSystemSet::ScriptCommandDispatch),
383439
);
384440
app
385441
}

examples/game_of_life.rs

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -24,10 +24,10 @@ use bevy_mod_scripting_core::{
2424
AllocatorDiagnosticPlugin, CoreScriptGlobalsPlugin,
2525
},
2626
callback_labels,
27-
commands::AddStaticScript,
27+
commands::{DeleteScript, AddStaticScript},
2828
event::ScriptCallbackEvent,
2929
handler::event_handler,
30-
script::ScriptComponent,
30+
script::{ScriptId, ScriptComponent},
3131
};
3232
use bevy_mod_scripting_lua::LuaScriptingPlugin;
3333
use bevy_mod_scripting_rhai::RhaiScriptingPlugin;
@@ -56,6 +56,8 @@ fn run_script_cmd(
5656
mut commands: Commands,
5757
asset_server: Res<AssetServer>,
5858
mut script_handle: Local<Option<Handle<ScriptAsset>>>,
59+
script_comps: Query<Entity, With<ScriptComponent>>,
60+
mut static_scripts_created: Local<Vec<ScriptId>>,
5961
) {
6062
if let Some(Ok(command)) = log.take() {
6163
match command {
@@ -64,29 +66,34 @@ fn run_script_cmd(
6466
use_static_script,
6567
} => {
6668
// create an entity with the script component
67-
bevy::log::info!(
68-
"Starting game of life spawning entity with the game_of_life.{} script",
69-
language
70-
);
69+
bevy::log::info!("Using game of life script game_of_life.{}", language);
7170

7271
let script_path = format!("scripts/game_of_life.{}", language);
7372
if !use_static_script {
7473
bevy::log::info!("Spawning an entity with ScriptComponent");
7574
commands.spawn(ScriptComponent::new(vec![asset_server.load(script_path)]));
7675
} else {
7776
bevy::log::info!("Using static script instead of spawning an entity");
78-
commands.queue(AddStaticScript::new(asset_server.load(script_path)))
77+
let handle = asset_server.load(script_path);
78+
static_scripts_created.push(handle.id());
79+
commands.queue(AddStaticScript::new(handle))
7980
}
8081
}
8182
GameOfLifeCommand::Stop => {
8283
// we can simply drop the handle, or manually delete, I'll just drop the handle
8384
bevy::log::info!("Stopping game of life by dropping the handles to all scripts");
8485

8586

87+
for id in &script_comps {
88+
commands.entity(id).despawn();
89+
}
90+
8691
// you could also do
87-
// commands.queue(DeleteScript::<LuaScriptingPlugin>::new(
88-
// "scripts/game_of_life.lua".into(),
89-
// ));
92+
for script_id in static_scripts_created.drain(..) {
93+
commands.queue(DeleteScript::<LuaScriptingPlugin>::new(
94+
script_id
95+
));
96+
}
9097
// as this will retain your script asset and handle
9198
}
9299
}

0 commit comments

Comments
 (0)