Compare commits
10 commits
eaffce5c6d
...
56fd44062c
| Author | SHA1 | Date | |
|---|---|---|---|
| 56fd44062c | |||
|
|
297bffd060 | ||
|
|
2c82a2fa0e | ||
|
|
ec84d9e740 | ||
|
|
f9e872e111 | ||
|
|
a718aa7ce6 | ||
|
|
be8a80519d | ||
|
|
f85dbcffe2 | ||
|
|
182f26e273 | ||
|
|
7488de076b |
33 changed files with 513 additions and 167 deletions
8
.github/workflows/rust.yml
vendored
8
.github/workflows/rust.yml
vendored
|
|
@ -11,9 +11,9 @@ env:
|
||||||
|
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
|
env:
|
||||||
|
RUSTFLAGS: -D warnings
|
||||||
steps:
|
steps:
|
||||||
- uses: actions/checkout@v3
|
- uses: actions/checkout@v3
|
||||||
- name: Clippy
|
- name: Clippy
|
||||||
|
|
@ -22,7 +22,3 @@ jobs:
|
||||||
run: cargo build --all-features --verbose
|
run: cargo build --all-features --verbose
|
||||||
- name: Run tests
|
- name: Run tests
|
||||||
run: cargo test --all-features --verbose
|
run: cargo test --all-features --verbose
|
||||||
- name: Install cargo-examples
|
|
||||||
run: cargo install cargo-examples
|
|
||||||
- name: Run all examples
|
|
||||||
run: cargo examples --features=lua,rhai
|
|
||||||
|
|
|
||||||
58
Cargo.toml
58
Cargo.toml
|
|
@ -1,7 +1,7 @@
|
||||||
[package]
|
[package]
|
||||||
name = "bevy_scriptum"
|
name = "bevy_scriptum"
|
||||||
authors = ["Jaroslaw Konik <konikjar@gmail.com>"]
|
authors = ["Jaroslaw Konik <konikjar@gmail.com>"]
|
||||||
version = "0.5.0"
|
version = "0.8.1"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
readme = "README.md"
|
readme = "README.md"
|
||||||
|
|
@ -15,95 +15,141 @@ lua = ["mlua/luajit"]
|
||||||
rhai = ["dep:rhai"]
|
rhai = ["dep:rhai"]
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bevy = { default-features = false, version = "0.13.0", features = [
|
bevy = { default-features = false, version = "0.16", features = ["bevy_asset", "bevy_log"] }
|
||||||
"bevy_asset",
|
|
||||||
] }
|
|
||||||
serde = "1.0.162"
|
serde = "1.0.162"
|
||||||
rhai = { version = "1.14.0", features = ["sync", "internals", "unchecked"], optional = true }
|
rhai = { version = "1.14.0", features = [
|
||||||
|
"sync",
|
||||||
|
"internals",
|
||||||
|
"unchecked",
|
||||||
|
], optional = true }
|
||||||
thiserror = "1.0.40"
|
thiserror = "1.0.40"
|
||||||
anyhow = "1.0.82"
|
anyhow = "1.0.82"
|
||||||
tracing = "0.1.40"
|
tracing = "0.1.40"
|
||||||
mlua = { version = "0.9.8", features = ["luajit", "vendored", "send"], optional = true }
|
mlua = { version = "0.9.8", features = [
|
||||||
|
"luajit",
|
||||||
|
"vendored",
|
||||||
|
"send",
|
||||||
|
], optional = true }
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "call_function_from_rust_rhai"
|
name = "call_function_from_rust_rhai"
|
||||||
path = "examples/rhai/call_function_from_rust.rs"
|
path = "examples/rhai/call_function_from_rust.rs"
|
||||||
|
required-features = ["rhai"]
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "current_entity_rhai"
|
name = "current_entity_rhai"
|
||||||
path = "examples/rhai/current_entity.rs"
|
path = "examples/rhai/current_entity.rs"
|
||||||
|
required-features = ["rhai"]
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "custom_type_rhai"
|
name = "custom_type_rhai"
|
||||||
path = "examples/rhai/custom_type.rs"
|
path = "examples/rhai/custom_type.rs"
|
||||||
|
required-features = ["rhai"]
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "ecs_rhai"
|
name = "ecs_rhai"
|
||||||
path = "examples/rhai/ecs.rs"
|
path = "examples/rhai/ecs.rs"
|
||||||
|
required-features = ["rhai"]
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "entity_variable_rhai"
|
name = "entity_variable_rhai"
|
||||||
path = "examples/rhai/entity_variable.rs"
|
path = "examples/rhai/entity_variable.rs"
|
||||||
|
required-features = ["rhai"]
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "function_params_rhai"
|
name = "function_params_rhai"
|
||||||
path = "examples/rhai/function_params.rs"
|
path = "examples/rhai/function_params.rs"
|
||||||
|
required-features = ["rhai"]
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "hello_world_rhai"
|
name = "hello_world_rhai"
|
||||||
path = "examples/rhai/hello_world.rs"
|
path = "examples/rhai/hello_world.rs"
|
||||||
|
required-features = ["rhai"]
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "multiple_plugins_rhai"
|
||||||
|
path = "examples/rhai/multiple_plugins.rs"
|
||||||
|
required-features = ["rhai"]
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "non_closure_system_rhai"
|
name = "non_closure_system_rhai"
|
||||||
path = "examples/rhai/non_closure_system.rs"
|
path = "examples/rhai/non_closure_system.rs"
|
||||||
|
required-features = ["rhai"]
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "promises_rhai"
|
name = "promises_rhai"
|
||||||
path = "examples/rhai/promises.rs"
|
path = "examples/rhai/promises.rs"
|
||||||
|
required-features = ["rhai"]
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "side_effects_rhai"
|
name = "side_effects_rhai"
|
||||||
path = "examples/rhai/side_effects.rs"
|
path = "examples/rhai/side_effects.rs"
|
||||||
|
required-features = ["rhai"]
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "function_return_value_rhai"
|
||||||
|
path = "examples/rhai/function_return_value.rs"
|
||||||
|
required-features = ["rhai"]
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "call_function_from_rust_lua"
|
name = "call_function_from_rust_lua"
|
||||||
path = "examples/lua/call_function_from_rust.rs"
|
path = "examples/lua/call_function_from_rust.rs"
|
||||||
|
required-features = ["lua"]
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "current_entity_lua"
|
name = "current_entity_lua"
|
||||||
path = "examples/lua/current_entity.rs"
|
path = "examples/lua/current_entity.rs"
|
||||||
|
required-features = ["lua"]
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "custom_type_lua"
|
name = "custom_type_lua"
|
||||||
path = "examples/lua/custom_type.rs"
|
path = "examples/lua/custom_type.rs"
|
||||||
|
required-features = ["lua"]
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "ecs_lua"
|
name = "ecs_lua"
|
||||||
path = "examples/lua/ecs.rs"
|
path = "examples/lua/ecs.rs"
|
||||||
|
required-features = ["lua"]
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "entity_variable_lua"
|
name = "entity_variable_lua"
|
||||||
path = "examples/lua/entity_variable.rs"
|
path = "examples/lua/entity_variable.rs"
|
||||||
|
required-features = ["lua"]
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "function_params_lua"
|
name = "function_params_lua"
|
||||||
path = "examples/lua/function_params.rs"
|
path = "examples/lua/function_params.rs"
|
||||||
|
required-features = ["lua"]
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "hello_world_lua"
|
name = "hello_world_lua"
|
||||||
path = "examples/lua/hello_world.rs"
|
path = "examples/lua/hello_world.rs"
|
||||||
|
required-features = ["lua"]
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "multiple_plugins_lua"
|
||||||
|
path = "examples/lua/multiple_plugins.rs"
|
||||||
|
required-features = ["lua"]
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "non_closure_system_lua"
|
name = "non_closure_system_lua"
|
||||||
path = "examples/lua/non_closure_system.rs"
|
path = "examples/lua/non_closure_system.rs"
|
||||||
|
required-features = ["lua"]
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "promises_lua"
|
name = "promises_lua"
|
||||||
path = "examples/lua/promises.rs"
|
path = "examples/lua/promises.rs"
|
||||||
|
required-features = ["lua"]
|
||||||
|
|
||||||
[[example]]
|
[[example]]
|
||||||
name = "side_effects_lua"
|
name = "side_effects_lua"
|
||||||
path = "examples/lua/side_effects.rs"
|
path = "examples/lua/side_effects.rs"
|
||||||
|
required-features = ["lua"]
|
||||||
|
|
||||||
|
[[example]]
|
||||||
|
name = "function_return_value_lua"
|
||||||
|
path = "examples/lua/function_return_value.rs"
|
||||||
|
required-features = ["lua"]
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
tracing-subscriber = "0.3.18"
|
tracing-subscriber = "0.3.18"
|
||||||
|
|
|
||||||
48
README.md
48
README.md
|
|
@ -1,5 +1,7 @@
|
||||||
# bevy_scriptum 📜
|
# bevy_scriptum 📜
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
bevy_scriptum is a a plugin for [Bevy](https://bevyengine.org/) that allows you to write some of your game logic in a scripting language.
|
bevy_scriptum is a a plugin for [Bevy](https://bevyengine.org/) that allows you to write some of your game logic in a scripting language.
|
||||||
Currently [Rhai](https://rhai.rs/) and [Lua](https://lua.org/) are supported, but more languages may be added in the future.
|
Currently [Rhai](https://rhai.rs/) and [Lua](https://lua.org/) are supported, but more languages may be added in the future.
|
||||||
|
|
||||||
|
|
@ -84,6 +86,33 @@ which you can then call in your script like this:
|
||||||
```lua
|
```lua
|
||||||
fun_with_string_param("Hello world!")
|
fun_with_string_param("Hello world!")
|
||||||
```
|
```
|
||||||
|
It is also possible to split the definition of your callback functions up over multiple plugins. This enables you to split up your code by subject and keep the main initialization light and clean.
|
||||||
|
This can be accomplished by using `add_scripting_api`. Be careful though, `add_scripting` has to be called before adding plugins.
|
||||||
|
```rust
|
||||||
|
use bevy::prelude::*;
|
||||||
|
use bevy_scriptum::prelude::*;
|
||||||
|
use bevy_scriptum::runtimes::lua::prelude::*;
|
||||||
|
|
||||||
|
struct MyPlugin;
|
||||||
|
impl Plugin for MyPlugin {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
app.add_scripting_api::<LuaRuntime>(|runtime| {
|
||||||
|
runtime.add_function(String::from("hello_from_my_plugin"), || {
|
||||||
|
info!("Hello from MyPlugin");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
App::new()
|
||||||
|
.add_plugins(DefaultPlugins)
|
||||||
|
.add_scripting::<LuaRuntime>(|_| {
|
||||||
|
// nice and clean
|
||||||
|
})
|
||||||
|
.add_plugins(MyPlugin)
|
||||||
|
.run();
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
### Usage
|
### Usage
|
||||||
|
|
||||||
|
|
@ -91,7 +120,7 @@ Add the following to your `Cargo.toml`:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bevy_scriptum = { version = "0.5", features = ["lua"] }
|
bevy_scriptum = { version = "0.7", features = ["lua"] }
|
||||||
```
|
```
|
||||||
|
|
||||||
or execute `cargo add bevy_scriptum --features lua` from your project directory.
|
or execute `cargo add bevy_scriptum --features lua` from your project directory.
|
||||||
|
|
@ -147,10 +176,6 @@ App::new()
|
||||||
|
|
||||||
You should then see `my_print: 'Hello world!'` printed in your console.
|
You should then see `my_print: 'Hello world!'` printed in your console.
|
||||||
|
|
||||||
### Demo
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
### Provided examples
|
### Provided examples
|
||||||
|
|
||||||
You can also try running provided examples by cloning this repository and running `cargo run --example <example_name>_<language_name>`. For example:
|
You can also try running provided examples by cloning this repository and running `cargo run --example <example_name>_<language_name>`. For example:
|
||||||
|
|
@ -163,11 +188,14 @@ The examples live in `examples` directory and their corresponding scripts live i
|
||||||
### Bevy compatibility
|
### Bevy compatibility
|
||||||
|
|
||||||
| bevy version | bevy_scriptum version |
|
| bevy version | bevy_scriptum version |
|
||||||
|--------------|----------------------|
|
|--------------|-----------------------|
|
||||||
| 0.13 | 0.4-0.5 |
|
| 0.16 | 0.8 |
|
||||||
| 0.12 | 0.3 |
|
| 0.15 | 0.7 |
|
||||||
| 0.11 | 0.2 |
|
| 0.14 | 0.6 |
|
||||||
| 0.10 | 0.1 |
|
| 0.13 | 0.4-0.5 |
|
||||||
|
| 0.12 | 0.3 |
|
||||||
|
| 0.11 | 0.2 |
|
||||||
|
| 0.10 | 0.1 |
|
||||||
|
|
||||||
### Promises - getting return values from scripts
|
### Promises - getting return values from scripts
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ currently being supported with security updates.
|
||||||
|
|
||||||
| Version | Supported |
|
| Version | Supported |
|
||||||
| ------- | ------------------ |
|
| ------- | ------------------ |
|
||||||
| 0.5 | :white_check_mark: |
|
| 0.8 | :white_check_mark: |
|
||||||
|
|
||||||
## Reporting a Vulnerability
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
|
|
|
||||||
3
assets/examples/lua/function_return_value.lua
Normal file
3
assets/examples/lua/function_return_value.lua
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
function get_value()
|
||||||
|
return 42
|
||||||
|
end
|
||||||
1
assets/examples/lua/multiple_plugins_plugin_a.lua
Normal file
1
assets/examples/lua/multiple_plugins_plugin_a.lua
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
hello_from_plugin_a()
|
||||||
1
assets/examples/lua/multiple_plugins_plugin_b.lua
Normal file
1
assets/examples/lua/multiple_plugins_plugin_b.lua
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
hello_from_plugin_b_with_parameters("hello", 42)
|
||||||
3
assets/examples/rhai/function_return_value.rhai
Normal file
3
assets/examples/rhai/function_return_value.rhai
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
fn get_value() {
|
||||||
|
42
|
||||||
|
}
|
||||||
1
assets/examples/rhai/multiple_plugins_plugin_a.rhai
Normal file
1
assets/examples/rhai/multiple_plugins_plugin_a.rhai
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
hello_from_plugin_a();
|
||||||
1
assets/examples/rhai/multiple_plugins_plugin_b.rhai
Normal file
1
assets/examples/rhai/multiple_plugins_plugin_b.rhai
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
hello_from_plugin_b_with_parameters("hello", 42);
|
||||||
|
|
@ -1,8 +1,11 @@
|
||||||
# Bevy support matrix
|
# Bevy support matrix
|
||||||
|
|
||||||
| bevy version | bevy_scriptum version |
|
| bevy version | bevy_scriptum version |
|
||||||
|--------------|----------------------|
|
| ------------ | --------------------- |
|
||||||
| 0.13 | 0.4-0.5 |
|
| 0.16 | 0.8 |
|
||||||
| 0.12 | 0.3 |
|
| 0.15 | 0.7 |
|
||||||
| 0.11 | 0.2 |
|
| 0.14 | 0.6 |
|
||||||
| 0.10 | 0.1 |
|
| 0.13 | 0.4-0.5 |
|
||||||
|
| 0.12 | 0.3 |
|
||||||
|
| 0.11 | 0.2 |
|
||||||
|
| 0.10 | 0.1 |
|
||||||
|
|
|
||||||
|
|
@ -88,13 +88,43 @@ which you can then call in your script like this:
|
||||||
fun_with_string_param("Hello world!")
|
fun_with_string_param("Hello world!")
|
||||||
```
|
```
|
||||||
|
|
||||||
|
It is also possible to split the definition of your callback functions up over multiple plugins. This enables you to split up your code by subject and keep the main initialization light and clean.
|
||||||
|
This can be accomplished by using `add_scripting_api`. Be careful though, `add_scripting` has to be called before adding plugins.
|
||||||
|
```rust
|
||||||
|
use bevy::prelude::*;
|
||||||
|
use bevy_scriptum::prelude::*;
|
||||||
|
use bevy_scriptum::runtimes::lua::prelude::*;
|
||||||
|
|
||||||
|
struct MyPlugin;
|
||||||
|
impl Plugin for MyPlugin {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
app.add_scripting_api::<LuaRuntime>(|runtime| {
|
||||||
|
runtime.add_function(String::from("hello_from_my_plugin"), || {
|
||||||
|
info!("Hello from MyPlugin");
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main
|
||||||
|
fn main() {
|
||||||
|
App::new()
|
||||||
|
.add_plugins(DefaultPlugins)
|
||||||
|
.add_scripting::<LuaRuntime>(|_| {
|
||||||
|
// nice and clean
|
||||||
|
})
|
||||||
|
.add_plugins(MyPlugin)
|
||||||
|
.run();
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
### Usage
|
### Usage
|
||||||
|
|
||||||
Add the following to your `Cargo.toml`:
|
Add the following to your `Cargo.toml`:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bevy_scriptum = { version = "0.5", features = ["lua"] }
|
bevy_scriptum = { version = "0.8", features = ["lua"] }
|
||||||
```
|
```
|
||||||
|
|
||||||
or execute `cargo add bevy_scriptum --features lua` from your project directory.
|
or execute `cargo add bevy_scriptum --features lua` from your project directory.
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ Add the following to your `Cargo.toml`:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bevy = "0.13"
|
bevy = "0.16"
|
||||||
bevy_scriptum = { version = "0.5", features = ["lua"] }
|
bevy_scriptum = { version = "0.8", features = ["lua"] }
|
||||||
```
|
```
|
||||||
|
|
||||||
If you need a different version of bevy you need to use a matching bevy_scriptum
|
If you need a different version of bevy you need to use a matching bevy_scriptum
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ Add the following to your `Cargo.toml`:
|
||||||
|
|
||||||
```toml
|
```toml
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bevy = "0.13"
|
bevy = "0.16"
|
||||||
bevy_scriptum = { version = "0.5", features = ["rhai"] }
|
bevy_scriptum = { version = "0.8", features = ["rhai"] }
|
||||||
```
|
```
|
||||||
|
|
||||||
If you need a different version of bevy you need to use a matching bevy_scriptum
|
If you need a different version of bevy you need to use a matching bevy_scriptum
|
||||||
|
|
|
||||||
|
|
@ -2,11 +2,11 @@
|
||||||
|
|
||||||
## Bevy included support
|
## Bevy included support
|
||||||
|
|
||||||
To enable life reload it should be enough to enable `file-watcher` feature
|
To enable live reload it should be enough to enable `file-watcher` feature
|
||||||
within bevy dependency in `Cargo.toml`
|
within bevy dependency in `Cargo.toml`
|
||||||
|
|
||||||
```
|
```
|
||||||
bevy = { version = "0.13", features = ["file_watcher"] }
|
bevy = { version = "0.16", features = ["file_watcher"] }
|
||||||
```
|
```
|
||||||
|
|
||||||
## Init-teardown pattern for game development
|
## Init-teardown pattern for game development
|
||||||
|
|
|
||||||
|
|
@ -1,32 +1,15 @@
|
||||||
use bevy::{app::AppExit, ecs::event::ManualEventReader, prelude::*};
|
use bevy::{app::AppExit, prelude::*};
|
||||||
use bevy_scriptum::prelude::*;
|
use bevy_scriptum::prelude::*;
|
||||||
use bevy_scriptum::runtimes::lua::prelude::*;
|
use bevy_scriptum::runtimes::lua::prelude::*;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
App::new()
|
App::new()
|
||||||
// This is just needed for headless console app, not needed for a regular bevy game
|
|
||||||
// that uses a winit window
|
|
||||||
.set_runner(move |mut app: App| {
|
|
||||||
let mut app_exit_event_reader = ManualEventReader::<AppExit>::default();
|
|
||||||
loop {
|
|
||||||
if let Some(app_exit_events) = app.world.get_resource_mut::<Events<AppExit>>() {
|
|
||||||
if app_exit_event_reader
|
|
||||||
.read(&app_exit_events)
|
|
||||||
.last()
|
|
||||||
.is_some()
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
app.update();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.add_plugins(DefaultPlugins)
|
.add_plugins(DefaultPlugins)
|
||||||
.add_systems(Startup, startup)
|
.add_systems(Startup, startup)
|
||||||
.add_systems(Update, call_lua_on_update_from_rust)
|
.add_systems(Update, call_lua_on_update_from_rust)
|
||||||
.add_scripting::<LuaRuntime>(|runtime| {
|
.add_scripting::<LuaRuntime>(|runtime| {
|
||||||
runtime.add_function(String::from("quit"), |mut exit: EventWriter<AppExit>| {
|
runtime.add_function(String::from("quit"), |mut exit: EventWriter<AppExit>| {
|
||||||
exit.send(AppExit);
|
exit.write(AppExit::Success);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.run();
|
.run();
|
||||||
|
|
|
||||||
42
examples/lua/function_return_value.rs
Normal file
42
examples/lua/function_return_value.rs
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
use bevy::{app::AppExit, prelude::*};
|
||||||
|
use bevy_scriptum::prelude::*;
|
||||||
|
use bevy_scriptum::runtimes::lua::prelude::*;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
App::new()
|
||||||
|
.add_plugins(DefaultPlugins)
|
||||||
|
.add_systems(Startup, startup)
|
||||||
|
.add_systems(Update, call_lua_on_update_from_rust)
|
||||||
|
.add_scripting::<LuaRuntime>(|runtime| {
|
||||||
|
runtime.add_function(String::from("quit"), |mut exit: EventWriter<AppExit>| {
|
||||||
|
exit.write(AppExit::Success);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn startup(mut commands: Commands, assets_server: Res<AssetServer>) {
|
||||||
|
commands.spawn(Script::<LuaScript>::new(
|
||||||
|
assets_server.load("examples/lua/function_return_value.lua"),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call_lua_on_update_from_rust(
|
||||||
|
mut scripted_entities: Query<(Entity, &mut LuaScriptData)>,
|
||||||
|
scripting_runtime: ResMut<LuaRuntime>,
|
||||||
|
mut exit: EventWriter<AppExit>,
|
||||||
|
) {
|
||||||
|
for (entity, mut script_data) in &mut scripted_entities {
|
||||||
|
let val = scripting_runtime
|
||||||
|
.call_fn("get_value", &mut script_data, entity, ())
|
||||||
|
.unwrap()
|
||||||
|
.0;
|
||||||
|
scripting_runtime.with_engine(|engine| {
|
||||||
|
println!(
|
||||||
|
"script returned: {}",
|
||||||
|
engine.registry_value::<mlua::Integer>(&val).unwrap()
|
||||||
|
);
|
||||||
|
});
|
||||||
|
exit.write(AppExit::Success);
|
||||||
|
}
|
||||||
|
}
|
||||||
67
examples/lua/multiple_plugins.rs
Normal file
67
examples/lua/multiple_plugins.rs
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
use bevy::prelude::*;
|
||||||
|
use bevy_scriptum::prelude::*;
|
||||||
|
use bevy_scriptum::runtimes::lua::prelude::*;
|
||||||
|
|
||||||
|
// Plugin A
|
||||||
|
struct PluginA;
|
||||||
|
impl Plugin for PluginA {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
app.add_scripting_api::<LuaRuntime>(|runtime| {
|
||||||
|
runtime.add_function(String::from("hello_from_plugin_a"), || {
|
||||||
|
info!("Hello from Plugin A");
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.add_systems(Startup, plugin_a_startup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn plugin_a_startup(mut commands: Commands, assets_server: Res<AssetServer>) {
|
||||||
|
commands.spawn(Script::<LuaScript>::new(
|
||||||
|
assets_server.load("examples/lua/multiple_plugins_plugin_a.lua"),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Plugin B
|
||||||
|
struct PluginB;
|
||||||
|
impl Plugin for PluginB {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
app.add_scripting_api::<LuaRuntime>(|runtime| {
|
||||||
|
runtime.add_function(
|
||||||
|
String::from("hello_from_plugin_b_with_parameters"),
|
||||||
|
hello_from_b,
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.add_systems(Startup, plugin_b_startup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn plugin_b_startup(mut commands: Commands, assets_server: Res<AssetServer>) {
|
||||||
|
commands.spawn(Script::<LuaScript>::new(
|
||||||
|
assets_server.load("examples/lua/multiple_plugins_plugin_b.lua"),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hello_from_b(In((text, x)): In<(String, i32)>) {
|
||||||
|
info!("{} from Plugin B: {}", text, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main
|
||||||
|
fn main() {
|
||||||
|
App::new()
|
||||||
|
.add_plugins(DefaultPlugins)
|
||||||
|
.add_scripting::<LuaRuntime>(|runtime| {
|
||||||
|
runtime.add_function(String::from("hello_bevy"), || {
|
||||||
|
info!("hello bevy, called from script");
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.add_systems(Startup, main_startup)
|
||||||
|
.add_plugins(PluginA)
|
||||||
|
.add_plugins(PluginB)
|
||||||
|
.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main_startup(mut commands: Commands, assets_server: Res<AssetServer>) {
|
||||||
|
commands.spawn(Script::<LuaScript>::new(
|
||||||
|
assets_server.load("examples/lua/hello_world.lua"),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
@ -11,7 +11,7 @@ fn main() {
|
||||||
.add_scripting::<LuaRuntime>(|builder| {
|
.add_scripting::<LuaRuntime>(|builder| {
|
||||||
builder.add_function(
|
builder.add_function(
|
||||||
String::from("get_player_name"),
|
String::from("get_player_name"),
|
||||||
|player_names: Query<&Name, With<Player>>| player_names.single().to_string(),
|
|player_names: Query<&Name, With<Player>>| player_names.single().expect("Missing player_names").to_string(),
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.add_systems(Startup, startup)
|
.add_systems(Startup, startup)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use bevy::{app::AppExit, ecs::event::ManualEventReader, prelude::*};
|
use bevy::{app::AppExit, prelude::*};
|
||||||
use bevy_scriptum::prelude::*;
|
use bevy_scriptum::prelude::*;
|
||||||
use bevy_scriptum::runtimes::lua::prelude::*;
|
use bevy_scriptum::runtimes::lua::prelude::*;
|
||||||
|
|
||||||
|
|
@ -7,18 +7,11 @@ fn main() {
|
||||||
// This is just needed for headless console app, not needed for a regular bevy game
|
// This is just needed for headless console app, not needed for a regular bevy game
|
||||||
// that uses a winit window
|
// that uses a winit window
|
||||||
.set_runner(move |mut app: App| {
|
.set_runner(move |mut app: App| {
|
||||||
let mut app_exit_event_reader = ManualEventReader::<AppExit>::default();
|
|
||||||
loop {
|
loop {
|
||||||
if let Some(app_exit_events) = app.world.get_resource_mut::<Events<AppExit>>() {
|
|
||||||
if app_exit_event_reader
|
|
||||||
.read(&app_exit_events)
|
|
||||||
.last()
|
|
||||||
.is_some()
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
app.update();
|
app.update();
|
||||||
|
if let Some(exit) = app.should_exit() {
|
||||||
|
return exit;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.add_plugins(DefaultPlugins)
|
.add_plugins(DefaultPlugins)
|
||||||
|
|
@ -45,6 +38,6 @@ fn print_entity_names_and_quit(query: Query<&Name>, mut exit: EventWriter<AppExi
|
||||||
for e in &query {
|
for e in &query {
|
||||||
println!("{}", e);
|
println!("{}", e);
|
||||||
}
|
}
|
||||||
exit.send(AppExit);
|
exit.write(AppExit::Success);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,32 +1,15 @@
|
||||||
use bevy::{app::AppExit, ecs::event::ManualEventReader, prelude::*};
|
use bevy::{app::AppExit, prelude::*};
|
||||||
use bevy_scriptum::prelude::*;
|
use bevy_scriptum::prelude::*;
|
||||||
use bevy_scriptum::runtimes::rhai::prelude::*;
|
use bevy_scriptum::runtimes::rhai::prelude::*;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
App::new()
|
App::new()
|
||||||
// This is just needed for headless console app, not needed for a regular bevy game
|
|
||||||
// that uses a winit window
|
|
||||||
.set_runner(move |mut app: App| {
|
|
||||||
let mut app_exit_event_reader = ManualEventReader::<AppExit>::default();
|
|
||||||
loop {
|
|
||||||
if let Some(app_exit_events) = app.world.get_resource_mut::<Events<AppExit>>() {
|
|
||||||
if app_exit_event_reader
|
|
||||||
.read(&app_exit_events)
|
|
||||||
.last()
|
|
||||||
.is_some()
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
app.update();
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.add_plugins(DefaultPlugins)
|
.add_plugins(DefaultPlugins)
|
||||||
.add_systems(Startup, startup)
|
.add_systems(Startup, startup)
|
||||||
.add_systems(Update, call_rhai_on_update_from_rust)
|
.add_systems(Update, call_rhai_on_update_from_rust)
|
||||||
.add_scripting::<RhaiRuntime>(|runtime| {
|
.add_scripting::<RhaiRuntime>(|runtime| {
|
||||||
runtime.add_function(String::from("quit"), |mut exit: EventWriter<AppExit>| {
|
runtime.add_function(String::from("quit"), |mut exit: EventWriter<AppExit>| {
|
||||||
exit.send(AppExit);
|
exit.write(AppExit::Success);
|
||||||
});
|
});
|
||||||
})
|
})
|
||||||
.run();
|
.run();
|
||||||
|
|
|
||||||
37
examples/rhai/function_return_value.rs
Normal file
37
examples/rhai/function_return_value.rs
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
use bevy::{app::AppExit, prelude::*};
|
||||||
|
use bevy_scriptum::prelude::*;
|
||||||
|
use bevy_scriptum::runtimes::rhai::prelude::*;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
App::new()
|
||||||
|
.add_plugins(DefaultPlugins)
|
||||||
|
.add_systems(Startup, startup)
|
||||||
|
.add_systems(Update, call_rhai_on_update_from_rust)
|
||||||
|
.add_scripting::<RhaiRuntime>(|runtime| {
|
||||||
|
runtime.add_function(String::from("quit"), |mut exit: EventWriter<AppExit>| {
|
||||||
|
exit.write(AppExit::Success);
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn startup(mut commands: Commands, assets_server: Res<AssetServer>) {
|
||||||
|
commands.spawn(Script::<RhaiScript>::new(
|
||||||
|
assets_server.load("examples/rhai/function_return_value.rhai"),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn call_rhai_on_update_from_rust(
|
||||||
|
mut scripted_entities: Query<(Entity, &mut RhaiScriptData)>,
|
||||||
|
scripting_runtime: ResMut<RhaiRuntime>,
|
||||||
|
mut exit: EventWriter<AppExit>,
|
||||||
|
) {
|
||||||
|
for (entity, mut script_data) in &mut scripted_entities {
|
||||||
|
let val = scripting_runtime
|
||||||
|
.call_fn("get_value", &mut script_data, entity, ())
|
||||||
|
.unwrap()
|
||||||
|
.0;
|
||||||
|
println!("script returned: {}", val);
|
||||||
|
exit.write(AppExit::Success);
|
||||||
|
}
|
||||||
|
}
|
||||||
68
examples/rhai/multiple_plugins.rs
Normal file
68
examples/rhai/multiple_plugins.rs
Normal file
|
|
@ -0,0 +1,68 @@
|
||||||
|
use bevy::prelude::*;
|
||||||
|
use bevy_scriptum::prelude::*;
|
||||||
|
use bevy_scriptum::runtimes::rhai::prelude::*;
|
||||||
|
use rhai::ImmutableString;
|
||||||
|
|
||||||
|
// Plugin A
|
||||||
|
struct PluginA;
|
||||||
|
impl Plugin for PluginA {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
app.add_scripting_api::<RhaiRuntime>(|runtime| {
|
||||||
|
runtime.add_function(String::from("hello_from_plugin_a"), || {
|
||||||
|
info!("Hello from Plugin A");
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.add_systems(Startup, plugin_a_startup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn plugin_a_startup(mut commands: Commands, assets_server: Res<AssetServer>) {
|
||||||
|
commands.spawn(Script::<RhaiScript>::new(
|
||||||
|
assets_server.load("examples/rhai/multiple_plugins_plugin_a.rhai"),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Plugin B
|
||||||
|
struct PluginB;
|
||||||
|
impl Plugin for PluginB {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
app.add_scripting_api::<RhaiRuntime>(|runtime| {
|
||||||
|
runtime.add_function(
|
||||||
|
String::from("hello_from_plugin_b_with_parameters"),
|
||||||
|
hello_from_b,
|
||||||
|
);
|
||||||
|
})
|
||||||
|
.add_systems(Startup, plugin_b_startup);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn plugin_b_startup(mut commands: Commands, assets_server: Res<AssetServer>) {
|
||||||
|
commands.spawn(Script::<RhaiScript>::new(
|
||||||
|
assets_server.load("examples/rhai/multiple_plugins_plugin_b.rhai"),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn hello_from_b(In((text, x)): In<(ImmutableString, i64)>) {
|
||||||
|
info!("{} from Plugin B: {}", text, x);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Main
|
||||||
|
fn main() {
|
||||||
|
App::new()
|
||||||
|
.add_plugins(DefaultPlugins)
|
||||||
|
.add_scripting::<RhaiRuntime>(|runtime| {
|
||||||
|
runtime.add_function(String::from("hello_bevy"), || {
|
||||||
|
info!("hello bevy, called from script");
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.add_systems(Startup, main_startup)
|
||||||
|
.add_plugins(PluginA)
|
||||||
|
.add_plugins(PluginB)
|
||||||
|
.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main_startup(mut commands: Commands, assets_server: Res<AssetServer>) {
|
||||||
|
commands.spawn(Script::<RhaiScript>::new(
|
||||||
|
assets_server.load("examples/rhai/hello_world.rhai"),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
@ -11,7 +11,7 @@ fn main() {
|
||||||
.add_scripting::<RhaiRuntime>(|builder| {
|
.add_scripting::<RhaiRuntime>(|builder| {
|
||||||
builder.add_function(
|
builder.add_function(
|
||||||
String::from("get_player_name"),
|
String::from("get_player_name"),
|
||||||
|player_names: Query<&Name, With<Player>>| player_names.single().to_string(),
|
|player_names: Query<&Name, With<Player>>| player_names.single().expect("Missing player_names").to_string(),
|
||||||
);
|
);
|
||||||
})
|
})
|
||||||
.add_systems(Startup, startup)
|
.add_systems(Startup, startup)
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use bevy::{app::AppExit, ecs::event::ManualEventReader, prelude::*};
|
use bevy::{app::AppExit, prelude::*};
|
||||||
use bevy_scriptum::prelude::*;
|
use bevy_scriptum::prelude::*;
|
||||||
use bevy_scriptum::runtimes::rhai::prelude::*;
|
use bevy_scriptum::runtimes::rhai::prelude::*;
|
||||||
|
|
||||||
|
|
@ -6,19 +6,10 @@ fn main() {
|
||||||
App::new()
|
App::new()
|
||||||
// This is just needed for headless console app, not needed for a regular bevy game
|
// This is just needed for headless console app, not needed for a regular bevy game
|
||||||
// that uses a winit window
|
// that uses a winit window
|
||||||
.set_runner(move |mut app: App| {
|
.set_runner(move |mut app: App| loop {
|
||||||
let mut app_exit_event_reader = ManualEventReader::<AppExit>::default();
|
app.update();
|
||||||
loop {
|
if let Some(exit) = app.should_exit() {
|
||||||
if let Some(app_exit_events) = app.world.get_resource_mut::<Events<AppExit>>() {
|
return exit;
|
||||||
if app_exit_event_reader
|
|
||||||
.read(&app_exit_events)
|
|
||||||
.last()
|
|
||||||
.is_some()
|
|
||||||
{
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
app.update();
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
.add_plugins(DefaultPlugins)
|
.add_plugins(DefaultPlugins)
|
||||||
|
|
@ -45,6 +36,6 @@ fn print_entity_names_and_quit(query: Query<&Name>, mut exit: EventWriter<AppExi
|
||||||
for e in &query {
|
for e in &query {
|
||||||
println!("{}", e);
|
println!("{}", e);
|
||||||
}
|
}
|
||||||
exit.send(AppExit);
|
exit.write(AppExit::Success);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
|
|
||||||
use bevy::{
|
use bevy::{
|
||||||
asset::{io::Reader, Asset, AssetLoader, AsyncReadExt as _, LoadContext},
|
asset::{io::Reader, Asset, AssetLoader, LoadContext},
|
||||||
utils::BoxedFuture,
|
tasks::ConditionalSendFuture,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// A loader for script assets.
|
/// A loader for script assets.
|
||||||
|
|
@ -29,12 +29,12 @@ impl<A: Asset + From<String> + GetExtensions> AssetLoader for ScriptLoader<A> {
|
||||||
type Settings = ();
|
type Settings = ();
|
||||||
type Error = anyhow::Error;
|
type Error = anyhow::Error;
|
||||||
|
|
||||||
fn load<'a>(
|
fn load(
|
||||||
&'a self,
|
&self,
|
||||||
reader: &'a mut Reader,
|
reader: &mut dyn Reader,
|
||||||
_settings: &'a Self::Settings,
|
_settings: &Self::Settings,
|
||||||
_load_context: &'a mut LoadContext,
|
_load_context: &mut LoadContext,
|
||||||
) -> BoxedFuture<'a, anyhow::Result<A, anyhow::Error>> {
|
) -> impl ConditionalSendFuture<Output = Result<Self::Asset, Self::Error>> {
|
||||||
Box::pin(async move {
|
Box::pin(async move {
|
||||||
let mut bytes = Vec::new();
|
let mut bytes = Vec::new();
|
||||||
reader.read_to_end(&mut bytes).await?;
|
reader.read_to_end(&mut bytes).await?;
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ use crate::{promise::Promise, Runtime};
|
||||||
|
|
||||||
/// A system that can be used to call a script function.
|
/// A system that can be used to call a script function.
|
||||||
pub struct CallbackSystem<R: Runtime> {
|
pub struct CallbackSystem<R: Runtime> {
|
||||||
pub(crate) system: Box<dyn System<In = Vec<R::Value>, Out = R::Value>>,
|
pub(crate) system: Box<dyn System<In = In<Vec<R::Value>>, Out = R::Value>>,
|
||||||
pub(crate) arg_types: Vec<TypeId>,
|
pub(crate) arg_types: Vec<TypeId>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -56,7 +56,10 @@ pub(crate) trait FromRuntimeValueWithEngine<'a, R: Runtime> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Trait that alllows to convert a script callback function into a Bevy [`System`].
|
/// Trait that alllows to convert a script callback function into a Bevy [`System`].
|
||||||
pub trait IntoCallbackSystem<R: Runtime, In, Out, Marker>: IntoSystem<In, Out, Marker> {
|
pub trait IntoCallbackSystem<R: Runtime, In, Out, Marker>: IntoSystem<In, Out, Marker>
|
||||||
|
where
|
||||||
|
In: SystemInput,
|
||||||
|
{
|
||||||
/// Convert this function into a [CallbackSystem].
|
/// Convert this function into a [CallbackSystem].
|
||||||
#[must_use]
|
#[must_use]
|
||||||
fn into_callback_system(self, world: &mut World) -> CallbackSystem<R>;
|
fn into_callback_system(self, world: &mut World) -> CallbackSystem<R>;
|
||||||
|
|
@ -87,10 +90,10 @@ where
|
||||||
|
|
||||||
macro_rules! impl_tuple {
|
macro_rules! impl_tuple {
|
||||||
($($idx:tt $t:tt),+) => {
|
($($idx:tt $t:tt),+) => {
|
||||||
impl<RN: Runtime, $($t,)+ Out, FN, Marker> IntoCallbackSystem<RN, ($($t,)+), Out, Marker>
|
impl<RN: Runtime, $($t,)+ Out, FN, Marker> IntoCallbackSystem<RN, In<($($t,)+)>, Out, Marker>
|
||||||
for FN
|
for FN
|
||||||
where
|
where
|
||||||
FN: IntoSystem<($($t,)+), Out, Marker>,
|
FN: IntoSystem<In<($($t,)+)>, Out, Marker>,
|
||||||
Out: for<'a> IntoRuntimeValueWithEngine<'a, Out, RN>,
|
Out: for<'a> IntoRuntimeValueWithEngine<'a, Out, RN>,
|
||||||
$($t: 'static + for<'a> FromRuntimeValueWithEngine<'a, RN>,)+
|
$($t: 'static + for<'a> FromRuntimeValueWithEngine<'a, RN>,)+
|
||||||
{
|
{
|
||||||
|
|
|
||||||
93
src/lib.rs
93
src/lib.rs
|
|
@ -1,3 +1,5 @@
|
||||||
|
//! 
|
||||||
|
//!
|
||||||
//! bevy_scriptum is a a plugin for [Bevy](https://bevyengine.org/) that allows you to write some of your game logic in a scripting language.
|
//! bevy_scriptum is a a plugin for [Bevy](https://bevyengine.org/) that allows you to write some of your game logic in a scripting language.
|
||||||
//! Currently [Rhai](https://rhai.rs/) and [Lua](https://lua.org/) are supported, but more languages may be added in the future.
|
//! Currently [Rhai](https://rhai.rs/) and [Lua](https://lua.org/) are supported, but more languages may be added in the future.
|
||||||
//!
|
//!
|
||||||
|
|
@ -16,7 +18,7 @@
|
||||||
//! Scripts are separate files that can be hot-reloaded at runtime. This allows you to quickly iterate on your game logic without having to recompile your game.
|
//! Scripts are separate files that can be hot-reloaded at runtime. This allows you to quickly iterate on your game logic without having to recompile your game.
|
||||||
//!
|
//!
|
||||||
//! All you need to do is register callbacks on your Bevy app like this:
|
//! All you need to do is register callbacks on your Bevy app like this:
|
||||||
//! ```rust
|
//! ```no_run
|
||||||
//! use bevy::prelude::*;
|
//! use bevy::prelude::*;
|
||||||
//! use bevy_scriptum::prelude::*;
|
//! use bevy_scriptum::prelude::*;
|
||||||
//! use bevy_scriptum::runtimes::lua::prelude::*;
|
//! use bevy_scriptum::runtimes::lua::prelude::*;
|
||||||
|
|
@ -37,7 +39,7 @@
|
||||||
//!
|
//!
|
||||||
//! Every callback function that you expose to the scripting language is also a Bevy system, so you can easily query and mutate ECS components and resources just like you would in a regular Bevy system:
|
//! Every callback function that you expose to the scripting language is also a Bevy system, so you can easily query and mutate ECS components and resources just like you would in a regular Bevy system:
|
||||||
//!
|
//!
|
||||||
//! ```rust
|
//! ```no_run
|
||||||
//! use bevy::prelude::*;
|
//! use bevy::prelude::*;
|
||||||
//! use bevy_scriptum::prelude::*;
|
//! use bevy_scriptum::prelude::*;
|
||||||
//! use bevy_scriptum::runtimes::lua::prelude::*;
|
//! use bevy_scriptum::runtimes::lua::prelude::*;
|
||||||
|
|
@ -61,7 +63,7 @@
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! You can also pass arguments to your callback functions, just like you would in a regular Bevy system - using `In` structs with tuples:
|
//! You can also pass arguments to your callback functions, just like you would in a regular Bevy system - using `In` structs with tuples:
|
||||||
//! ```rust
|
//! ```no_run
|
||||||
//! use bevy::prelude::*;
|
//! use bevy::prelude::*;
|
||||||
//! use bevy_scriptum::prelude::*;
|
//! use bevy_scriptum::prelude::*;
|
||||||
//! use bevy_scriptum::runtimes::lua::prelude::*;
|
//! use bevy_scriptum::runtimes::lua::prelude::*;
|
||||||
|
|
@ -82,6 +84,33 @@
|
||||||
//! ```lua
|
//! ```lua
|
||||||
//! fun_with_string_param("Hello world!")
|
//! fun_with_string_param("Hello world!")
|
||||||
//! ```
|
//! ```
|
||||||
|
//! It is also possible to split the definition of your callback functions up over multiple plugins. This enables you to split up your code by subject and keep the main initialization light and clean.
|
||||||
|
//! This can be accomplished by using `add_scripting_api`. Be careful though, `add_scripting` has to be called before adding plugins.
|
||||||
|
//! ```no_run
|
||||||
|
//! use bevy::prelude::*;
|
||||||
|
//! use bevy_scriptum::prelude::*;
|
||||||
|
//! use bevy_scriptum::runtimes::lua::prelude::*;
|
||||||
|
//!
|
||||||
|
//! struct MyPlugin;
|
||||||
|
//! impl Plugin for MyPlugin {
|
||||||
|
//! fn build(&self, app: &mut App) {
|
||||||
|
//! app.add_scripting_api::<LuaRuntime>(|runtime| {
|
||||||
|
//! runtime.add_function(String::from("hello_from_my_plugin"), || {
|
||||||
|
//! info!("Hello from MyPlugin");
|
||||||
|
//! });
|
||||||
|
//! });
|
||||||
|
//! }
|
||||||
|
//! }
|
||||||
|
//!
|
||||||
|
//! App::new()
|
||||||
|
//! .add_plugins(DefaultPlugins)
|
||||||
|
//! .add_scripting::<LuaRuntime>(|_| {
|
||||||
|
//! // nice and clean
|
||||||
|
//! })
|
||||||
|
//! .add_plugins(MyPlugin)
|
||||||
|
//! .run();
|
||||||
|
//! ```
|
||||||
|
//!
|
||||||
//!
|
//!
|
||||||
//! ## Usage
|
//! ## Usage
|
||||||
//!
|
//!
|
||||||
|
|
@ -89,14 +118,14 @@
|
||||||
//!
|
//!
|
||||||
//! ```toml
|
//! ```toml
|
||||||
//! [dependencies]
|
//! [dependencies]
|
||||||
//! bevy_scriptum = { version = "0.5", features = ["lua"] }
|
//! bevy_scriptum = { version = "0.8", features = ["lua"] }
|
||||||
//! ```
|
//! ```
|
||||||
//!
|
//!
|
||||||
//! or execute `cargo add bevy_scriptum --features lua` from your project directory.
|
//! or execute `cargo add bevy_scriptum --features lua` from your project directory.
|
||||||
//!
|
//!
|
||||||
//! You can now start exposing functions to the scripting language. For example, you can expose a function that prints a message to the console:
|
//! You can now start exposing functions to the scripting language. For example, you can expose a function that prints a message to the console:
|
||||||
//!
|
//!
|
||||||
//! ```rust
|
//! ```no_run
|
||||||
//! use bevy::prelude::*;
|
//! use bevy::prelude::*;
|
||||||
//! use bevy_scriptum::prelude::*;
|
//! use bevy_scriptum::prelude::*;
|
||||||
//! use bevy_scriptum::runtimes::lua::prelude::*;
|
//! use bevy_scriptum::runtimes::lua::prelude::*;
|
||||||
|
|
@ -122,7 +151,7 @@
|
||||||
//!
|
//!
|
||||||
//! And spawn an entity with attached `Script` component with a handle to a script source file:
|
//! And spawn an entity with attached `Script` component with a handle to a script source file:
|
||||||
//!
|
//!
|
||||||
//! ```rust
|
//! ```no_run
|
||||||
//! use bevy::prelude::*;
|
//! use bevy::prelude::*;
|
||||||
//! use bevy_scriptum::prelude::*;
|
//! use bevy_scriptum::prelude::*;
|
||||||
//! use bevy_scriptum::runtimes::lua::prelude::*;
|
//! use bevy_scriptum::runtimes::lua::prelude::*;
|
||||||
|
|
@ -145,10 +174,6 @@
|
||||||
//!
|
//!
|
||||||
//! You should then see `my_print: 'Hello world!'` printed in your console.
|
//! You should then see `my_print: 'Hello world!'` printed in your console.
|
||||||
//!
|
//!
|
||||||
//! ## Demo
|
|
||||||
//!
|
|
||||||
//! 
|
|
||||||
//!
|
|
||||||
//! ## Provided examples
|
//! ## Provided examples
|
||||||
//!
|
//!
|
||||||
//! You can also try running provided examples by cloning this repository and running `cargo run --example <example_name>_<language_name>`. For example:
|
//! You can also try running provided examples by cloning this repository and running `cargo run --example <example_name>_<language_name>`. For example:
|
||||||
|
|
@ -161,11 +186,14 @@
|
||||||
//! ## Bevy compatibility
|
//! ## Bevy compatibility
|
||||||
//!
|
//!
|
||||||
//! | bevy version | bevy_scriptum version |
|
//! | bevy version | bevy_scriptum version |
|
||||||
//! |--------------|----------------------|
|
//! |--------------|-----------------------|
|
||||||
//! | 0.13 | 0.4-0.5 |
|
//! | 0.16 | 0.8 |
|
||||||
//! | 0.12 | 0.3 |
|
//! | 0.15 | 0.7 |
|
||||||
//! | 0.11 | 0.2 |
|
//! | 0.14 | 0.6 |
|
||||||
//! | 0.10 | 0.1 |
|
//! | 0.13 | 0.4-0.5 |
|
||||||
|
//! | 0.12 | 0.3 |
|
||||||
|
//! | 0.11 | 0.2 |
|
||||||
|
//! | 0.10 | 0.1 |
|
||||||
//!
|
//!
|
||||||
//! ## Promises - getting return values from scripts
|
//! ## Promises - getting return values from scripts
|
||||||
//!
|
//!
|
||||||
|
|
@ -231,7 +259,7 @@ use std::{
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
};
|
};
|
||||||
|
|
||||||
use bevy::{app::MainScheduleOrder, ecs::schedule::ScheduleLabel, prelude::*};
|
use bevy::{app::MainScheduleOrder, ecs::{component::Mutable, schedule::ScheduleLabel}, prelude::*};
|
||||||
use callback::{Callback, IntoCallbackSystem};
|
use callback::{Callback, IntoCallbackSystem};
|
||||||
use systems::{init_callbacks, log_errors, process_calls};
|
use systems::{init_callbacks, log_errors, process_calls};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
@ -241,6 +269,7 @@ use self::{
|
||||||
systems::{process_new_scripts, reload_scripts},
|
systems::{process_new_scripts, reload_scripts},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#[cfg(any(feature = "rhai", feature = "lua"))]
|
||||||
const ENTITY_VAR_NAME: &str = "entity";
|
const ENTITY_VAR_NAME: &str = "entity";
|
||||||
|
|
||||||
/// An error that can occur when internal [ScriptingPlugin] systems are being executed
|
/// An error that can occur when internal [ScriptingPlugin] systems are being executed
|
||||||
|
|
@ -262,7 +291,7 @@ pub enum ScriptingError {
|
||||||
pub trait Runtime: Resource + Default {
|
pub trait Runtime: Resource + Default {
|
||||||
type Schedule: ScheduleLabel + Debug + Clone + Eq + Hash + Default;
|
type Schedule: ScheduleLabel + Debug + Clone + Eq + Hash + Default;
|
||||||
type ScriptAsset: Asset + From<String> + GetExtensions;
|
type ScriptAsset: Asset + From<String> + GetExtensions;
|
||||||
type ScriptData: Component;
|
type ScriptData: Component<Mutability = Mutable>;
|
||||||
type CallContext: Send + Clone;
|
type CallContext: Send + Clone;
|
||||||
type Value: Send + Clone;
|
type Value: Send + Clone;
|
||||||
type RawEngine;
|
type RawEngine;
|
||||||
|
|
@ -330,6 +359,12 @@ pub trait BuildScriptingRuntime {
|
||||||
/// Returns a "runtime" type than can be used to setup scripting runtime(
|
/// Returns a "runtime" type than can be used to setup scripting runtime(
|
||||||
/// add scripting functions etc.).
|
/// add scripting functions etc.).
|
||||||
fn add_scripting<R: Runtime>(&mut self, f: impl Fn(ScriptingRuntimeBuilder<R>)) -> &mut Self;
|
fn add_scripting<R: Runtime>(&mut self, f: impl Fn(ScriptingRuntimeBuilder<R>)) -> &mut Self;
|
||||||
|
|
||||||
|
/// Returns a "runtime" type that can be used to add additional scripting functions from plugins etc.
|
||||||
|
fn add_scripting_api<R: Runtime>(
|
||||||
|
&mut self,
|
||||||
|
f: impl Fn(ScriptingRuntimeBuilder<R>),
|
||||||
|
) -> &mut Self;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct ScriptingRuntimeBuilder<'a, R: Runtime> {
|
pub struct ScriptingRuntimeBuilder<'a, R: Runtime> {
|
||||||
|
|
@ -353,7 +388,10 @@ impl<'a, R: Runtime> ScriptingRuntimeBuilder<'a, R> {
|
||||||
self,
|
self,
|
||||||
name: String,
|
name: String,
|
||||||
fun: impl IntoCallbackSystem<R, In, Out, Marker>,
|
fun: impl IntoCallbackSystem<R, In, Out, Marker>,
|
||||||
) -> Self {
|
) -> Self
|
||||||
|
where
|
||||||
|
In: SystemInput,
|
||||||
|
{
|
||||||
let system = fun.into_callback_system(self.world);
|
let system = fun.into_callback_system(self.world);
|
||||||
|
|
||||||
let mut callbacks_resource = self.world.resource_mut::<Callbacks<R>>();
|
let mut callbacks_resource = self.world.resource_mut::<Callbacks<R>>();
|
||||||
|
|
@ -372,7 +410,7 @@ impl BuildScriptingRuntime for App {
|
||||||
/// Adds a scripting runtime. Registers required bevy systems that take
|
/// Adds a scripting runtime. Registers required bevy systems that take
|
||||||
/// care of processing and running the scripts.
|
/// care of processing and running the scripts.
|
||||||
fn add_scripting<R: Runtime>(&mut self, f: impl Fn(ScriptingRuntimeBuilder<R>)) -> &mut Self {
|
fn add_scripting<R: Runtime>(&mut self, f: impl Fn(ScriptingRuntimeBuilder<R>)) -> &mut Self {
|
||||||
self.world
|
self.world_mut()
|
||||||
.resource_mut::<MainScheduleOrder>()
|
.resource_mut::<MainScheduleOrder>()
|
||||||
.insert_after(Update, R::Schedule::default());
|
.insert_after(Update, R::Schedule::default());
|
||||||
|
|
||||||
|
|
@ -395,7 +433,22 @@ impl BuildScriptingRuntime for App {
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
let runtime = ScriptingRuntimeBuilder::<R>::new(&mut self.world);
|
let runtime = ScriptingRuntimeBuilder::<R>::new(self.world_mut());
|
||||||
|
|
||||||
|
f(runtime);
|
||||||
|
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds a way to add additional accesspoints to the scripting runtime. For example from plugins to add
|
||||||
|
/// for example additional lua functions to the runtime.
|
||||||
|
///
|
||||||
|
/// Be careful with calling this though, make sure that the `add_scripting` call is already called before calling this function.
|
||||||
|
fn add_scripting_api<R: Runtime>(
|
||||||
|
&mut self,
|
||||||
|
f: impl Fn(ScriptingRuntimeBuilder<R>),
|
||||||
|
) -> &mut Self {
|
||||||
|
let runtime = ScriptingRuntimeBuilder::<R>::new(self.world_mut());
|
||||||
|
|
||||||
f(runtime);
|
f(runtime);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -58,6 +58,7 @@ impl<C: Clone + Send + 'static, V: Send + Clone> Promise<C, V> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Register a callback that will be called when the [Promise] is resolved.
|
/// Register a callback that will be called when the [Promise] is resolved.
|
||||||
|
#[cfg(any(feature = "rhai", feature = "lua"))]
|
||||||
pub(crate) fn then(&mut self, callback: V) -> Self {
|
pub(crate) fn then(&mut self, callback: V) -> Self {
|
||||||
let mut inner = self
|
let mut inner = self
|
||||||
.inner
|
.inner
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
use bevy::{
|
use bevy::{
|
||||||
asset::Asset,
|
asset::Asset,
|
||||||
ecs::{component::Component, entity::Entity, schedule::ScheduleLabel, system::Resource},
|
ecs::{component::Component, entity::Entity, resource::Resource, schedule::ScheduleLabel},
|
||||||
math::Vec3,
|
math::Vec3,
|
||||||
reflect::TypePath,
|
reflect::TypePath,
|
||||||
};
|
};
|
||||||
|
|
@ -21,7 +21,7 @@ use crate::{
|
||||||
type LuaEngine = Arc<Mutex<Lua>>;
|
type LuaEngine = Arc<Mutex<Lua>>;
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct LuaValue(Arc<RegistryKey>);
|
pub struct LuaValue(pub Arc<RegistryKey>);
|
||||||
|
|
||||||
impl LuaValue {
|
impl LuaValue {
|
||||||
fn new<'a, T: IntoLua<'a>>(engine: &'a Lua, value: T) -> Self {
|
fn new<'a, T: IntoLua<'a>>(engine: &'a Lua, value: T) -> Self {
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ use std::fmt::Debug;
|
||||||
|
|
||||||
use bevy::{
|
use bevy::{
|
||||||
asset::Asset,
|
asset::Asset,
|
||||||
ecs::{component::Component, entity::Entity, schedule::ScheduleLabel, system::Resource},
|
ecs::{component::Component, entity::Entity, resource::Resource, schedule::ScheduleLabel},
|
||||||
math::Vec3,
|
math::Vec3,
|
||||||
reflect::TypePath,
|
reflect::TypePath,
|
||||||
};
|
};
|
||||||
|
|
@ -48,7 +48,7 @@ pub struct RhaiScriptData {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct RhaiValue(rhai::Dynamic);
|
pub struct RhaiValue(pub rhai::Dynamic);
|
||||||
|
|
||||||
impl Runtime for RhaiRuntime {
|
impl Runtime for RhaiRuntime {
|
||||||
type Schedule = RhaiSchedule;
|
type Schedule = RhaiSchedule;
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,4 @@
|
||||||
use bevy::{prelude::*, utils::tracing};
|
use bevy::{prelude::*, log::tracing};
|
||||||
use std::{
|
use std::{
|
||||||
fmt::Display,
|
fmt::Display,
|
||||||
sync::{Arc, Mutex},
|
sync::{Arc, Mutex},
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,17 @@
|
||||||
|
#[cfg(any(feature = "rhai", feature = "lua"))]
|
||||||
use std::sync::OnceLock;
|
use std::sync::OnceLock;
|
||||||
|
|
||||||
|
#[cfg(any(feature = "rhai", feature = "lua"))]
|
||||||
use bevy::ecs::system::RunSystemOnce as _;
|
use bevy::ecs::system::RunSystemOnce as _;
|
||||||
|
#[cfg(any(feature = "rhai", feature = "lua"))]
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
|
#[cfg(any(feature = "rhai", feature = "lua"))]
|
||||||
use bevy_scriptum::{prelude::*, FuncArgs, Runtime};
|
use bevy_scriptum::{prelude::*, FuncArgs, Runtime};
|
||||||
use mlua::Table;
|
|
||||||
|
|
||||||
|
#[cfg(any(feature = "rhai", feature = "lua"))]
|
||||||
static TRACING_SUBSCRIBER: OnceLock<()> = OnceLock::new();
|
static TRACING_SUBSCRIBER: OnceLock<()> = OnceLock::new();
|
||||||
|
|
||||||
|
#[cfg(any(feature = "rhai", feature = "lua"))]
|
||||||
fn build_test_app() -> App {
|
fn build_test_app() -> App {
|
||||||
let mut app = App::new();
|
let mut app = App::new();
|
||||||
|
|
||||||
|
|
@ -20,34 +25,37 @@ fn build_test_app() -> App {
|
||||||
app
|
app
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "rhai", feature = "lua"))]
|
||||||
fn run_script<R: Runtime, Out, Marker>(
|
fn run_script<R: Runtime, Out, Marker>(
|
||||||
app: &mut App,
|
app: &mut App,
|
||||||
path: String,
|
path: String,
|
||||||
system: impl IntoSystem<(), Out, Marker>,
|
system: impl IntoSystem<(), Out, Marker>,
|
||||||
) -> Entity {
|
) -> Entity {
|
||||||
let asset_server = app.world.get_resource_mut::<AssetServer>().unwrap();
|
let asset_server = app.world_mut().get_resource_mut::<AssetServer>().unwrap();
|
||||||
let asset = asset_server.load::<R::ScriptAsset>(path);
|
let asset = asset_server.load::<R::ScriptAsset>(path);
|
||||||
|
|
||||||
let entity_id = app.world.spawn(Script::new(asset)).id();
|
let entity_id = app.world_mut().spawn(Script::new(asset)).id();
|
||||||
app.update(); // let `ScriptData` resources be added to entities
|
app.update(); // let `ScriptData` resources be added to entities
|
||||||
app.world.run_system_once(system);
|
app.world_mut().run_system_once(system).unwrap();
|
||||||
app.update(); // let callbacks be executed
|
app.update(); // let callbacks be executed
|
||||||
|
|
||||||
entity_id
|
entity_id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "rhai", feature = "lua"))]
|
||||||
fn call_script_on_update_from_rust<R: Runtime>(
|
fn call_script_on_update_from_rust<R: Runtime>(
|
||||||
mut scripted_entities: Query<(Entity, &mut R::ScriptData)>,
|
mut scripted_entities: Query<(Entity, &mut R::ScriptData)>,
|
||||||
scripting_runtime: ResMut<R>,
|
scripting_runtime: ResMut<R>,
|
||||||
) where
|
) where
|
||||||
(): for<'a> FuncArgs<'a, R::Value, R>,
|
(): for<'a> FuncArgs<'a, R::Value, R>,
|
||||||
{
|
{
|
||||||
let (entity, mut script_data) = scripted_entities.single_mut();
|
let (entity, mut script_data) = scripted_entities.single_mut().unwrap();
|
||||||
scripting_runtime
|
scripting_runtime
|
||||||
.call_fn("test_func", &mut script_data, entity, ())
|
.call_fn("test_func", &mut script_data, entity, ())
|
||||||
.unwrap();
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "rhai", feature = "lua"))]
|
||||||
trait AssertStateKeyValue {
|
trait AssertStateKeyValue {
|
||||||
type ScriptData;
|
type ScriptData;
|
||||||
fn assert_state_key_value_i64(world: &World, entity_id: Entity, key: &str, value: i64);
|
fn assert_state_key_value_i64(world: &World, entity_id: Entity, key: &str, value: i64);
|
||||||
|
|
@ -55,6 +63,7 @@ trait AssertStateKeyValue {
|
||||||
fn assert_state_key_value_string(world: &World, entity_id: Entity, key: &str, value: &str);
|
fn assert_state_key_value_string(world: &World, entity_id: Entity, key: &str, value: &str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(feature = "rhai", feature = "lua"))]
|
||||||
macro_rules! scripting_tests {
|
macro_rules! scripting_tests {
|
||||||
($runtime:ty, $script:literal, $extension:literal) => {
|
($runtime:ty, $script:literal, $extension:literal) => {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
@ -74,7 +83,7 @@ macro_rules! scripting_tests {
|
||||||
.to_string(),
|
.to_string(),
|
||||||
|mut scripted_entities: Query<(Entity, &mut <$runtime as Runtime>::ScriptData)>,
|
|mut scripted_entities: Query<(Entity, &mut <$runtime as Runtime>::ScriptData)>,
|
||||||
scripting_runtime: ResMut<$runtime>| {
|
scripting_runtime: ResMut<$runtime>| {
|
||||||
let (entity, mut script_data) = scripted_entities.single_mut();
|
let (entity, mut script_data) = scripted_entities.single_mut().unwrap();
|
||||||
scripting_runtime
|
scripting_runtime
|
||||||
.call_fn("test_func", &mut script_data, entity, vec![1])
|
.call_fn("test_func", &mut script_data, entity, vec![1])
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
@ -91,7 +100,7 @@ macro_rules! scripting_tests {
|
||||||
my_int: i64,
|
my_int: i64,
|
||||||
}
|
}
|
||||||
|
|
||||||
app.world.init_resource::<IntResource>();
|
app.world_mut().init_resource::<IntResource>();
|
||||||
|
|
||||||
app.add_scripting::<$runtime>(|runtime| {
|
app.add_scripting::<$runtime>(|runtime| {
|
||||||
runtime.add_function(
|
runtime.add_function(
|
||||||
|
|
@ -112,7 +121,7 @@ macro_rules! scripting_tests {
|
||||||
call_script_on_update_from_rust::<$runtime>,
|
call_script_on_update_from_rust::<$runtime>,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(app.world.get_resource::<IntResource>().unwrap().my_int, 5);
|
assert_eq!(app.world().get_resource::<IntResource>().unwrap().my_int, 5);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -125,7 +134,7 @@ macro_rules! scripting_tests {
|
||||||
b: String,
|
b: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
app.world.init_resource::<TestResource>();
|
app.world_mut().init_resource::<TestResource>();
|
||||||
|
|
||||||
app.add_scripting::<$runtime>(|runtime| {
|
app.add_scripting::<$runtime>(|runtime| {
|
||||||
runtime.add_function(
|
runtime.add_function(
|
||||||
|
|
@ -147,9 +156,9 @@ macro_rules! scripting_tests {
|
||||||
call_script_on_update_from_rust::<$runtime>,
|
call_script_on_update_from_rust::<$runtime>,
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(app.world.get_resource::<TestResource>().unwrap().a, 5);
|
assert_eq!(app.world().get_resource::<TestResource>().unwrap().a, 5);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.world.get_resource::<TestResource>().unwrap().b,
|
app.world().get_resource::<TestResource>().unwrap().b,
|
||||||
String::from("test")
|
String::from("test")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
@ -169,14 +178,14 @@ macro_rules! scripting_tests {
|
||||||
.to_string(),
|
.to_string(),
|
||||||
|mut scripted_entities: Query<(Entity, &mut <$runtime as Runtime>::ScriptData)>,
|
|mut scripted_entities: Query<(Entity, &mut <$runtime as Runtime>::ScriptData)>,
|
||||||
scripting_runtime: ResMut<$runtime>| {
|
scripting_runtime: ResMut<$runtime>| {
|
||||||
let (entity, mut script_data) = scripted_entities.single_mut();
|
let (entity, mut script_data) = scripted_entities.single_mut().unwrap();
|
||||||
scripting_runtime
|
scripting_runtime
|
||||||
.call_fn("test_func", &mut script_data, entity, vec![1])
|
.call_fn("test_func", &mut script_data, entity, vec![1])
|
||||||
.unwrap();
|
.unwrap();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
<$runtime>::assert_state_key_value_i32(&app.world, entity_id, "a_value", 1i32);
|
<$runtime>::assert_state_key_value_i32(&app.world(), entity_id, "a_value", 1i32);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -194,7 +203,7 @@ macro_rules! scripting_tests {
|
||||||
.to_string(),
|
.to_string(),
|
||||||
|mut scripted_entities: Query<(Entity, &mut <$runtime as Runtime>::ScriptData)>,
|
|mut scripted_entities: Query<(Entity, &mut <$runtime as Runtime>::ScriptData)>,
|
||||||
scripting_runtime: ResMut<$runtime>| {
|
scripting_runtime: ResMut<$runtime>| {
|
||||||
let (entity, mut script_data) = scripted_entities.single_mut();
|
let (entity, mut script_data) = scripted_entities.single_mut().unwrap();
|
||||||
scripting_runtime
|
scripting_runtime
|
||||||
.call_fn(
|
.call_fn(
|
||||||
"test_func",
|
"test_func",
|
||||||
|
|
@ -206,9 +215,9 @@ macro_rules! scripting_tests {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
<$runtime>::assert_state_key_value_i32(&app.world, entity_id, "a_value", 1i32);
|
<$runtime>::assert_state_key_value_i32(&app.world(), entity_id, "a_value", 1i32);
|
||||||
<$runtime>::assert_state_key_value_string(
|
<$runtime>::assert_state_key_value_string(
|
||||||
&app.world,
|
&app.world(),
|
||||||
entity_id,
|
entity_id,
|
||||||
"b_value",
|
"b_value",
|
||||||
&String::from("abc"),
|
&String::from("abc"),
|
||||||
|
|
@ -230,15 +239,15 @@ macro_rules! scripting_tests {
|
||||||
.to_string(),
|
.to_string(),
|
||||||
|mut scripted_entities: Query<(Entity, &mut <$runtime as Runtime>::ScriptData)>,
|
|mut scripted_entities: Query<(Entity, &mut <$runtime as Runtime>::ScriptData)>,
|
||||||
scripting_runtime: ResMut<$runtime>| {
|
scripting_runtime: ResMut<$runtime>| {
|
||||||
let (entity, mut script_data) = scripted_entities.single_mut();
|
let (entity, mut script_data) = scripted_entities.single_mut().unwrap();
|
||||||
scripting_runtime
|
scripting_runtime
|
||||||
.call_fn("test_func", &mut script_data, entity, vec![1, 2])
|
.call_fn("test_func", &mut script_data, entity, vec![1, 2])
|
||||||
.unwrap();
|
.unwrap();
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
<$runtime>::assert_state_key_value_i32(&app.world, entity_id, "a_value", 1i32);
|
<$runtime>::assert_state_key_value_i32(&app.world(), entity_id, "a_value", 1i32);
|
||||||
<$runtime>::assert_state_key_value_i32(&app.world, entity_id, "b_value", 2i32);
|
<$runtime>::assert_state_key_value_i32(&app.world(), entity_id, "b_value", 2i32);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -256,7 +265,7 @@ macro_rules! scripting_tests {
|
||||||
.to_string(),
|
.to_string(),
|
||||||
|mut scripted_entities: Query<(Entity, &mut <$runtime as Runtime>::ScriptData)>,
|
|mut scripted_entities: Query<(Entity, &mut <$runtime as Runtime>::ScriptData)>,
|
||||||
scripting_runtime: ResMut<$runtime>| {
|
scripting_runtime: ResMut<$runtime>| {
|
||||||
let (entity, mut script_data) = scripted_entities.single_mut();
|
let (entity, mut script_data) = scripted_entities.single_mut().unwrap();
|
||||||
let result =
|
let result =
|
||||||
scripting_runtime.call_fn("test_func", &mut script_data, entity, ());
|
scripting_runtime.call_fn("test_func", &mut script_data, entity, ());
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
|
|
@ -279,7 +288,7 @@ macro_rules! scripting_tests {
|
||||||
.to_string(),
|
.to_string(),
|
||||||
|mut scripted_entities: Query<(Entity, &mut <$runtime as Runtime>::ScriptData)>,
|
|mut scripted_entities: Query<(Entity, &mut <$runtime as Runtime>::ScriptData)>,
|
||||||
scripting_runtime: ResMut<$runtime>| {
|
scripting_runtime: ResMut<$runtime>| {
|
||||||
let (entity, mut script_data) = scripted_entities.single_mut();
|
let (entity, mut script_data) = scripted_entities.single_mut().unwrap();
|
||||||
let result =
|
let result =
|
||||||
scripting_runtime.call_fn("does_not_exist", &mut script_data, entity, ());
|
scripting_runtime.call_fn("does_not_exist", &mut script_data, entity, ());
|
||||||
assert!(result.is_err());
|
assert!(result.is_err());
|
||||||
|
|
@ -303,7 +312,7 @@ macro_rules! scripting_tests {
|
||||||
call_script_on_update_from_rust::<$runtime>,
|
call_script_on_update_from_rust::<$runtime>,
|
||||||
);
|
);
|
||||||
|
|
||||||
<$runtime>::assert_state_key_value_i64(&app.world, entity_id, "times_called", 1i64);
|
<$runtime>::assert_state_key_value_i64(&app.world(), entity_id, "times_called", 1i64);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -320,7 +329,7 @@ macro_rules! scripting_tests {
|
||||||
call_script_on_update_from_rust::<$runtime>,
|
call_script_on_update_from_rust::<$runtime>,
|
||||||
);
|
);
|
||||||
|
|
||||||
<$runtime>::assert_state_key_value_i32(&app.world, entity_id, "x", 123i32);
|
<$runtime>::assert_state_key_value_i32(&app.world(), entity_id, "x", 123i32);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -357,9 +366,11 @@ macro_rules! scripting_tests {
|
||||||
call_script_on_update_from_rust::<$runtime>,
|
call_script_on_update_from_rust::<$runtime>,
|
||||||
);
|
);
|
||||||
|
|
||||||
app.world.run_system_once(|tagged: Query<&MyTag>| {
|
app.world_mut()
|
||||||
tagged.single();
|
.run_system_once(|tagged: Query<&MyTag>| {
|
||||||
});
|
tagged.single().unwrap();
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -371,7 +382,7 @@ macro_rules! scripting_tests {
|
||||||
times_called: u8,
|
times_called: u8,
|
||||||
}
|
}
|
||||||
|
|
||||||
app.world.init_resource::<TimesCalled>();
|
app.world_mut().init_resource::<TimesCalled>();
|
||||||
|
|
||||||
app.add_scripting::<$runtime>(|runtime| {
|
app.add_scripting::<$runtime>(|runtime| {
|
||||||
runtime.add_function(String::from("rust_func"), |mut res: ResMut<TimesCalled>| {
|
runtime.add_function(String::from("rust_func"), |mut res: ResMut<TimesCalled>| {
|
||||||
|
|
@ -390,7 +401,7 @@ macro_rules! scripting_tests {
|
||||||
);
|
);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
app.world
|
app.world()
|
||||||
.get_resource::<TimesCalled>()
|
.get_resource::<TimesCalled>()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.times_called,
|
.times_called,
|
||||||
|
|
@ -434,6 +445,7 @@ mod rhai_tests {
|
||||||
mod lua_tests {
|
mod lua_tests {
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
use bevy_scriptum::runtimes::lua::prelude::*;
|
use bevy_scriptum::runtimes::lua::prelude::*;
|
||||||
|
use mlua::Table;
|
||||||
|
|
||||||
impl AssertStateKeyValue for LuaRuntime {
|
impl AssertStateKeyValue for LuaRuntime {
|
||||||
type ScriptData = LuaScriptData;
|
type ScriptData = LuaScriptData;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue