diff --git a/assets/tests/lifecycle/default/entity_script/loading/scenario.bmsscenario b/assets/tests/lifecycle/default/entity_script/loading/scenario.bmsscenario index 616e2dd3fa..2ac7a64ecf 100644 --- a/assets/tests/lifecycle/default/entity_script/loading/scenario.bmsscenario +++ b/assets/tests/lifecycle/default/entity_script/loading/scenario.bmsscenario @@ -1,3 +1,4 @@ +// #main_script lifecycle.lua SetCurrentLanguage language="@this_script_language" InstallPlugin emit_responses=true FinalizeApp @@ -19,6 +20,22 @@ AssertCallbackSuccess attachment="EntityScript", entity="test_entity_a", label=" AssertCallbackSuccess attachment="EntityScript", entity="test_entity_a", label="OnScriptReloaded", script="script_a", expect_string_value="reloaded with: unloaded!" AssertNoCallbackResponsesEmitted +// insert second.lua into original entity +LoadScriptAs as_name="script_b", path="second.lua" +WaitForScriptAssetLoaded name="script_b" +AddScriptToEntity name="test_entity_a", script="script_b" +RunUpdateOnce +AssertCallbackSuccess attachment="EntityScript", entity="test_entity_a", label="OnScriptLoaded", script="script_b", expect_string_value="2:loaded!" +AssertNoCallbackResponsesEmitted +AssertContextResidents attachment="EntityScript", script="script_a", entity="test_entity_a", residents_num=1 +AssertContextResidents attachment="EntityScript", script="script_b", entity="test_entity_a", residents_num=1 + +// remove second.lua from original entity +RemoveScriptFromEntity name="test_entity_a", script="script_b" +RunUpdateOnce +AssertCallbackSuccess attachment="EntityScript", entity="test_entity_a", label="OnScriptUnloaded", script="script_b", expect_string_value="2:unloaded!" +AssertNoCallbackResponsesEmitted + // now first drop the script asset, assert that does nothing yet DropScriptAsset script="script_a" RunUpdateOnce diff --git a/assets/tests/lifecycle/default/entity_script/loading/second.lua b/assets/tests/lifecycle/default/entity_script/loading/second.lua new file mode 100644 index 0000000000..fe57e63bc2 --- /dev/null +++ b/assets/tests/lifecycle/default/entity_script/loading/second.lua @@ -0,0 +1,11 @@ +function on_script_loaded() + return "2:loaded!" +end + +function on_script_unloaded() + return "2:unloaded!" +end + +function on_script_reloaded(val) + return "2:reloaded with: " .. val +end diff --git a/crates/bevy_mod_scripting_core/src/lib.rs b/crates/bevy_mod_scripting_core/src/lib.rs index d9be349f2b..feffe99332 100644 --- a/crates/bevy_mod_scripting_core/src/lib.rs +++ b/crates/bevy_mod_scripting_core/src/lib.rs @@ -9,8 +9,9 @@ use crate::{ event::ScriptErrorEvent, handler::script_error_logger, pipeline::ScriptLoadingPipeline, + script::{ScriptComponentsChangeCache, script_component_changed_handler}, }; -use bevy_app::{App, Plugin, PostUpdate}; +use bevy_app::{App, Plugin, PostUpdate, PreUpdate}; use bevy_asset::{AssetApp, Handle}; use bevy_ecs::schedule::IntoScheduleConfigs; use bevy_ecs::{ @@ -46,16 +47,11 @@ pub mod script_system; #[derive(SystemSet, Hash, Debug, Eq, PartialEq, Clone)] /// Labels for various BMS systems pub enum ScriptingSystemSet { - /// Systems which handle the processing of asset events for script assets, and dispatching internal script asset events - ScriptAssetDispatch, - /// Systems which read incoming internal script asset events and produce script lifecycle commands - ScriptCommandDispatch, - // /// Systems which read entity removal events and remove contexts associated with them - // EntityRemoval, - /// One time runtime initialization systems - RuntimeInitialization, - /// Systems which handle the garbage collection of allocated values + /// Systems in [`PostUpdate`] which handle the garbage collection of allocated values GarbageCollection, + + /// Systems in [`PreUpdate`] dispatching pipeline events whenever handles are added or removed from [`ScriptComponent`]'s + SyncScriptingComponents, } /// Types which act like scripting plugins, by selecting a context and runtime @@ -172,6 +168,7 @@ impl Plugin for ScriptingPlugin

{ P::set_world_local_config(app.world().id(), config); app.insert_resource(ScriptContexts::

::new(self.context_policy.clone())); + app.init_resource::(); app.register_asset_loader(ScriptAssetLoader::new(config.language_extensions)); app.add_plugins(( @@ -355,6 +352,11 @@ impl Plugin for BMSScriptingInfrastructurePlugin { ((garbage_collector).in_set(ScriptingSystemSet::GarbageCollection),), ); + app.add_systems( + PreUpdate, + script_component_changed_handler.in_set(ScriptingSystemSet::SyncScriptingComponents), + ); + if !self.dont_log_script_event_errors { app.add_systems(PostUpdate, script_error_logger); } diff --git a/crates/bevy_mod_scripting_core/src/pipeline/mod.rs b/crates/bevy_mod_scripting_core/src/pipeline/mod.rs index 7b8f994543..2efc25b56f 100644 --- a/crates/bevy_mod_scripting_core/src/pipeline/mod.rs +++ b/crates/bevy_mod_scripting_core/src/pipeline/mod.rs @@ -18,7 +18,7 @@ use bevy_mod_scripting_display::DisplayProxy; use parking_lot::Mutex; use crate::{ - IntoScriptPluginParams, + IntoScriptPluginParams, ScriptingSystemSet, context::ScriptingLoader, error::ScriptError, event::{ @@ -249,6 +249,7 @@ impl Plugin for ScriptLoadingPipeline

{ PreUpdate, PipelineSet::ListeningPhase .after(bevy_asset::AssetTrackingSystems) + .after(ScriptingSystemSet::SyncScriptingComponents) // we want to pick up changes immediately .before(PipelineSet::MachineStartPhase), ); diff --git a/crates/bevy_mod_scripting_core/src/script/mod.rs b/crates/bevy_mod_scripting_core/src/script/mod.rs index c7b7e06892..6aaa300175 100644 --- a/crates/bevy_mod_scripting_core/src/script/mod.rs +++ b/crates/bevy_mod_scripting_core/src/script/mod.rs @@ -17,7 +17,15 @@ use ::{ mod context_key; mod script_context; -use bevy_ecs::{component::Component, lifecycle::HookContext}; +use bevy_ecs::{ + component::Component, + entity::EntityHashMap, + lifecycle::HookContext, + message::MessageWriter, + query::Changed, + system::{Query, ResMut}, + world::Ref, +}; use bevy_log::trace; use bevy_mod_scripting_asset::ScriptAsset; use bevy_mod_scripting_script::ScriptAttachment; @@ -29,7 +37,7 @@ pub use script_context::*; /// I.e. an asset with the path `path/to/asset.ext` will have the script id `path/to/asset.ext` pub type ScriptId = Handle; -#[derive(Component, Reflect, Clone, Default, Debug)] +#[derive(Component, Reflect, Clone, Default, Debug, PartialEq, Eq)] #[reflect(Component)] #[component(on_remove=Self::on_remove, on_add=Self::on_add)] /// A component which identifies the scripts existing on an entity. @@ -65,7 +73,13 @@ impl ScriptComponent { /// the removal of the script. pub fn on_remove(mut world: DeferredWorld, context: HookContext) { let context_keys = Self::get_context_keys_present(&world, context.entity); + trace!("on remove hook for script components: {context_keys:?}"); + + if let Some(mut cache) = world.get_resource_mut::() { + cache.last_values.remove(&context.entity); + } + world.write_message_batch(context_keys.into_iter().map(ScriptDetachedEvent)); } @@ -74,10 +88,70 @@ impl ScriptComponent { pub fn on_add(mut world: DeferredWorld, context: HookContext) { let context_keys = Self::get_context_keys_present(&world, context.entity); trace!("on add hook for script components: {context_keys:?}"); + + if let Some(mut cache) = world.get_resource_mut::() { + cache.last_values.insert( + context.entity, + context_keys.iter().map(|x| x.script().clone()).collect(), + ); + } + world.write_message_batch(context_keys.into_iter().map(ScriptAttachedEvent)); } } +/// Cache holding the last values of script components +/// Allows the calculation of what handles have been added or removed since last frame. +/// +/// Any handles in this cache are removed immediately when they are removed via the component +#[derive(Resource, Default)] +pub struct ScriptComponentsChangeCache { + last_values: EntityHashMap>>, +} + +/// A system that handles pure modifications to a [`ScriptComponent`]. +/// +/// Other lifecycle events, such as addition and removal of these components are handled immediately via component hooks. +pub fn script_component_changed_handler( + mut cache: ResMut, + changed: Query<(Entity, Ref), Changed>, + mut attachment_messages: MessageWriter, + mut detachment_messages: MessageWriter, +) { + for (entity, current_value) in changed { + if let Some(last_value) = cache.last_values.get_mut(&entity) { + let mut any_change = false; + + // check removals + for old in last_value.iter() { + if !current_value.0.contains(old) { + any_change = true; + detachment_messages.write(ScriptDetachedEvent(ScriptAttachment::EntityScript( + entity, + old.clone(), + ))); + } + } + + // check additions + for new in current_value.0.iter() { + if !last_value.contains(new) { + any_change = true; + attachment_messages.write(ScriptAttachedEvent(ScriptAttachment::EntityScript( + entity, + new.clone(), + ))); + } + } + + if any_change { + last_value.clear(); + last_value.extend(current_value.0.iter().cloned()); + } + } + } +} + #[cfg(test)] mod tests { use bevy_ecs::{message::Messages, world::World}; diff --git a/crates/testing_crates/bevy_mod_scripting_test_scenario_syntax/src/parse.rs b/crates/testing_crates/bevy_mod_scripting_test_scenario_syntax/src/parse.rs index 096be2b399..f5602b847b 100644 --- a/crates/testing_crates/bevy_mod_scripting_test_scenario_syntax/src/parse.rs +++ b/crates/testing_crates/bevy_mod_scripting_test_scenario_syntax/src/parse.rs @@ -110,6 +110,20 @@ pub enum ScenarioStepSerialized { /// the script to spawn on the entity script: String, }, + /// Pushes a script into the existing script component on an entity, or creates a new one and inserts the script + AddScriptToEntity { + /// the name of the entity to insert into + name: String, + /// the name of the script to insert + script: String, + }, + /// Removes a script from the entity, asserting it exists + RemoveScriptFromEntity { + /// the name of the entity to remove from + name: String, + /// the name of the script to remove + script: String, + }, /// Attaches a static script AttachStaticScript { /// the script to be attached diff --git a/crates/testing_crates/bevy_mod_scripting_test_scenario_syntax/src/schema.rs b/crates/testing_crates/bevy_mod_scripting_test_scenario_syntax/src/schema.rs index cbf48de314..f954285fa7 100644 --- a/crates/testing_crates/bevy_mod_scripting_test_scenario_syntax/src/schema.rs +++ b/crates/testing_crates/bevy_mod_scripting_test_scenario_syntax/src/schema.rs @@ -167,6 +167,28 @@ fn get_schema() -> ScenarioSchema { .collect(), }, ), + ( + "AddScriptToEntity".into(), + StepSchema { + fields: vec![ + str_field("name", false, "the name of the script to insert"), + str_field("script", false, "the name of the entity to insert into"), + ] + .into_iter() + .collect(), + }, + ), + ( + "RemoveScriptFromEntity".into(), + StepSchema { + fields: vec![ + str_field("name", false, "the name of the entity to remove from"), + str_field("script", false, "the name of the script to remove"), + ] + .into_iter() + .collect(), + }, + ), ( "DetachStaticScript".into(), StepSchema { diff --git a/crates/testing_crates/script_integration_test_harness/src/scenario.rs b/crates/testing_crates/script_integration_test_harness/src/scenario.rs index fc19485444..fa142d5d51 100644 --- a/crates/testing_crates/script_integration_test_harness/src/scenario.rs +++ b/crates/testing_crates/script_integration_test_harness/src/scenario.rs @@ -298,6 +298,18 @@ impl Scenario { entity: name, } } + ScenarioStepSerialized::AddScriptToEntity { name, script } => { + ScenarioStep::AddScriptToEntity { + script: self.context.get_script_handle(&script)?, + name: self.context.get_entity(&name)?, + } + } + ScenarioStepSerialized::RemoveScriptFromEntity { name, script } => { + ScenarioStep::RemoveScriptFromEntity { + script: self.context.get_script_handle(&script)?, + name: self.context.get_entity(&name)?, + } + } ScenarioStepSerialized::ReloadScriptFrom { script, path } => { ScenarioStep::ReloadScriptFrom { script: self.context.get_script_handle(&script)?, @@ -569,6 +581,14 @@ pub enum ScenarioStep { SetNanosecondsBudget { nanoseconds_budget: Option, }, + AddScriptToEntity { + script: Handle, + name: Entity, + }, + RemoveScriptFromEntity { + script: Handle, + name: Entity, + }, } /// Execution @@ -1097,6 +1117,27 @@ impl ScenarioStep { } } } + ScenarioStep::AddScriptToEntity { script, name } => { + let world = app.world_mut(); + world + .entity_mut(name) + .entry::() + .and_modify(|mut c| c.0.push(script.clone())) + .or_insert_with(|| ScriptComponent(vec![script])); + } + ScenarioStep::RemoveScriptFromEntity { script, name } => { + let world = app.world_mut(); + let mut entity = world.entity_mut(name); + let mut component = match entity.get_mut::() { + Some(component) => component, + None => { + return Err(anyhow!( + "Expected script {script:?} to exist on entity {name}" + )); + } + }; + component.0.retain(|c| c != &script); + } } Ok(()) } diff --git a/scenario_file_language_server/out/.gitignore b/scenario_file_language_server/out/.gitignore new file mode 100644 index 0000000000..e69de29bb2 diff --git a/scenario_file_language_server/out/extension.js b/scenario_file_language_server/out/extension.js deleted file mode 100644 index 29f228520e..0000000000 --- a/scenario_file_language_server/out/extension.js +++ /dev/null @@ -1,75 +0,0 @@ -"use strict"; -Object.defineProperty(exports, "__esModule", { value: true }); -exports.activate = activate; -exports.deactivate = deactivate; -const vscode = require("vscode"); -const fs = require("fs"); -const path = require("path"); -let schema; -function activate(context) { - // Create output channel - const output = vscode.window.createOutputChannel("Scenario DSL"); - output.show(true); - output.appendLine("Activating Scenario DSL extension..."); - try { - const schemaPath = path.join(context.extensionPath, "src", "schema.json"); - schema = JSON.parse(fs.readFileSync(schemaPath, "utf-8")); - output.appendLine(`Loaded schema with ${Object.keys(schema.steps).length} steps.`); - } - catch (err) { - output.appendLine("Error loading schema.json:"); - output.appendLine(String(err)); - vscode.window.showErrorMessage("Scenario DSL: Failed to load schema.json. Check Output → Scenario DSL."); - return; // don’t register provider if schema fails - } - const provider = vscode.languages.registerCompletionItemProvider("scenario", { - provideCompletionItems(document, position) { - try { - const linePrefix = document.lineAt(position).text.slice(0, position.character); - output.appendLine(`Completion requested for line: "${linePrefix}"`); - // Suggest step names if line is empty or whitespace - if (/^\s*$/.test(linePrefix)) { - const items = Object.keys(schema.steps).map(step => { - const item = new vscode.CompletionItem(step, vscode.CompletionItemKind.Function); - item.detail = "Scenario step"; - return item; - }); - output.appendLine(`Suggesting ${items.length} steps.`); - return items; - } - // Suggest fields after a step - const stepMatch = linePrefix.match(/^(\w+)\s+/); - if (stepMatch) { - const stepName = stepMatch[1]; - const stepSchema = schema.steps[stepName]; - output.appendLine(`Detected step: ${stepName}`); - if (stepSchema) { - const items = Object.entries(stepSchema.fields).map(([name, field]) => { - const item = new vscode.CompletionItem(name, vscode.CompletionItemKind.Property); - item.detail = field.doc; - item.insertText = `${name}=`; - return item; - }); - output.appendLine(`Suggesting ${items.length} fields for step ${stepName}.`); - return items; - } - else { - output.appendLine(`Step ${stepName} not found in schema.`); - } - } - return []; - } - catch (err) { - output.appendLine("Error in completion provider:"); - output.appendLine(String(err)); - return []; - } - } - }, " ", "=" // trigger completions on space or '=' - ); - context.subscriptions.push(provider); - context.subscriptions.push(output); - output.appendLine("Scenario DSL extension activated."); -} -function deactivate() { } -//# sourceMappingURL=extension.js.map \ No newline at end of file diff --git a/scenario_file_language_server/out/extension.js.map b/scenario_file_language_server/out/extension.js.map deleted file mode 100644 index 9bed7c7b72..0000000000 --- a/scenario_file_language_server/out/extension.js.map +++ /dev/null @@ -1 +0,0 @@ -{"version":3,"file":"extension.js","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/scenario_file_language_server/package.json b/scenario_file_language_server/package.json index dbb8059f6a..f97b1067ad 100644 --- a/scenario_file_language_server/package.json +++ b/scenario_file_language_server/package.json @@ -2,7 +2,7 @@ "name": "scenario-dsl", "displayName": "Scenario DSL", "description": "Syntax highlighting and completions for Scenario DSL from the bevy mod scripting framework", - "version": "0.0.1", + "version": "0.0.2", "publisher": "MaksymilianMozolewski", "engines": { "vscode": "^1.80.0" diff --git a/scenario_file_language_server/src/scenario.tmLanguage.json b/scenario_file_language_server/src/scenario.tmLanguage.json index eb9e06c00e..f6e2500248 100644 --- a/scenario_file_language_server/src/scenario.tmLanguage.json +++ b/scenario_file_language_server/src/scenario.tmLanguage.json @@ -21,7 +21,7 @@ "patterns": [ { "name": "keyword.control.step.scenario", - "match": "\\b(SetCurrentLanguage|InstallPlugin|SetupHandler|FinalizeApp|LoadScriptAs|WaitForScriptAssetLoaded|SpawnEntityWithScript|RunUpdateOnce|EmitScriptCallbackEvent|AssertCallbackSuccess|AssertNoCallbackResponsesEmitted|AssertContextState|AssertContextResidents|ReloadScriptFrom|DropScriptAsset|DespawnEntity|AttachStaticScript)\\b" + "match": "\\b(SetCurrentLanguage|InstallPlugin|SetupHandler|FinalizeApp|LoadScriptAs|WaitForScriptAssetLoaded|SpawnEntityWithScript|RunUpdateOnce|EmitScriptCallbackEvent|AssertCallbackSuccess|AssertNoCallbackResponsesEmitted|AssertContextState|AssertContextResidents|ReloadScriptFrom|DropScriptAsset|DespawnEntity|AttachStaticScript|RemoveScriptFromEntity|AddScriptToEntity)\\b" }, { "name": "variable.parameter.field.scenario", diff --git a/scenario_file_language_server/src/schema.json b/scenario_file_language_server/src/schema.json index 9beb8c871c..d0e26cb2d7 100644 --- a/scenario_file_language_server/src/schema.json +++ b/scenario_file_language_server/src/schema.json @@ -1,5 +1,19 @@ { "steps": { + "AddScriptToEntity": { + "fields": { + "name": { + "ty": "String", + "optional": false, + "doc": "the name of the script to insert" + }, + "script": { + "ty": "String", + "optional": false, + "doc": "the name of the entity to insert into" + } + } + }, "AssertCallbackSuccess": { "fields": { "attachment": { @@ -219,6 +233,20 @@ } } }, + "RemoveScriptFromEntity": { + "fields": { + "name": { + "ty": "String", + "optional": false, + "doc": "the name of the entity to remove from" + }, + "script": { + "ty": "String", + "optional": false, + "doc": "the name of the script to remove" + } + } + }, "RunUpdateOnce": { "fields": {} },