Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
95 changes: 95 additions & 0 deletions .github/instructions/documentation.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
---
applyTo: docs/, **/*.md
---

# Documentation Instructions

The `/docs` folder contain documentation for the project as well as release notes.

Newer release notes should be added to `/docs/src/ReleaseNotes/`.

When making changes to the documentation, please ensure that you follow these guidelines:
- Use clear and concise language, focusing on EXAMPLES and practical usage.
- Use these naming conventions:
- Use lowercase letters and hyphens for file names (e.g., `my-documentation-file.md`).
- for migration guides use the format `0.0.1-to-0.0.2.md`.
- for release notes use the format `0.0.1.md`.


# Release Notes Instructions

Release notes should highlight the major highlights of each release, while leaving the breaking changes for migration guides.

When creating release notes, please follow these guidelines:
- Include links to relevant issues or pull requests when applicable.
- YOU MUST use the following heading structure:
- `# Version - Short Description`
- `## Summary`
- `### <Theme>` for each major theme or change
- `### Other Changes` (if applicable) for smaller changes worth mentioning
- `## Migration Guide` (if applicable) providing a link to the detailed migration guide.


# Migration Guide Instructions

When creating migration guides, please follow these guidelines:
- Provide step-by-step instructions for updating projects to the new version.
- Each breaking change should come under a heading related to the change i.e. `### ScriptAsset removed`
- Include code snippets to illustrate changes.
- Use diff format when talking about concrete changes to specific structures or traits.
- Include links to relevant issues or pull requests when applicable.
- Generally each pull request has a migration guide section, which must be taken into account and expanded on when writing relevant migration guides.


# Examples

## Release Notes Example

```markdown
# 0.15.0 - Asset Handles and Context Policies

This release focuses on aligning `bevy_mod_scripting` with modern Bevy practices, most notably by switching to `Handle<ScriptAsset>` for script management. This change simplifies the API, removes boilerplate, and makes script handling more idiomatic.

## Summary

### Asset-First Workflow
Scripts are now treated as first-class Bevy assets. The old `ScriptId` (which was a string) has been replaced by `AssetId<ScriptAsset>`, and you'll primarily interact with scripts via `Handle<ScriptAsset>`.

```rust,ignore
// New way
let handle: Handle<ScriptAsset> = asset_server.load("my_script.lua");
commands.spawn(ScriptComponent(vec![handle]));
```

Scripts are now only evaluated when they are attached to a `ScriptComponent` or added to `StaticScripts`, which means you have more control over when and how scripts are executed.

### Other Changes
- **`Recipients` Enum:** The `Recipients` enum for events has been redesigned to align with the new context policies, offering `AllScripts` and `AllContexts` variants, and removing some variants which don't fit the new model. If you need the old behaviour, you can simply query the ECS first before sending events.
- **API Cleanup:** Several types and traits were removed or simplified, including `ScriptAssetSettings`, `AssetPathToScriptIdMapper`, and `ScriptMetadataStore`, as they are no longer needed with the new asset-based approach.

## Migration Guide
This release contains significant breaking changes. Please refer to the migration guide for detailed instructions on updating your project.

- [Migration Guide: 0.14 to 0.15](https://makspll.github.io/bevy_mod_scripting/Migration/0.14-to-0.15.html)

```

## Migration Guide Example

```markdown
# Migration Guide: <from> to <to>

## Changes to pre handling callbacks

This change affects the parameters for the `context_pre_handling_initializers`
```diff
- context_pre_handling_initializers: vec![|script_id, entity, context| {
+ context_pre_handling_initializers: vec![|context_key, context| {
```
and `context_initializers`:
```diff
- context_initializers: vec![|script_id, context| {
+ context_initializers: vec![|context_key, context| {
```

```
40 changes: 40 additions & 0 deletions .github/instructions/general.instructions.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
---
applyTo: **
---

# Repository Instructions

## High-Level Structure

### Core Components
- **bevy_mod_scripting** - Main workspace crate that re-exports key functionality.
- **bevy_mod_scripting_core** - Core framework with language-agnostic scripting functionality
- **bevy_mod_scripting_asset** - Handles script assets, loading, and language detection
- **bevy_mod_scripting_derive** - Procedural macros for generating bindings
- **bevy_mod_scripting_functions** - Core Bevy function bindings, and plugin managing various binding crates via features.

### Language Implementations
- **bevy_mod_scripting_lua** - Lua language implementation
- **bevy_mod_scripting_rhai** - Rhai language implementation

### Binding Crates
- Multiple **bevy_*_bms_bindings** crates (e.g., transform, asset, pbr, etc.) that provide specific Bevy module bindings
- These are automatically generated via the `/codegen` tools, per bevy release

### Development Tools
- **xtask** - Custom task runner for development workflows
- **codegen** - Code generation tools for generating bindings from Bevy's API
- **docs** - Documentation built with mdbook
- **docs/src/ReleaseNotes** - Release notes and migration guides

## Key Features

1. **Script Management** - Loading, hot reloading, and lifecycle management via Bevy's asset system
2. **Flexible Bindings** - Attach bindings to any Reflect-implementing types
3. **Dynamic Systems** - Create ECS systems from scripts that run in parallel
4. **Component Creation** - Register and use components from scripts
5. **Multiple Language Support** - Currently supports Lua and Rhai


## Xtask Commands
- `cargo xtask check` - Builds the project and runs clippy
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
// perfect application of AI
// helps proompting LLMs to do good for this project
---
applyTo: **/.rhai
---

# Convert lua to rhai script
Convert the current test to a rhai test. below are examples and instructions on the conversions necessary:
Expand Down
9 changes: 7 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,8 @@ bevy_mod_scripting_rhai = { workspace = true, optional = true }
bevy_mod_scripting_functions = { workspace = true }
bevy_mod_scripting_derive = { workspace = true }
bevy_mod_scripting_asset = { workspace = true }
bevy_mod_scripting_bindings = { workspace = true }
bevy_mod_scripting_display = { workspace = true }

[workspace.dependencies]
# local crates
Expand All @@ -112,7 +114,8 @@ ladfile_builder = { path = "crates/ladfile_builder", version = "0.5.1" }
bevy_mod_scripting_lua = { path = "crates/languages/bevy_mod_scripting_lua", version = "0.15.1", default-features = false }
bevy_mod_scripting_rhai = { path = "crates/languages/bevy_mod_scripting_rhai", version = "0.15.1", default-features = false }
bevy_mod_scripting_asset = { path = "crates/bevy_mod_scripting_asset", version = "0.15.1", default-features = false }

bevy_mod_scripting_bindings = { path = "crates/bevy_mod_scripting_bindings", version = "0.15.1", default-features = false }
bevy_mod_scripting_display = { path = "crates/bevy_mod_scripting_display", version = "0.15.1", default-features = false }
# bevy

bevy_mod_scripting_core = { path = "crates/bevy_mod_scripting_core", version = "0.15.1" }
Expand Down Expand Up @@ -190,7 +193,7 @@ itertools = { version = "0.14", default-features = false }
fixedbitset = { version = "0.5", default-features = false }
variadics_please = { version = "1.1.0", default-features = false }
anyhow = { version = "1.0", default-features = false }

indent_write = { version = "2", default-features = false, features = ["std"] }

# development and testing

Expand Down Expand Up @@ -245,6 +248,8 @@ members = [
"crates/bevy_system_reflection",
"crates/bindings/*",
"crates/bevy_mod_scripting_asset",
"crates/bevy_mod_scripting_bindings",
"crates/bevy_mod_scripting_display",
]
resolver = "2"
exclude = ["codegen", "crates/macro_tests", "xtask"]
Expand Down
2 changes: 1 addition & 1 deletion assets/tests/add_system/added_systems_run_in_parallel.lua
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ digraph {
node_1 [label="bevy_asset::assets::Assets<bevy_asset::assets::LoadedUntypedAsset>::asset_events"];
node_2 [label="bevy_asset::assets::Assets<()>::asset_events"];
node_3 [label="bevy_asset::assets::Assets<bevy_mod_scripting_asset::script_asset::ScriptAsset>::asset_events"];
node_4 [label="bevy_mod_scripting_core::bindings::allocator::garbage_collector"];
node_4 [label="bevy_mod_scripting_bindings::allocator::garbage_collector"];
node_5 [label="script_integration_test_harness::dummy_before_post_update_system"];
node_6 [label="script_integration_test_harness::dummy_post_update_system"];
node_7 [label="on_test_post_update"];
Expand Down
2 changes: 1 addition & 1 deletion assets/tests/add_system/added_systems_run_in_parallel.rhai
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ digraph {
node_1 [label="bevy_asset::assets::Assets<bevy_asset::assets::LoadedUntypedAsset>::asset_events"];
node_2 [label="bevy_asset::assets::Assets<()>::asset_events"];
node_3 [label="bevy_asset::assets::Assets<bevy_mod_scripting_asset::script_asset::ScriptAsset>::asset_events"];
node_4 [label="bevy_mod_scripting_core::bindings::allocator::garbage_collector"];
node_4 [label="bevy_mod_scripting_bindings::allocator::garbage_collector"];
node_5 [label="script_integration_test_harness::dummy_before_post_update_system"];
node_6 [label="script_integration_test_harness::dummy_post_update_system"];
node_7 [label="on_test_post_update"];
Expand Down
5 changes: 2 additions & 3 deletions assets/tests/construct/construct_tuple_struct.lua
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,5 @@ local constructed = construct(type, {
_1 = 123
})

print(constructed:display_value())

assert(constructed._1 == 123, "Value was constructed incorrectly, expected constructed.foo to be 123 but got " .. constructed._1)
assert(constructed._1 == 123,
"Value was constructed incorrectly, expected constructed.foo to be 123 but got " .. constructed._1)
71 changes: 71 additions & 0 deletions assets/tests/display/print_value_by_default.lua
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
local vec = Vec3.new(1, 2, 3)

assert(vec:display() == "Vec3 { x: 1.0, y: 2.0, z: 3.0 }",
"Vec3 display incorrect, expected Vec3 { x: 1.0, y: 2.0, z: 3.0 } but got " .. vec:display())


-- multiline
local function strip_alloc_ids(s)
s = s:gsub("ReflectAllocationId%b()", "ReflectAllocationId()")
return s
end

local expected_vec3_debug = [[
ReflectReference {
base: ReflectBaseType {
type_id: TypeId(
"glam::Vec3",
),
base_id: Owned(
ReflectAllocationId(*anything*),
),
},
reflect_path: ParsedPath(
[],
),
}
]]
-- normalize allocation ids before comparison so tests don't fail on runtime-generated ids
do
local actual = vec:debug()
local expected = expected_vec3_debug
actual = strip_alloc_ids(actual)
expected = strip_alloc_ids(expected)
assert_str_eq(actual, expected)
end


local test_resource = world.get_resource(types.TestResource)

local expected_test_resource_debug = [[
ReflectReference {
base: ReflectBaseType {
type_id: TypeId(
"test_utils::test_data::TestResource",
),
base_id: Resource(
ComponentId(
"test_utils::test_data::TestResource",
),
),
},
reflect_path: ParsedPath(
[],
),
}
]]

-- normalize allocation ids before comparison so tests don't fail on runtime-generated ids
do
local actual = test_resource:debug()
local expected = expected_test_resource_debug
actual = strip_alloc_ids(actual)
expected = strip_alloc_ids(expected)
assert_str_eq(actual, expected,
"TestResource debug incorrect, expected " .. expected .. " but got " .. actual)
end


assert_str_eq(test_resource:display(), "TestResource { bytes: [0, 1, 2, 3, 4, 5] }",
"TestResource display incorrect, expected TestResource { bytes: [0, 1, 2, 3, 4, 5] } but got " ..
test_resource:display())
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@ for _, function_ref in pairs(functions) do
table.insert(available_names, function_ref.name)
end

assert(contains(available_names, "display_ref"), "functions should contain display_ref, but got: " .. table.concat(available_names, ", "))
assert(contains(available_names, "display"),
"functions should contain display, but got: " .. table.concat(available_names, ", "))
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,4 @@ for function_ref in functions {
available_names.push(function_ref.name);
}

assert("display_ref" in available_names, "functions should contain display_ref, but got: " + available_names);
assert("display" in available_names, "functions should contain display, but got: " + available_names);
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,12 @@ local received = {
}

assert(type ~= nil, 'Type not found')
assert(received.type_name == expected.type_name, 'type_name mismatch, expected: ' .. expected.type_name .. ', got: ' .. received.type_name)
assert(received.short_name == expected.short_name, 'short_name mismatch, expected: ' .. expected.short_name .. ', got: ' .. received.short_name)
assert(received.type_name == expected.type_name,
'type_name mismatch, expected: ' .. expected.type_name .. ', got: ' .. received.type_name)
assert(received.short_name == expected.short_name,
'short_name mismatch, expected: ' .. expected.short_name .. ', got: ' .. received.short_name)

local type_ref = type:display_ref()
local type_ref = type:display()
-- check contains ScriptComponentRegistration
assert(string.find(type_ref, "ScriptComponentRegistration") ~= nil, "ScriptComponentRegistration not found in type_ref. got: " .. type_ref)
assert(string.find(type_ref, "ScriptComponentRegistration") ~= nil,
"ScriptComponentRegistration not found in type_ref. got: " .. type_ref)
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@ local received = {
}

assert(type ~= nil, 'Type not found')
assert(received.type_name == expected.type_name, 'type_name mismatch, expected: ' .. expected.type_name .. ', got: ' .. received.type_name)
assert(received.short_name == expected.short_name, 'short_name mismatch, expected: ' .. expected.short_name .. ', got: ' .. received.short_name)
local type_ref = type:display_ref()
assert(received.type_name == expected.type_name,
'type_name mismatch, expected: ' .. expected.type_name .. ', got: ' .. received.type_name)
assert(received.short_name == expected.short_name,
'short_name mismatch, expected: ' .. expected.short_name .. ', got: ' .. received.short_name)
local type_ref = type:display()
-- check contains ScriptResourceRegistration
assert(string.find(type_ref, "ScriptResourceRegistration") ~= nil, "ScriptResourceRegistration not found in type_ref. got: " .. type_ref)
assert(string.find(type_ref, "ScriptResourceRegistration") ~= nil,
"ScriptResourceRegistration not found in type_ref. got: " .. type_ref)
5 changes: 2 additions & 3 deletions assets/tests/remove_resource/no_resource_data_errors.lua
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@

local type = world._get_mock_resource_type()

assert_throws(function ()
assert_throws(function()
world.remove_resource(type)
end, "Missing type data ReflectResource for type: Unregistered.TypeId.*")
end, "Missing type data ReflectResource for type: Unregistered Type.*")
2 changes: 1 addition & 1 deletion assets/tests/remove_resource/no_resource_data_errors.rhai
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ let type = world._get_mock_resource_type.call();

assert_throws(||{
world.remove_resource.call(type)
}, "Missing type data ReflectResource for type: Unregistered.TypeId.*");
}, "Missing type data ReflectResource for type: Unregistered Type.*");
2 changes: 1 addition & 1 deletion benches/benchmarks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use bevy::{
},
reflect::Reflect,
};
use bevy_mod_scripting_core::bindings::{
use bevy_mod_scripting_bindings::{
FromScript, IntoScript, Mut, Ref, ReflectReference, ScriptValue, Val,
};
use criterion::{
Expand Down
2 changes: 1 addition & 1 deletion codegen/Cargo.bootstrap.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ version = "0.1.0"
edition = "2024"

[dependencies]
bevy_mod_scripting_core = { path = "{{BMS_CORE_PATH}}" }
bevy_mod_scripting_bindings = { path = "{{BMS_BINDINGS_PATH}}" }
bevy_reflect = { version = "0.16.0", features = [
"smol_str",
"glam",
Expand Down
4 changes: 2 additions & 2 deletions codegen/src/args.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,9 +60,9 @@ pub struct Args {
#[arg(global = true, long)]
pub template_args: Option<String>,

/// The path to the bevy_mod_scripting_core crate, used to bootstrap necessary traits
/// The path to the bevy_mod_scripting_bindings crate, used to bootstrap necessary traits
#[arg(global = true, long, default_value = ".")]
pub bms_core_path: Utf8PathBuf,
pub bms_bindings_path: Utf8PathBuf,

/// Crates to exclude from code generation
#[arg(
Expand Down
Loading
Loading