Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 11 additions & 8 deletions crates/bevy_mod_scripting_core/src/asset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ use ::{
// },
bevy_reflect::Reflect,
};
use bevy_asset::AssetServer;
use bevy_asset::{AssetServer, Handle};
use bevy_ecs::{
entity::Entity,
event::{EventReader, EventWriter},
Expand All @@ -23,7 +23,7 @@ use bevy_ecs::{
use serde::{Deserialize, Serialize};

use crate::{
IntoScriptPluginParams, LanguageExtensions, ScriptComponent, ScriptingSystemSet, StaticScripts,
IntoScriptPluginParams, LanguageExtensions, ScriptComponent, ScriptingSystemSet,
commands::{CreateOrUpdateScript, DeleteScript},
error::ScriptError,
event::ScriptEvent,
Expand Down Expand Up @@ -215,7 +215,6 @@ fn sync_assets(
fn handle_script_events<P: IntoScriptPluginParams>(
mut events: EventReader<ScriptEvent>,
script_assets: Res<Assets<ScriptAsset>>,
static_scripts: Res<StaticScripts>,
scripts: Query<(Entity, &ScriptComponent)>,
asset_server: Res<AssetServer>,
mut script_queue: Local<ScriptQueue>,
Expand All @@ -233,6 +232,9 @@ fn handle_script_events<P: IntoScriptPluginParams>(
// We need to reload the script for any context it's
// associated with. That could be static scripts, script
// components.

let mut found_entity = false;

for (entity, script_component) in &scripts {
if let Some(handle) =
script_component.0.iter().find(|handle| handle.id() == *id)
Expand All @@ -244,15 +246,16 @@ fn handle_script_events<P: IntoScriptPluginParams>(
))
.with_responses(P::readonly_configuration(world_id).emit_responses),
);
found_entity = true;
}
}

if let Some(handle) = static_scripts.scripts.iter().find(|s| s.id() == *id) {
if !found_entity {
let handle = Handle::Weak(*id);
// if the script does not have any associated entity it's static.
commands.queue(
CreateOrUpdateScript::<P>::new(ScriptAttachment::StaticScript(
handle.clone(),
))
.with_responses(P::readonly_configuration(world_id).emit_responses),
CreateOrUpdateScript::<P>::new(ScriptAttachment::StaticScript(handle))
.with_responses(P::readonly_configuration(world_id).emit_responses),
);
}
}
Expand Down
23 changes: 1 addition & 22 deletions crates/bevy_mod_scripting_core/src/commands.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ use crate::{
},
extractors::{HandlerContext, with_handler_system_state},
handler::{handle_script_errors, send_callback_response},
script::{DisplayProxy, ScriptAttachment, StaticScripts},
script::{DisplayProxy, ScriptAttachment},
};
use bevy_ecs::{system::Command, world::World};
use bevy_log::{error, info, trace};
Expand Down Expand Up @@ -66,23 +66,6 @@ impl<P: IntoScriptPluginParams> Command for DeleteScript<P> {
),
world,
);
match &self.context_key {
ScriptAttachment::EntityScript(_, _) => {
// nothing special needs to be done, just the context removal
}
ScriptAttachment::StaticScript(script) => {
// remove the static script
let mut scripts = world.get_resource_or_init::<StaticScripts>();
if scripts.remove(script.id()) {
debug!("Deleted static script {}", script.display());
} else {
warn!(
"Attempted to delete static script {}, but it was not found",
script.display()
);
}
}
}

let mut script_contexts = world.get_resource_or_init::<ScriptContext<P>>();
let residents_count = script_contexts.residents_len(&self.context_key);
Expand Down Expand Up @@ -225,10 +208,6 @@ impl<P: IntoScriptPluginParams> CreateOrUpdateScript<P> {
) -> Result<(), ScriptError> {
// we demote to weak from here on out, so as not to hold the asset hostage
let attachment = attachment.clone().into_weak();
if let ScriptAttachment::StaticScript(id) = &attachment {
// add to static scripts
handler_ctxt.static_scripts.insert(id.clone());
}

let script_id = attachment.script();

Expand Down
4 changes: 2 additions & 2 deletions crates/bevy_mod_scripting_core/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ pub trait GetPluginThreadConfig<P: IntoScriptPluginParams + ?Sized> {
fn readonly_configuration(world: WorldId) -> ScriptingPluginConfiguration<P>;

/// Set the configuration or overwrites it if already set.
fn set_thread_config(world: WorldId, config: ScriptingPluginConfiguration<P>);
fn set_world_local_config(world: WorldId, config: ScriptingPluginConfiguration<P>);
}

#[macro_export]
Expand Down Expand Up @@ -76,7 +76,7 @@ macro_rules! make_plugin_config_static {
)
}

fn set_thread_config(
fn set_world_local_config(
world: bevy_ecs::world::WorldId,
config: ScriptingPluginConfiguration<$ty>,
) {
Expand Down
11 changes: 1 addition & 10 deletions crates/bevy_mod_scripting_core/src/extractors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use crate::{
error::{InteropError, ScriptError},
event::{CallbackLabel, IntoCallbackLabel},
handler::ScriptingHandler,
script::{ScriptAttachment, ScriptContext, StaticScripts},
script::{ScriptAttachment, ScriptContext},
};

/// Executes `system_state.get_mut` followed by `system_state.apply` after running the given closure, makes sure state is correctly handled in the context of an exclusive system.
Expand All @@ -47,8 +47,6 @@ pub fn with_handler_system_state<

/// Context for systems which handle events for scripts
pub struct HandlerContext<P: IntoScriptPluginParams> {
/// List of static scripts
pub(crate) static_scripts: StaticScripts,
/// Script context
pub(crate) script_context: ScriptContext<P>,
}
Expand All @@ -58,7 +56,6 @@ impl<P: IntoScriptPluginParams> HandlerContext<P> {
/// Every call to this function must be paired with a call to [`Self::release`].
pub fn yoink(world: &mut World) -> Self {
Self {
static_scripts: world.remove_resource().unwrap_or_default(),
script_context: world.remove_resource().unwrap_or_default(),
}
}
Expand All @@ -67,15 +64,9 @@ impl<P: IntoScriptPluginParams> HandlerContext<P> {
/// Only call this if you have previously yoinked the handler context from the world.
pub fn release(self, world: &mut World) {
// insert the handler context back into the world
world.insert_resource(self.static_scripts);
world.insert_resource(self.script_context);
}

/// Get the static scripts
pub fn static_scripts(&mut self) -> &mut StaticScripts {
&mut self.static_scripts
}

/// Get the static scripts
pub fn script_context(&mut self) -> &mut ScriptContext<P> {
&mut self.script_context
Expand Down
5 changes: 2 additions & 3 deletions crates/bevy_mod_scripting_core/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ use context::{Context, ContextInitializer, ContextPreHandlingInitializer};
use event::{ScriptCallbackEvent, ScriptCallbackResponseEvent, ScriptEvent};
use handler::HandlerFn;
use runtime::{Runtime, RuntimeInitializer};
use script::{ContextPolicy, ScriptComponent, ScriptContext, StaticScripts};
use script::{ContextPolicy, ScriptComponent, ScriptContext};
use std::ops::{Deref, DerefMut};

pub mod asset;
Expand Down Expand Up @@ -165,7 +165,7 @@ impl<P: IntoScriptPluginParams> Plugin for ScriptingPlugin<P> {
runtime: Box::leak(Box::new(runtime)),
};

P::set_thread_config(app.world().id(), config);
P::set_world_local_config(app.world().id(), config);

app.insert_resource(ScriptContext::<P>::new(self.context_policy.clone()));

Expand Down Expand Up @@ -294,7 +294,6 @@ impl Plugin for BMSScriptingInfrastructurePlugin {
.add_event::<ScriptCallbackEvent>()
.add_event::<ScriptCallbackResponseEvent>()
.init_resource::<AppReflectAllocator>()
.init_resource::<StaticScripts>()
.init_asset::<ScriptAsset>()
.init_resource::<AppScriptFunctionRegistry>()
.insert_resource(AppScheduleRegistry::new());
Expand Down
76 changes: 0 additions & 76 deletions crates/bevy_mod_scripting_core/src/script/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,88 +125,12 @@ impl ScriptComponent {
}
}

/// A collection of scripts, not associated with any entity.
///
/// Useful for `global` or `static` scripts which operate over a larger scope than a single entity.
#[derive(Default, Resource)]
pub struct StaticScripts {
pub(crate) scripts: HashSet<Handle<ScriptAsset>>,
}

#[profiling::all_functions]
impl StaticScripts {
/// Inserts a static script into the collection
pub fn insert<S: Into<Handle<ScriptAsset>>>(&mut self, script: S) {
self.scripts.insert(script.into());
}

/// Removes a static script from the collection, returning `true` if the script was in the collection, `false` otherwise
pub fn remove(&mut self, script_id: impl Into<ScriptId>) -> bool {
let script_id = script_id.into();
self.scripts
.extract_if(|handle| handle.id() == script_id)
.next()
.is_some()
}

/// Checks if a static script is in the collection
/// Returns `true` if the script is in the collection, `false` otherwise
pub fn contains(&self, script_id: impl Into<ScriptId>) -> bool {
let script_id = script_id.into();
self.scripts.iter().any(|handle| handle.id() == script_id)
}

/// Returns an iterator over the static scripts
pub fn values(&self) -> impl Iterator<Item = &Handle<ScriptAsset>> {
self.scripts.iter()
}
}

#[cfg(test)]
mod tests {
use bevy_ecs::{event::Events, world::World};

use super::*;

#[test]
fn static_scripts_insert() {
let mut static_scripts = StaticScripts::default();
let script1 = Handle::default();
static_scripts.insert(script1.clone());
assert_eq!(static_scripts.scripts.len(), 1);
assert!(static_scripts.scripts.contains(&script1));
}

#[test]
fn static_scripts_remove() {
let mut static_scripts = StaticScripts::default();
let script1 = Handle::default();
static_scripts.insert(script1.clone());
assert_eq!(static_scripts.scripts.len(), 1);
assert!(static_scripts.scripts.contains(&script1));
assert!(static_scripts.remove(&script1));
assert_eq!(static_scripts.scripts.len(), 0);
assert!(!static_scripts.scripts.contains(&script1));
}

fn scriptid_from_u128(uuid: u128) -> ScriptId {
ScriptId::from(uuid::Builder::from_random_bytes(uuid.to_le_bytes()).into_uuid())
}

fn handle_from_u128(uuid: u128) -> Handle<ScriptAsset> {
Handle::Weak(scriptid_from_u128(uuid))
}

#[test]
fn static_scripts_contains() {
let mut static_scripts = StaticScripts::default();
let script1 = handle_from_u128(0);
let script2 = handle_from_u128(1);
static_scripts.insert(script1.clone());
assert!(static_scripts.contains(&script1));
assert!(!static_scripts.contains(&script2));
}

#[test]
fn test_component_add() {
let mut world = World::new();
Expand Down
15 changes: 12 additions & 3 deletions crates/languages/bevy_mod_scripting_lua/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -279,14 +279,23 @@ mod test {
let mut old_ctxt = lua.clone();
let handle = Handle::Weak(AssetId::from(AssetIndex::from_bits(0)));
let context_key = ScriptAttachment::EntityScript(Entity::from_raw(1), handle);

let world_id = WorldId::new().unwrap();
LuaScriptingPlugin::set_world_local_config(
world_id,
ScriptingPluginConfiguration {
pre_handling_callbacks: &[],
context_initialization_callbacks: &[],
emit_responses: false,
runtime: &(),
},
);
lua_context_load(
&context_key,
"function hello_world_from_first_load()

end"
.as_bytes(),
WorldId::new().unwrap(),
world_id,
)
.unwrap();

Expand All @@ -297,7 +306,7 @@ mod test {
end"
.as_bytes(),
&mut old_ctxt,
WorldId::new().unwrap(),
world_id,
)
.unwrap();

Expand Down
7 changes: 4 additions & 3 deletions examples/game_of_life.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use bevy::{
};
use bevy_console::{AddConsoleCommand, ConsoleCommand, ConsoleOpen, ConsolePlugin, make_layer};
use bevy_mod_scripting::{core::bindings::AllocatorDiagnosticPlugin, prelude::*};
use bevy_mod_scripting_core::{commands::RemoveStaticScript, script::StaticScripts};
use bevy_mod_scripting_core::commands::RemoveStaticScript;
use clap::Parser;

// CONSOLE SETUP
Expand All @@ -42,7 +42,7 @@ fn run_script_cmd(
mut commands: Commands,
asset_server: Res<AssetServer>,
script_comps: Query<(Entity, &ScriptComponent)>,
static_scripts: Res<StaticScripts>,
mut static_scripts: Local<Vec<Handle<ScriptAsset>>>,
) {
if let Some(Ok(command)) = log.take() {
match command {
Expand All @@ -60,6 +60,7 @@ fn run_script_cmd(
} else {
bevy::log::info!("Using static script instead of spawning an entity");
let handle = asset_server.load(script_path);
static_scripts.push(handle.clone());
commands.queue(AddStaticScript::new(handle))
}
}
Expand All @@ -72,7 +73,7 @@ fn run_script_cmd(
commands.entity(id).despawn();
}

for script in static_scripts.values() {
for script in static_scripts.iter() {
commands.queue(RemoveStaticScript::new(script.clone()));
}
}
Expand Down
5 changes: 1 addition & 4 deletions tests/script_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,10 +28,7 @@ impl TestExecutor for Test {

// do this in a separate thread to isolate the thread locals

match execute_integration_test(scenario) {
Ok(_) => Ok(()),
Err(e) => Err(Failed::from(format!("{e:?}"))), // print whole error from anyhow including source and backtrace
}
Ok(execute_integration_test(scenario)?)
}

fn name(&self) -> String {
Expand Down
Loading