Compare commits
18 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fa70abac23 | ||
| 41d0fd57f3 | |||
|
|
e430795dce | ||
|
|
c6bdfb1400 | ||
|
|
450962b1d0 | ||
|
|
53479f94b5 | ||
|
|
f2bb079c60 | ||
| 56fd44062c | |||
|
|
297bffd060 | ||
|
|
2c82a2fa0e | ||
|
|
ec84d9e740 | ||
|
|
f9e872e111 | ||
|
|
a718aa7ce6 | ||
|
|
be8a80519d | ||
|
|
f85dbcffe2 | ||
|
|
182f26e273 | ||
|
|
7488de076b | ||
|
|
eaffce5c6d |
113 changed files with 5577 additions and 380 deletions
54
.github/workflows/book.yml
vendored
Normal file
54
.github/workflows/book.yml
vendored
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
name: Book
|
||||
|
||||
on:
|
||||
push:
|
||||
branches: ["main"]
|
||||
pull_request:
|
||||
branches: ["main"]
|
||||
|
||||
jobs:
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v4
|
||||
with:
|
||||
fetch-depth: 0
|
||||
- name: Cache Ruby
|
||||
id: cache-ruby
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: rubies
|
||||
key: ${{ runner.os }}-ruby
|
||||
- name: Install Ruby
|
||||
if: steps.cache-ruby.outputs.cache-hit != 'true'
|
||||
env:
|
||||
CC: clang
|
||||
run: |
|
||||
url="https://cache.ruby-lang.org/pub/ruby/3.4/ruby-3.4.4.tar.gz"
|
||||
prefix=`pwd`/rubies/ruby-3.4
|
||||
mkdir rubies
|
||||
mkdir ruby_src
|
||||
curl -sSL $url | tar -xz
|
||||
cd ruby-3.4.4
|
||||
mkdir build
|
||||
cd build
|
||||
../configure --without-shared --prefix=$prefix
|
||||
make install
|
||||
echo $prefix/bin >> $GITHUB_PATH
|
||||
- name: Add Ruby to PATH
|
||||
run: |
|
||||
prefix=`pwd`/rubies/ruby-3.4
|
||||
echo $prefix/bin >> $GITHUB_PATH
|
||||
- name: Install latest mdbook
|
||||
run: |
|
||||
tag=$(curl 'https://api.github.com/repos/rust-lang/mdbook/releases/latest' | jq -r '.tag_name')
|
||||
url="https://github.com/rust-lang/mdbook/releases/download/${tag}/mdbook-${tag}-x86_64-unknown-linux-gnu.tar.gz"
|
||||
mkdir mdbook
|
||||
curl -sSL $url | tar -xz --directory=./mdbook
|
||||
echo `pwd`/mdbook >> $GITHUB_PATH
|
||||
- name: Test Book
|
||||
run: |
|
||||
cd book
|
||||
export CARGO_MANIFEST_DIR=$(pwd)
|
||||
cargo build
|
||||
mdbook test -L target/debug/deps/
|
||||
51
.github/workflows/rust.yml
vendored
51
.github/workflows/rust.yml
vendored
|
|
@ -2,27 +2,48 @@ name: Rust
|
|||
|
||||
on:
|
||||
push:
|
||||
branches: [ "main" ]
|
||||
branches: ["main"]
|
||||
pull_request:
|
||||
branches: [ "main" ]
|
||||
branches: ["main"]
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
env:
|
||||
RUSTFLAGS: -D warnings
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- name: Clippy
|
||||
run: cargo clippy --all-features --verbose -- -D warnings
|
||||
- name: Build
|
||||
run: cargo build --all-features --verbose
|
||||
- name: Run tests
|
||||
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
|
||||
- uses: actions/checkout@v3
|
||||
- name: Cache Ruby
|
||||
id: cache-ruby
|
||||
uses: actions/cache@v4
|
||||
with:
|
||||
path: rubies
|
||||
key: ${{ runner.os }}-ruby
|
||||
- name: Install Ruby
|
||||
if: steps.cache-ruby.outputs.cache-hit != 'true'
|
||||
env:
|
||||
CC: clang
|
||||
run: |
|
||||
url="https://cache.ruby-lang.org/pub/ruby/3.4/ruby-3.4.4.tar.gz"
|
||||
prefix=`pwd`/rubies/ruby-3.4
|
||||
mkdir rubies
|
||||
mkdir ruby_src
|
||||
curl -sSL $url | tar -xz
|
||||
cd ruby-3.4.4
|
||||
mkdir build
|
||||
cd build
|
||||
../configure --without-shared --prefix=$prefix
|
||||
make install
|
||||
- name: Add Ruby to PATH
|
||||
run: |
|
||||
prefix=`pwd`/rubies/ruby-3.4
|
||||
echo $prefix/bin >> $GITHUB_PATH
|
||||
- name: Clippy
|
||||
run: cargo clippy --all-features --verbose -- -D warnings
|
||||
- name: Build
|
||||
run: cargo build --all-features --verbose
|
||||
- name: Run tests
|
||||
run: cargo test --all-features --verbose
|
||||
|
|
|
|||
2
.gitignore
vendored
2
.gitignore
vendored
|
|
@ -1,4 +1,4 @@
|
|||
/target
|
||||
/Cargo.lock
|
||||
.vscode
|
||||
rust-analyzer.json
|
||||
.nvim.lua
|
||||
|
|
|
|||
126
Cargo.toml
126
Cargo.toml
|
|
@ -1,109 +1,215 @@
|
|||
[package]
|
||||
name = "bevy_scriptum"
|
||||
authors = ["Jaroslaw Konik <konikjar@gmail.com>"]
|
||||
version = "0.5.0"
|
||||
edition = "2021"
|
||||
version = "0.9.1"
|
||||
edition = "2024"
|
||||
license = "MIT OR Apache-2.0"
|
||||
readme = "README.md"
|
||||
categories = ["game-development"]
|
||||
description = "Plugin for Bevy engine that allows you to write some of your game logic in a scripting language"
|
||||
description = "Plugin for Bevy engine that allows you to write some of your game or application logic in a scripting language"
|
||||
repository = "https://github.com/jarkonik/bevy_scriptum"
|
||||
keywords = ["bevy", "rhai", "scripting", "game", "gamedev"]
|
||||
keywords = ["bevy", "lua", "scripting", "game", "script"]
|
||||
|
||||
[features]
|
||||
lua = ["mlua/luajit"]
|
||||
lua = ["dep:mlua", "mlua/luajit"]
|
||||
rhai = ["dep:rhai"]
|
||||
ruby = ["dep:magnus", "dep:rb-sys"]
|
||||
|
||||
[dependencies]
|
||||
bevy = { default-features = false, version = "0.13.0", features = [
|
||||
"bevy_asset",
|
||||
] }
|
||||
bevy = { default-features = false, version = "0.16", features = ["bevy_asset", "bevy_log"] }
|
||||
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"
|
||||
anyhow = "1.0.82"
|
||||
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 }
|
||||
magnus = { version = "0.7.1", optional = true }
|
||||
rb-sys = { version = "0.9", default-features = false, features = ["link-ruby", "ruby-static"], optional = true }
|
||||
crossbeam-channel = "0.5.15"
|
||||
libc = "0.2.172"
|
||||
|
||||
[[example]]
|
||||
name = "call_function_from_rust_rhai"
|
||||
path = "examples/rhai/call_function_from_rust.rs"
|
||||
required-features = ["rhai"]
|
||||
|
||||
[[example]]
|
||||
name = "current_entity_rhai"
|
||||
path = "examples/rhai/current_entity.rs"
|
||||
required-features = ["rhai"]
|
||||
|
||||
[[example]]
|
||||
name = "custom_type_rhai"
|
||||
path = "examples/rhai/custom_type.rs"
|
||||
required-features = ["rhai"]
|
||||
|
||||
[[example]]
|
||||
name = "ecs_rhai"
|
||||
path = "examples/rhai/ecs.rs"
|
||||
required-features = ["rhai"]
|
||||
|
||||
[[example]]
|
||||
name = "entity_variable_rhai"
|
||||
path = "examples/rhai/entity_variable.rs"
|
||||
required-features = ["rhai"]
|
||||
|
||||
[[example]]
|
||||
name = "function_params_rhai"
|
||||
path = "examples/rhai/function_params.rs"
|
||||
required-features = ["rhai"]
|
||||
|
||||
[[example]]
|
||||
name = "hello_world_rhai"
|
||||
path = "examples/rhai/hello_world.rs"
|
||||
required-features = ["rhai"]
|
||||
|
||||
[[example]]
|
||||
name = "multiple_plugins_rhai"
|
||||
path = "examples/rhai/multiple_plugins.rs"
|
||||
required-features = ["rhai"]
|
||||
|
||||
[[example]]
|
||||
name = "non_closure_system_rhai"
|
||||
path = "examples/rhai/non_closure_system.rs"
|
||||
required-features = ["rhai"]
|
||||
|
||||
[[example]]
|
||||
name = "promises_rhai"
|
||||
path = "examples/rhai/promises.rs"
|
||||
required-features = ["rhai"]
|
||||
|
||||
[[example]]
|
||||
name = "side_effects_rhai"
|
||||
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]]
|
||||
name = "call_function_from_rust_lua"
|
||||
path = "examples/lua/call_function_from_rust.rs"
|
||||
required-features = ["lua"]
|
||||
|
||||
[[example]]
|
||||
name = "current_entity_lua"
|
||||
path = "examples/lua/current_entity.rs"
|
||||
required-features = ["lua"]
|
||||
|
||||
[[example]]
|
||||
name = "custom_type_lua"
|
||||
path = "examples/lua/custom_type.rs"
|
||||
required-features = ["lua"]
|
||||
|
||||
[[example]]
|
||||
name = "ecs_lua"
|
||||
path = "examples/lua/ecs.rs"
|
||||
required-features = ["lua"]
|
||||
|
||||
[[example]]
|
||||
name = "entity_variable_lua"
|
||||
path = "examples/lua/entity_variable.rs"
|
||||
required-features = ["lua"]
|
||||
|
||||
[[example]]
|
||||
name = "function_params_lua"
|
||||
path = "examples/lua/function_params.rs"
|
||||
required-features = ["lua"]
|
||||
|
||||
[[example]]
|
||||
name = "hello_world_lua"
|
||||
path = "examples/lua/hello_world.rs"
|
||||
required-features = ["lua"]
|
||||
|
||||
[[example]]
|
||||
name = "multiple_plugins_lua"
|
||||
path = "examples/lua/multiple_plugins.rs"
|
||||
required-features = ["lua"]
|
||||
|
||||
[[example]]
|
||||
name = "non_closure_system_lua"
|
||||
path = "examples/lua/non_closure_system.rs"
|
||||
required-features = ["lua"]
|
||||
|
||||
[[example]]
|
||||
name = "promises_lua"
|
||||
path = "examples/lua/promises.rs"
|
||||
required-features = ["lua"]
|
||||
|
||||
[[example]]
|
||||
name = "side_effects_lua"
|
||||
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"]
|
||||
|
||||
[[example]]
|
||||
name = "call_function_from_rust_ruby"
|
||||
path = "examples/ruby/call_function_from_rust.rs"
|
||||
required-features = ["ruby"]
|
||||
|
||||
[[example]]
|
||||
name = "current_entity_ruby"
|
||||
path = "examples/ruby/current_entity.rs"
|
||||
required-features = ["ruby"]
|
||||
|
||||
[[example]]
|
||||
name = "custom_type_ruby"
|
||||
path = "examples/ruby/custom_type.rs"
|
||||
required-features = ["ruby"]
|
||||
|
||||
[[example]]
|
||||
name = "ecs_ruby"
|
||||
path = "examples/ruby/ecs.rs"
|
||||
required-features = ["ruby"]
|
||||
|
||||
[[example]]
|
||||
name = "entity_variable_ruby"
|
||||
path = "examples/ruby/entity_variable.rs"
|
||||
required-features = ["ruby"]
|
||||
|
||||
[[example]]
|
||||
name = "function_params_ruby"
|
||||
path = "examples/ruby/function_params.rs"
|
||||
required-features = ["ruby"]
|
||||
|
||||
[[example]]
|
||||
name = "function_return_value_ruby"
|
||||
path = "examples/ruby/function_return_value.rs"
|
||||
required-features = ["ruby"]
|
||||
|
||||
[[example]]
|
||||
name = "hello_world_ruby"
|
||||
path = "examples/ruby/hello_world.rs"
|
||||
required-features = ["ruby"]
|
||||
|
||||
[[example]]
|
||||
name = "multiple_plugins_ruby"
|
||||
path = "examples/ruby/multiple_plugins.rs"
|
||||
required-features = ["ruby"]
|
||||
|
||||
[[example]]
|
||||
name = "promises_ruby"
|
||||
path = "examples/ruby/promises.rs"
|
||||
required-features = ["ruby"]
|
||||
|
||||
[[example]]
|
||||
name = "side_effects_ruby"
|
||||
path = "examples/ruby/side_effects.rs"
|
||||
required-features = ["ruby"]
|
||||
|
||||
[dev-dependencies]
|
||||
tracing-subscriber = "0.3.18"
|
||||
|
|
|
|||
34
README.md
34
README.md
|
|
@ -1,12 +1,19 @@
|
|||
# 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.
|
||||
Currently [Rhai](https://rhai.rs/) and [Lua](https://lua.org/) are supported, but more languages may be added in the future.
|
||||

|
||||
|
||||
Everything you need to know to get started with using this library is contained in the
|
||||
[bevy_scriptum book](https://jarkonik.github.io/bevy_scriptum/)
|
||||
bevy_scriptum is a a plugin for [Bevy](https://bevyengine.org/) that allows you to write some of your game or application logic in a scripting language.
|
||||
### Supported scripting languages/runtimes
|
||||
|
||||
API docs are available in [docs.rs](https://docs.rs/bevy_scriptum/latest/bevy_scriptum/)
|
||||
| language/runtime | cargo feature | documentation chapter |
|
||||
| ------------------------------------------ | ------------- | --------------------------------------------------------------- |
|
||||
| 🌙 LuaJIT | `lua` | [link](https://jarkonik.github.io/bevy_scriptum/lua/lua.html) |
|
||||
| 🌾 Rhai | `rhai` | [link](https://jarkonik.github.io/bevy_scriptum/rhai/rhai.html) |
|
||||
| 💎 Ruby(currently only supported on Linux) | `ruby` | [link](https://jarkonik.github.io/bevy_scriptum/ruby/ruby.html) |
|
||||
|
||||
Documentation book is available [here](https://jarkonik.github.io/bevy_scriptum/) 📖
|
||||
|
||||
Full API docs are available at [docs.rs](https://docs.rs/bevy_scriptum/latest/bevy_scriptum/) 🧑💻
|
||||
|
||||
bevy_scriptum's main advantages include:
|
||||
- low-boilerplate
|
||||
|
|
@ -15,7 +22,7 @@ bevy_scriptum's main advantages include:
|
|||
- flexibility
|
||||
- hot-reloading
|
||||
|
||||
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 or application logic without having to recompile it.
|
||||
|
||||
All you need to do is register callbacks on your Bevy app like this:
|
||||
```rust
|
||||
|
|
@ -91,7 +98,7 @@ Add the following to your `Cargo.toml`:
|
|||
|
||||
```toml
|
||||
[dependencies]
|
||||
bevy_scriptum = { version = "0.5", features = ["lua"] }
|
||||
bevy_scriptum = { version = "0.9", features = ["lua"] }
|
||||
```
|
||||
|
||||
or execute `cargo add bevy_scriptum --features lua` from your project directory.
|
||||
|
|
@ -159,11 +166,14 @@ The examples live in `examples` directory and their corresponding scripts live i
|
|||
### Bevy compatibility
|
||||
|
||||
| bevy version | bevy_scriptum version |
|
||||
|--------------|----------------------|
|
||||
| 0.13 | 0.4-0.5 |
|
||||
| 0.12 | 0.3 |
|
||||
| 0.11 | 0.2 |
|
||||
| 0.10 | 0.1 |
|
||||
|--------------|-----------------------|
|
||||
| 0.16 | 0.8-0.9 |
|
||||
| 0.15 | 0.7 |
|
||||
| 0.14 | 0.6 |
|
||||
| 0.13 | 0.4-0.5 |
|
||||
| 0.12 | 0.3 |
|
||||
| 0.11 | 0.2 |
|
||||
| 0.10 | 0.1 |
|
||||
|
||||
### Promises - getting return values from scripts
|
||||
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@ currently being supported with security updates.
|
|||
|
||||
| Version | Supported |
|
||||
| ------- | ------------------ |
|
||||
| 0.5 | :white_check_mark: |
|
||||
| 0.9 | :white_check_mark: |
|
||||
|
||||
## 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);
|
||||
13
assets/examples/ruby/call_function_from_rust.rb
Normal file
13
assets/examples/ruby/call_function_from_rust.rb
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
$my_state = {
|
||||
iterations: 0,
|
||||
}
|
||||
|
||||
def on_update
|
||||
$my_state[:iterations] += 1
|
||||
puts("on_update called #{$my_state[:iterations]} times")
|
||||
|
||||
if $my_state[:iterations] >= 10
|
||||
print("calling quit");
|
||||
quit()
|
||||
end
|
||||
end
|
||||
3
assets/examples/ruby/current_entity.rb
Normal file
3
assets/examples/ruby/current_entity.rb
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
get_name(Bevy::Entity.current).and_then do |name|
|
||||
puts(name)
|
||||
end
|
||||
4
assets/examples/ruby/custom_type.rb
Normal file
4
assets/examples/ruby/custom_type.rb
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
# Create a new instance of MyType
|
||||
my_type = MyType.new()
|
||||
# Call registered method
|
||||
puts(my_type.my_method)
|
||||
1
assets/examples/ruby/ecs.rb
Normal file
1
assets/examples/ruby/ecs.rb
Normal file
|
|
@ -0,0 +1 @@
|
|||
print_player_names
|
||||
2
assets/examples/ruby/entity_variable.rb
Normal file
2
assets/examples/ruby/entity_variable.rb
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
# Bevy::Entity.current can be used to access the entity that is currently being processed
|
||||
puts("Current entity index: #{Bevy::Entity.current.index}")
|
||||
4
assets/examples/ruby/function_params.rb
Normal file
4
assets/examples/ruby/function_params.rb
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
fun_with_string_param("hello")
|
||||
fun_with_i64_param(5)
|
||||
fun_with_multiple_params(5, "hello")
|
||||
fun_with_i64_and_array_param(5, [1, 2, "third element"])
|
||||
3
assets/examples/ruby/function_return_value.rb
Normal file
3
assets/examples/ruby/function_return_value.rb
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
def get_value
|
||||
42
|
||||
end
|
||||
1
assets/examples/ruby/hello_world.rb
Normal file
1
assets/examples/ruby/hello_world.rb
Normal file
|
|
@ -0,0 +1 @@
|
|||
hello_bevy()
|
||||
1
assets/examples/ruby/multiple_plugins_plugin_a.rb
Normal file
1
assets/examples/ruby/multiple_plugins_plugin_a.rb
Normal file
|
|
@ -0,0 +1 @@
|
|||
hello_from_plugin_a
|
||||
1
assets/examples/ruby/multiple_plugins_plugin_b.rb
Normal file
1
assets/examples/ruby/multiple_plugins_plugin_b.rb
Normal file
|
|
@ -0,0 +1 @@
|
|||
hello_from_plugin_b_with_parameters("hello", 42)
|
||||
3
assets/examples/ruby/promises.rb
Normal file
3
assets/examples/ruby/promises.rb
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
get_player_name.and_then do |name|
|
||||
puts name
|
||||
end
|
||||
1
assets/examples/ruby/side_effects.rb
Normal file
1
assets/examples/ruby/side_effects.rb
Normal file
|
|
@ -0,0 +1 @@
|
|||
spawn_entity()
|
||||
3
assets/tests/lua/entity_variable.lua
Normal file
3
assets/tests/lua/entity_variable.lua
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
function test_func()
|
||||
rust_func(entity.index)
|
||||
end
|
||||
5
assets/tests/lua/entity_variable_eval.lua
Normal file
5
assets/tests/lua/entity_variable_eval.lua
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
index = entity.index
|
||||
|
||||
function test_func()
|
||||
rust_func(index)
|
||||
end
|
||||
2
assets/tests/lua/eval_that_causes_runtime_error.lua
Normal file
2
assets/tests/lua/eval_that_causes_runtime_error.lua
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
mark_called()
|
||||
error()
|
||||
3
assets/tests/lua/pass_entity_from_script.lua
Normal file
3
assets/tests/lua/pass_entity_from_script.lua
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
function test_func()
|
||||
rust_func(entity)
|
||||
end
|
||||
3
assets/tests/lua/pass_vec3_from_script.lua
Normal file
3
assets/tests/lua/pass_vec3_from_script.lua
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
function test_func()
|
||||
rust_func(Vec3(1.5, 2.5, -3.5))
|
||||
end
|
||||
6
assets/tests/lua/pass_vec3_to_script.lua
Normal file
6
assets/tests/lua/pass_vec3_to_script.lua
Normal file
|
|
@ -0,0 +1,6 @@
|
|||
function test_func(vec3)
|
||||
assert(vec3.x == 1.5)
|
||||
assert(vec3.y == 2.5)
|
||||
assert(vec3.z == -3.5)
|
||||
mark_success()
|
||||
end
|
||||
3
assets/tests/rhai/entity_variable.rhai
Normal file
3
assets/tests/rhai/entity_variable.rhai
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fn test_func() {
|
||||
rust_func(entity.index);
|
||||
}
|
||||
5
assets/tests/rhai/entity_variable_eval.rhai
Normal file
5
assets/tests/rhai/entity_variable_eval.rhai
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
let index = entity.index;
|
||||
|
||||
fn test_func() {
|
||||
rust_func(index);
|
||||
}
|
||||
2
assets/tests/rhai/eval_that_causes_runtime_error.rhai
Normal file
2
assets/tests/rhai/eval_that_causes_runtime_error.rhai
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
mark_called();
|
||||
throw();
|
||||
3
assets/tests/rhai/pass_entity_from_script.rhai
Normal file
3
assets/tests/rhai/pass_entity_from_script.rhai
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fn test_func() {
|
||||
rust_func(entity);
|
||||
}
|
||||
3
assets/tests/rhai/pass_vec3_from_script.rhai
Normal file
3
assets/tests/rhai/pass_vec3_from_script.rhai
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
fn test_func() {
|
||||
rust_func(new_vec3(1.5, 2.5, -3.5));
|
||||
}
|
||||
7
assets/tests/rhai/pass_vec3_to_script.rhai
Normal file
7
assets/tests/rhai/pass_vec3_to_script.rhai
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
fn test_func(vec3) {
|
||||
if type_of(vec3) != "Vec3" { throw() }
|
||||
if vec3.x != 1.5 { throw() }
|
||||
if vec3.y != 2.5 { throw() }
|
||||
if vec3.z != -3.5 { throw() }
|
||||
mark_success();
|
||||
}
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
def test_func
|
||||
raise
|
||||
end
|
||||
7
assets/tests/ruby/call_script_function_with_params.rb
Normal file
7
assets/tests/ruby/call_script_function_with_params.rb
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
$state = {
|
||||
'called_with' => nil
|
||||
}
|
||||
|
||||
def test_func(val)
|
||||
$state['called_with'] = val
|
||||
end
|
||||
3
assets/tests/ruby/entity_variable.rb
Normal file
3
assets/tests/ruby/entity_variable.rb
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
def test_func
|
||||
rust_func(Bevy::Entity.current.index)
|
||||
end
|
||||
5
assets/tests/ruby/entity_variable_eval.rb
Normal file
5
assets/tests/ruby/entity_variable_eval.rb
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
$index = Bevy::Entity.current.index
|
||||
|
||||
def test_func
|
||||
rust_func($index)
|
||||
end
|
||||
2
assets/tests/ruby/eval_that_causes_runtime_error.rb
Normal file
2
assets/tests/ruby/eval_that_causes_runtime_error.rb
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
mark_called
|
||||
raise
|
||||
3
assets/tests/ruby/pass_entity_from_script.rb
Normal file
3
assets/tests/ruby/pass_entity_from_script.rb
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
def test_func
|
||||
rust_func(Bevy::Entity.current)
|
||||
end
|
||||
3
assets/tests/ruby/pass_vec3_from_script.rb
Normal file
3
assets/tests/ruby/pass_vec3_from_script.rb
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
def test_func
|
||||
rust_func(Bevy::Vec3.new(1.5, 2.5, -3.5))
|
||||
end
|
||||
7
assets/tests/ruby/pass_vec3_to_script.rb
Normal file
7
assets/tests/ruby/pass_vec3_to_script.rb
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
def test_func(vec3)
|
||||
raise unless vec3.is_a?(Bevy::Vec3)
|
||||
raise unless vec3.x == 1.5
|
||||
raise unless vec3.y == 2.5
|
||||
raise unless vec3.z == -3.5
|
||||
mark_success
|
||||
end
|
||||
5
assets/tests/ruby/promise_runtime_error.rb
Normal file
5
assets/tests/ruby/promise_runtime_error.rb
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
def test_func
|
||||
rust_func.and_then do |x|
|
||||
raise
|
||||
end
|
||||
end
|
||||
9
assets/tests/ruby/return_via_promise.rb
Normal file
9
assets/tests/ruby/return_via_promise.rb
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
$state = {
|
||||
'x' => nil
|
||||
}
|
||||
|
||||
def test_func
|
||||
rust_func.and_then do |x|
|
||||
$state['x'] = x
|
||||
end
|
||||
end
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
def test_func
|
||||
rust_func
|
||||
end
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
def test_func
|
||||
rust_func(5, 'test')
|
||||
end
|
||||
|
|
@ -0,0 +1,3 @@
|
|||
def test_func
|
||||
rust_func(5)
|
||||
end
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
$state = {
|
||||
'times_called' => 0
|
||||
}
|
||||
|
||||
def test_func
|
||||
$state['times_called'] += 1
|
||||
end
|
||||
|
|
@ -0,0 +1,9 @@
|
|||
$state = {
|
||||
'a_value' => nil,
|
||||
'b_value' => nil
|
||||
}
|
||||
|
||||
def test_func(a, b)
|
||||
$state['a_value'] = a
|
||||
$state['b_value'] = b
|
||||
end
|
||||
|
|
@ -0,0 +1,7 @@
|
|||
$state = {
|
||||
'a_value' => nil
|
||||
}
|
||||
|
||||
def test_func(a)
|
||||
$state['a_value'] = a
|
||||
end
|
||||
3
assets/tests/ruby/side_effects.rb
Normal file
3
assets/tests/ruby/side_effects.rb
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
def test_func
|
||||
spawn_entity
|
||||
end
|
||||
1
book/.gitignore
vendored
1
book/.gitignore
vendored
|
|
@ -1,2 +1,3 @@
|
|||
book
|
||||
doctest_cache
|
||||
target
|
||||
|
|
|
|||
2498
book/Cargo.lock
generated
Normal file
2498
book/Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load diff
7
book/Cargo.toml
Normal file
7
book/Cargo.toml
Normal file
|
|
@ -0,0 +1,7 @@
|
|||
[package]
|
||||
name = "bevy_scriptum_book"
|
||||
publish = false
|
||||
edition = "2024"
|
||||
|
||||
[dependencies]
|
||||
bevy_scriptum = { path = "../", features = ["ruby", "lua", "rhai"] }
|
||||
|
|
@ -4,9 +4,3 @@ language = "en"
|
|||
multilingual = false
|
||||
src = "src"
|
||||
title = "bevy_scriptum"
|
||||
|
||||
[preprocessor.keeper]
|
||||
command = "mdbook-keeper"
|
||||
manifest_dir = "../"
|
||||
externs = ["bevy", "bevy_scriptum"]
|
||||
build_features = ["lua", "rhai"]
|
||||
|
|
|
|||
15
book/justfile
Normal file
15
book/justfile
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
export CARGO_MANIFEST_DIR := `pwd`
|
||||
|
||||
build-deps:
|
||||
cargo clean && cargo build
|
||||
|
||||
_test:
|
||||
mdbook test -L target/debug/deps/
|
||||
|
||||
test: build-deps _test
|
||||
|
||||
test-watch: build-deps
|
||||
watchexec --exts md -r just _test
|
||||
|
||||
serve:
|
||||
mdbook serve
|
||||
|
|
@ -2,20 +2,29 @@
|
|||
|
||||
- [Introduction](./introduction.md)
|
||||
- [Runtimes](./runtimes.md)
|
||||
- [Lua](./lua/lua.md)
|
||||
- [Installation](./lua/installation.md)
|
||||
- [Hello World](./lua/hello_world.md)
|
||||
- [Spawning scripts](./lua/spawning_scripts.md)
|
||||
- [Calling Rust from Lua](./lua/calling_rust_from_script.md)
|
||||
- [Calling Lua from Rust](./lua/calling_script_from_rust.md)
|
||||
- [Interacting with bevy in callbacks](./lua/interacting_with_bevy.md)
|
||||
- [Builtin types](./lua/builtin_types.md)
|
||||
- [Builtin variables](./lua/builtin_variables.md)
|
||||
- [Rhai](./rhai/rhai.md)
|
||||
- [Installation](./rhai/installation.md)
|
||||
- [Hello World(TBD)]()
|
||||
- [Lua](./lua/lua.md)
|
||||
- [Installation](./lua/installation.md)
|
||||
- [Hello World](./lua/hello_world.md)
|
||||
- [Spawning scripts](./lua/spawning_scripts.md)
|
||||
- [Calling Rust from Lua](./lua/calling_rust_from_script.md)
|
||||
- [Calling Lua from Rust](./lua/calling_script_from_rust.md)
|
||||
- [Interacting with bevy in callbacks](./lua/interacting_with_bevy.md)
|
||||
- [Builtin types](./lua/builtin_types.md)
|
||||
- [Builtin variables](./lua/builtin_variables.md)
|
||||
- [Ruby](./ruby/ruby.md)
|
||||
- [Installation](./ruby/installation.md)
|
||||
- [Hello World](./ruby/hello_world.md)
|
||||
- [Spawning scripts](./ruby/spawning_scripts.md)
|
||||
- [Calling Rust from Ruby](./ruby/calling_rust_from_script.md)
|
||||
- [Calling Ruby from Rust](./ruby/calling_script_from_rust.md)
|
||||
- [Interacting with bevy in callbacks](./ruby/interacting_with_bevy.md)
|
||||
- [Builtin types](./ruby/builtin_types.md)
|
||||
- [Rhai](./rhai/rhai.md)
|
||||
- [Installation](./rhai/installation.md)
|
||||
- [Hello World(TBD)]()
|
||||
- [Multiple plugins](./multiple_plugins.md)
|
||||
- [Multiple runtimes(TBD)]()
|
||||
- [Implementing custom runtimes(TBD)]()
|
||||
- [Workflow](./workflow/workflow.md)
|
||||
- [Live-reload](./workflow/live_reload.md)
|
||||
- [Live-reload](./workflow/live_reload.md)
|
||||
- [Bevy support matrix](./bevy_support_matrix.md)
|
||||
|
|
|
|||
|
|
@ -1,8 +1,11 @@
|
|||
# Bevy support matrix
|
||||
|
||||
| bevy version | bevy_scriptum version |
|
||||
|--------------|----------------------|
|
||||
| 0.13 | 0.4-0.5 |
|
||||
| 0.12 | 0.3 |
|
||||
| 0.11 | 0.2 |
|
||||
| 0.10 | 0.1 |
|
||||
| ------------ | --------------------- |
|
||||
| 0.16 | 0.8-0.9 |
|
||||
| 0.15 | 0.7 |
|
||||
| 0.14 | 0.6 |
|
||||
| 0.13 | 0.4-0.5 |
|
||||
| 0.12 | 0.3 |
|
||||
| 0.11 | 0.2 |
|
||||
| 0.10 | 0.1 |
|
||||
|
|
|
|||
|
|
@ -1,21 +1,35 @@
|
|||
# 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.
|
||||
Currently [Rhai](https://rhai.rs/) and [Lua](https://lua.org/) are supported, but more languages may be added in the future.
|
||||
bevy_scriptum is a a plugin for [Bevy](https://bevyengine.org/) that allows you to write some of your game or application logic in a scripting language.
|
||||
|
||||
API docs are available in [docs.rs](https://docs.rs/bevy_scriptum/latest/bevy_scriptum/)
|
||||
## Supported scripting languages/runtimes
|
||||
|
||||
| language/runtime | cargo feature | documentation chapter |
|
||||
| ---------------- | ------------- | --------------------------------------------------------------- |
|
||||
| 🌙 LuaJIT | `lua` | [link](https://jarkonik.github.io/bevy_scriptum/lua/lua.html) |
|
||||
| 🌾 Rhai | `rhai` | [link](https://jarkonik.github.io/bevy_scriptum/rhai/rhai.html) |
|
||||
| 💎 Ruby | `ruby` | [link](https://jarkonik.github.io/bevy_scriptum/ruby/ruby.html) |
|
||||
|
||||
Documentation book is available [here](https://jarkonik.github.io/bevy_scriptum/) 📖
|
||||
|
||||
Full API docs are available at [docs.rs](https://docs.rs/bevy_scriptum/latest/bevy_scriptum/) 🧑💻
|
||||
|
||||
bevy_scriptum's main advantages include:
|
||||
|
||||
- low-boilerplate
|
||||
- easy to use
|
||||
- asynchronicity with a promise-based API
|
||||
- flexibility
|
||||
- hot-reloading
|
||||
|
||||
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 it.
|
||||
|
||||
All you need to do is register callbacks on your Bevy app like this:
|
||||
```rust
|
||||
|
||||
```rust,no_run
|
||||
# extern crate bevy;
|
||||
# extern crate bevy_scriptum;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::lua::prelude::*;
|
||||
|
|
@ -31,14 +45,20 @@ fn main() {
|
|||
.run();
|
||||
}
|
||||
```
|
||||
|
||||
And you can call them in your scripts like this:
|
||||
|
||||
```lua
|
||||
hello_bevy()
|
||||
```
|
||||
|
||||
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
|
||||
```rust,no_run
|
||||
# extern crate bevy;
|
||||
# extern crate bevy_ecs;
|
||||
# extern crate bevy_scriptum;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::lua::prelude::*;
|
||||
|
|
@ -64,7 +84,11 @@ fn main() {
|
|||
```
|
||||
|
||||
You can also pass arguments to your callback functions, just like you would in a regular Bevy system - using `In` structs with tuples:
|
||||
```rust
|
||||
|
||||
```rust,no_run
|
||||
# extern crate bevy;
|
||||
# extern crate bevy_scriptum;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::lua::prelude::*;
|
||||
|
|
@ -83,7 +107,9 @@ fn main() {
|
|||
.run();
|
||||
}
|
||||
```
|
||||
|
||||
which you can then call in your script like this:
|
||||
|
||||
```lua
|
||||
fun_with_string_param("Hello world!")
|
||||
```
|
||||
|
|
@ -94,14 +120,17 @@ Add the following to your `Cargo.toml`:
|
|||
|
||||
```toml
|
||||
[dependencies]
|
||||
bevy_scriptum = { version = "0.5", features = ["lua"] }
|
||||
bevy_scriptum = { version = "0.9", features = ["lua"] }
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
```rust
|
||||
```rust,no_run
|
||||
# extern crate bevy;
|
||||
# extern crate bevy_scriptum;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::lua::prelude::*;
|
||||
|
|
@ -129,7 +158,10 @@ my_print("Hello world!")
|
|||
|
||||
And spawn an entity with attached `Script` component with a handle to a script source file:
|
||||
|
||||
```rust
|
||||
```rust,no_run
|
||||
# extern crate bevy;
|
||||
# extern crate bevy_scriptum;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::lua::prelude::*;
|
||||
|
|
@ -156,11 +188,12 @@ You should then see `my_print: 'Hello world!'` printed in your console.
|
|||
|
||||
### 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:
|
||||
|
||||
```bash
|
||||
cargo run --example hello_world_lua
|
||||
```
|
||||
|
||||
The examples live in `examples` directory and their corresponding scripts live in `assets/examples` directory within the repository.
|
||||
|
||||
### Promises - getting return values from scripts
|
||||
|
|
@ -172,9 +205,13 @@ get_player_name():and_then(function(name)
|
|||
print(name)
|
||||
end)
|
||||
```
|
||||
|
||||
which will print out `John` when used with following exposed function:
|
||||
|
||||
```rust
|
||||
```rust,no_run
|
||||
# extern crate bevy;
|
||||
# extern crate bevy_scriptum;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::lua::prelude::*;
|
||||
|
|
@ -186,7 +223,7 @@ fn main() {
|
|||
runtime.add_function(String::from("get_player_name"), || String::from("John"));
|
||||
});
|
||||
}
|
||||
````
|
||||
```
|
||||
|
||||
## Access entity from script
|
||||
|
||||
|
|
@ -194,6 +231,7 @@ A variable called `entity` is automatically available to all scripts - it repres
|
|||
It exposes `index` property that returns bevy entity index.
|
||||
It is useful for accessing entity's components from scripts.
|
||||
It can be used in the following way:
|
||||
|
||||
```lua
|
||||
print("Current entity index: " .. entity.index)
|
||||
```
|
||||
|
|
|
|||
0
book/src/lib.rs
Normal file
0
book/src/lib.rs
Normal file
|
|
@ -20,14 +20,17 @@ bevy_scriptum provides following types that can be used in Lua:
|
|||
|
||||
### Example Lua usage
|
||||
|
||||
```
|
||||
```lua
|
||||
my_vec = Vec3(1, 2, 3)
|
||||
set_translation(entity, my_vec)
|
||||
```
|
||||
|
||||
### Example Rust usage
|
||||
|
||||
```rust
|
||||
```rust,no_run
|
||||
# extern crate bevy;
|
||||
# extern crate bevy_scriptum;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::lua::prelude::*;
|
||||
|
|
@ -69,7 +72,10 @@ pass_to_rust(entity)
|
|||
|
||||
### Example Rust usage
|
||||
|
||||
```rust
|
||||
```rust,no_run
|
||||
# extern crate bevy;
|
||||
# extern crate bevy_scriptum;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::lua::prelude::*;
|
||||
|
|
|
|||
|
|
@ -3,7 +3,10 @@
|
|||
To call a rust function from Lua first you need to register a function
|
||||
within Rust using builder pattern.
|
||||
|
||||
```rust
|
||||
```rust,no_run
|
||||
# extern crate bevy;
|
||||
# extern crate bevy_scriptum;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::lua::prelude::*;
|
||||
|
|
@ -20,7 +23,10 @@ fn main() {
|
|||
|
||||
For example to register a function called `my_rust_func` you can do the following:
|
||||
|
||||
```rust
|
||||
```rust,no_run
|
||||
# extern crate bevy;
|
||||
# extern crate bevy_scriptum;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::lua::prelude::*;
|
||||
|
|
@ -49,7 +55,10 @@ that implements `FromLua`.
|
|||
Since a registered callback function is a Bevy system, the parameters are passed
|
||||
to it as `In` struct with tuple, which has to be the first parameter of the closure.
|
||||
|
||||
```rust
|
||||
```rust,no_run
|
||||
# extern crate bevy;
|
||||
# extern crate bevy_scriptum;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::lua::prelude::*;
|
||||
|
|
@ -68,7 +77,10 @@ fn main() {
|
|||
|
||||
To make it look nicer you can destructure the `In` struct.
|
||||
|
||||
```rust
|
||||
```rust,no_run
|
||||
# extern crate bevy;
|
||||
# extern crate bevy_scriptum;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::lua::prelude::*;
|
||||
|
|
@ -97,7 +109,10 @@ Any registered rust function that returns a value will retrurn a promise when
|
|||
called within a script. By calling `:and_then` on the promise you can register
|
||||
a callback that will receive the value returned from Rust function.
|
||||
|
||||
```rust
|
||||
```rust,no_run
|
||||
# extern crate bevy;
|
||||
# extern crate bevy_scriptum;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::lua::prelude::*;
|
||||
|
|
|
|||
|
|
@ -13,7 +13,10 @@ of the function to call, `LuaScriptData` that has been automatically
|
|||
attached to entity after an entity with script attached has been spawned
|
||||
and its script evaluated, the entity and optionally some arguments.
|
||||
|
||||
```rust
|
||||
```rust,no_run
|
||||
# extern crate bevy;
|
||||
# extern crate bevy_scriptum;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::lua::prelude::*;
|
||||
|
|
@ -29,14 +32,15 @@ fn call_lua_on_update_from_rust(
|
|||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
```
|
||||
|
||||
We can also pass some arguments by providing a tuple or `Vec` as the last
|
||||
`call_fn` argument.
|
||||
|
||||
```rust
|
||||
```rust,no_run
|
||||
# extern crate bevy;
|
||||
# extern crate bevy_scriptum;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::lua::prelude::*;
|
||||
|
|
@ -51,8 +55,6 @@ fn call_lua_on_update_from_rust(
|
|||
.unwrap();
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
```
|
||||
|
||||
They will be passed to `on_update` Lua function
|
||||
|
|
|
|||
|
|
@ -12,7 +12,10 @@ a create feature.
|
|||
|
||||
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
|
||||
```rust,no_run
|
||||
# extern crate bevy;
|
||||
# extern crate bevy_scriptum;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::lua::prelude::*;
|
||||
|
|
@ -40,7 +43,10 @@ my_print("Hello world!")
|
|||
|
||||
And spawn an entity with attached `Script` component with a handle to a script source file:
|
||||
|
||||
```rust
|
||||
```rust,no_run
|
||||
# extern crate bevy;
|
||||
# extern crate bevy_scriptum;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::lua::prelude::*;
|
||||
|
|
|
|||
|
|
@ -4,8 +4,8 @@ Add the following to your `Cargo.toml`:
|
|||
|
||||
```toml
|
||||
[dependencies]
|
||||
bevy = "0.13"
|
||||
bevy_scriptum = { version = "0.5", features = ["lua"] }
|
||||
bevy = "0.16"
|
||||
bevy_scriptum = { version = "0.9", features = ["lua"] }
|
||||
```
|
||||
|
||||
If you need a different version of bevy you need to use a matching bevy_scriptum
|
||||
|
|
|
|||
|
|
@ -7,7 +7,11 @@ That allows you to do anything you would do in a Bevy system.
|
|||
You could for example create a callback system function that prints names
|
||||
of all entities with `Player` component.
|
||||
|
||||
```rust
|
||||
```rust,no_run
|
||||
# extern crate bevy;
|
||||
# extern crate bevy_ecs;
|
||||
# extern crate bevy_scriptum;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::lua::prelude::*;
|
||||
|
|
@ -42,7 +46,11 @@ You can use functions that interact with Bevy entities and resources and
|
|||
take arguments at the same time. It could be used for example to mutate a
|
||||
component.
|
||||
|
||||
```rust
|
||||
```rust,no_run
|
||||
# extern crate bevy;
|
||||
# extern crate bevy_ecs;
|
||||
# extern crate bevy_scriptum;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::lua::prelude::*;
|
||||
|
|
@ -59,7 +67,7 @@ fn main() {
|
|||
runtime.add_function(
|
||||
String::from("hurt_player"),
|
||||
|In((hit_value,)): In<(i32,)>, mut players: Query<&mut Player>| {
|
||||
let mut player = players.single_mut();
|
||||
let mut player = players.single_mut().unwrap();
|
||||
player.health -= hit_value;
|
||||
},
|
||||
);
|
||||
|
|
|
|||
|
|
@ -4,6 +4,9 @@ To spawn a Lua script you will need to get a handle to a script asset using
|
|||
bevy's `AssetServer`.
|
||||
|
||||
```rust
|
||||
# extern crate bevy;
|
||||
# extern crate bevy_scriptum;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::lua::prelude::*;
|
||||
|
|
@ -13,8 +16,6 @@ fn my_spawner(mut commands: Commands, assets_server: Res<AssetServer>) {
|
|||
assets_server.load("my_script.lua"),
|
||||
));
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
```
|
||||
|
||||
After they scripts have been evaled by bevy_scriptum, the entities that they've
|
||||
|
|
@ -24,6 +25,9 @@ been attached to will get the `Script::<LuaScript>` component stripped and inste
|
|||
So to query scipted entities you could do something like:
|
||||
|
||||
```rust
|
||||
# extern crate bevy;
|
||||
# extern crate bevy_scriptum;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::lua::prelude::*;
|
||||
|
|
@ -35,6 +39,4 @@ fn my_system(
|
|||
// do something with scripted entities
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
```
|
||||
|
|
|
|||
34
book/src/multiple_plugins.md
Normal file
34
book/src/multiple_plugins.md
Normal file
|
|
@ -0,0 +1,34 @@
|
|||
# Multiple plugins
|
||||
|
||||
It is 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,no_run
|
||||
# extern crate bevy;
|
||||
# extern crate bevy_scriptum;
|
||||
|
||||
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();
|
||||
}
|
||||
```
|
||||
|
|
@ -4,8 +4,8 @@ Add the following to your `Cargo.toml`:
|
|||
|
||||
```toml
|
||||
[dependencies]
|
||||
bevy = "0.13"
|
||||
bevy_scriptum = { version = "0.5", features = ["rhai"] }
|
||||
bevy = "0.16"
|
||||
bevy_scriptum = { version = "0.9", features = ["rhai"] }
|
||||
```
|
||||
|
||||
If you need a different version of bevy you need to use a matching bevy_scriptum
|
||||
|
|
|
|||
95
book/src/ruby/builtin_types.md
Normal file
95
book/src/ruby/builtin_types.md
Normal file
|
|
@ -0,0 +1,95 @@
|
|||
# Builtin types
|
||||
|
||||
bevy_scriptum provides following types that can be used in Ruby:
|
||||
|
||||
- `Bevy::Vec3`
|
||||
- `Bevy::Entity`
|
||||
|
||||
## Bevy::Vec3
|
||||
|
||||
### Class Methods
|
||||
|
||||
- `new(x, y, z)`
|
||||
- `current`
|
||||
|
||||
### Instance Methods
|
||||
|
||||
- `x`
|
||||
- `y`
|
||||
- `z`
|
||||
|
||||
### Example Ruby usage
|
||||
|
||||
```ruby
|
||||
my_vec = Bevy::Vec3.new(1, 2, 3)
|
||||
set_translation(entity, my_vec)
|
||||
```
|
||||
|
||||
### Example Rust usage
|
||||
|
||||
```rust,no_run
|
||||
# extern crate bevy;
|
||||
# extern crate bevy_scriptum;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::ruby::prelude::*;
|
||||
|
||||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_scripting::<RubyRuntime>(|runtime| {
|
||||
runtime.add_function(String::from("set_translation"), set_translation);
|
||||
})
|
||||
.run();
|
||||
}
|
||||
|
||||
fn set_translation(
|
||||
In((entity, translation)): In<(BevyEntity, BevyVec3)>,
|
||||
mut entities: Query<&mut Transform>,
|
||||
) {
|
||||
let mut transform = entities.get_mut(entity.0).unwrap();
|
||||
transform.translation = translation.0;
|
||||
}
|
||||
```
|
||||
|
||||
## Bevy::Entity
|
||||
|
||||
`Bevy::Entity.current` is currently not available within promise callbacks.
|
||||
|
||||
### Constructor
|
||||
|
||||
None - instances can only be acquired by using `Bevy::Entity.current`
|
||||
|
||||
### Class method
|
||||
|
||||
- `index`
|
||||
|
||||
### Example Ruby usage
|
||||
|
||||
```ruby
|
||||
puts(Bevy::Entity.current.index)
|
||||
pass_to_rust(Bevy::Entity.current)
|
||||
```
|
||||
|
||||
### Example Rust usage
|
||||
|
||||
```rust,no_run
|
||||
# extern crate bevy;
|
||||
# extern crate bevy_scriptum;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::ruby::prelude::*;
|
||||
|
||||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_scripting::<RubyRuntime>(|runtime| {
|
||||
runtime.add_function(String::from("pass_to_rust"), |In((entity,)): In<(BevyEntity,)>| {
|
||||
println!("pass_to_rust called with entity: {:?}", entity);
|
||||
});
|
||||
})
|
||||
.run();
|
||||
}
|
||||
```
|
||||
133
book/src/ruby/calling_rust_from_script.md
Normal file
133
book/src/ruby/calling_rust_from_script.md
Normal file
|
|
@ -0,0 +1,133 @@
|
|||
# Calling Rust from Ruby
|
||||
|
||||
To call a rust function from Ruby first you need to register a function
|
||||
within Rust using builder pattern.
|
||||
|
||||
```rust,no_run
|
||||
# extern crate bevy;
|
||||
# extern crate bevy_scriptum;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::ruby::prelude::*;
|
||||
|
||||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_scripting::<RubyRuntime>(|runtime| {
|
||||
// `runtime` is a builder that you can use to register functions
|
||||
})
|
||||
.run();
|
||||
}
|
||||
```
|
||||
|
||||
For example to register a function called `my_rust_func` you can do the following:
|
||||
|
||||
```rust,no_run
|
||||
# extern crate bevy;
|
||||
# extern crate bevy_scriptum;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::ruby::prelude::*;
|
||||
|
||||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_scripting::<RubyRuntime>(|runtime| {
|
||||
runtime.add_function(String::from("my_rust_func"), || {
|
||||
println!("my_rust_func has been called");
|
||||
});
|
||||
})
|
||||
.run();
|
||||
}
|
||||
```
|
||||
|
||||
After you do that the function will be available to Ruby code in your spawned scripts.
|
||||
|
||||
```ruby
|
||||
my_rust_func
|
||||
```
|
||||
|
||||
Since a registered callback function is a Bevy system, the parameters are passed
|
||||
to it as `In` struct with tuple, which has to be the first parameter of the closure.
|
||||
|
||||
```rust,no_run
|
||||
# extern crate bevy;
|
||||
# extern crate bevy_scriptum;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::ruby::prelude::*;
|
||||
|
||||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_scripting::<RubyRuntime>(|runtime| {
|
||||
runtime.add_function(String::from("func_with_params"), |args: In<(String, i64)>| {
|
||||
println!("my_rust_func has been called with string {} and i64 {}", args.0.0, args.0.1);
|
||||
});
|
||||
})
|
||||
.run();
|
||||
}
|
||||
```
|
||||
|
||||
To make it look nicer you can destructure the `In` struct.
|
||||
|
||||
```rust,no_run
|
||||
# extern crate bevy;
|
||||
# extern crate bevy_scriptum;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::ruby::prelude::*;
|
||||
|
||||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_scripting::<RubyRuntime>(|runtime| {
|
||||
runtime.add_function(String::from("func_with_params"), |In((a, b)): In<(String, i64)>| {
|
||||
println!("my_rust_func has been called with string {} and i64 {}", a, b);
|
||||
});
|
||||
})
|
||||
.run();
|
||||
}
|
||||
```
|
||||
|
||||
The above function can be called from Ruby
|
||||
|
||||
```ruby
|
||||
func_with_params("abc", 123)
|
||||
```
|
||||
|
||||
## Return value via promise
|
||||
|
||||
Any registered rust function that returns a value will retrurn a promise when
|
||||
called within a script. By calling `:and_then` on the promise you can register
|
||||
a callback that will receive the value returned from Rust function.
|
||||
|
||||
```rust,no_run
|
||||
# extern crate bevy;
|
||||
# extern crate bevy_scriptum;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::ruby::prelude::*;
|
||||
|
||||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_scripting::<RubyRuntime>(|runtime| {
|
||||
runtime.add_function(String::from("returns_value"), || {
|
||||
123
|
||||
});
|
||||
})
|
||||
.run();
|
||||
}
|
||||
```
|
||||
|
||||
```ruby
|
||||
returns_value.and_then do |value|
|
||||
puts(value) # 123
|
||||
end
|
||||
```
|
||||
66
book/src/ruby/calling_script_from_rust.md
Normal file
66
book/src/ruby/calling_script_from_rust.md
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
# Calling Ruby from Rust
|
||||
|
||||
To call a function defined in Ruby
|
||||
|
||||
```ruby
|
||||
def on_update
|
||||
end
|
||||
```
|
||||
|
||||
We need to acquire `RubyRuntime` resource within a bevy system.
|
||||
Then we will be able to call `call_fn` on it, providing the name
|
||||
of the function to call, `RubyScriptData` that has been automatically
|
||||
attached to entity after an entity with script attached has been spawned
|
||||
and its script evaluated, the entity and optionally some arguments.
|
||||
|
||||
```rust,no_run
|
||||
# extern crate bevy;
|
||||
# extern crate bevy_scriptum;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::ruby::prelude::*;
|
||||
|
||||
fn call_ruby_on_update_from_rust(
|
||||
mut scripted_entities: Query<(Entity, &mut RubyScriptData)>,
|
||||
scripting_runtime: ResMut<RubyRuntime>,
|
||||
) {
|
||||
for (entity, mut script_data) in &mut scripted_entities {
|
||||
// calling function named `on_update` defined in Ruby script
|
||||
scripting_runtime
|
||||
.call_fn("on_update", &mut script_data, entity, ())
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
We can also pass some arguments by providing a tuple or `Vec` as the last
|
||||
`call_fn` argument.
|
||||
|
||||
```rust,no_run
|
||||
# extern crate bevy;
|
||||
# extern crate bevy_scriptum;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::ruby::prelude::*;
|
||||
|
||||
fn call_ruby_on_update_from_rust(
|
||||
mut scripted_entities: Query<(Entity, &mut RubyScriptData)>,
|
||||
scripting_runtime: ResMut<RubyRuntime>,
|
||||
) {
|
||||
for (entity, mut script_data) in &mut scripted_entities {
|
||||
scripting_runtime
|
||||
.call_fn("on_update", &mut script_data, entity, (123, String::from("hello")))
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
They will be passed to `on_update` Ruby function
|
||||
```ruby
|
||||
def on_update(a, b)
|
||||
puts(a) # 123
|
||||
puts(b) # hello
|
||||
end
|
||||
```
|
||||
72
book/src/ruby/hello_world.md
Normal file
72
book/src/ruby/hello_world.md
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
# Hello World
|
||||
|
||||
After you are done installing the required crates, you can start developing
|
||||
your first game or application using bevy_scriptum.
|
||||
|
||||
To start using the library you need to first import some structs and traits
|
||||
with Rust `use` statements.
|
||||
|
||||
For convenience there is a main "prelude" module provided called
|
||||
`bevy_scriptum::prelude` and a prelude for each runtime you have enabled as
|
||||
a create feature.
|
||||
|
||||
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
|
||||
# extern crate bevy;
|
||||
# extern crate bevy_scriptum;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::ruby::prelude::*;
|
||||
|
||||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_scripting::<RubyRuntime>(|runtime| {
|
||||
runtime.add_function(
|
||||
String::from("my_print"),
|
||||
|In((x,)): In<(String,)>| {
|
||||
println!("my_print: '{}'", x);
|
||||
},
|
||||
);
|
||||
})
|
||||
.run();
|
||||
}
|
||||
```
|
||||
|
||||
Then you can create a script file in `assets` directory called `script.rb` that calls this function:
|
||||
|
||||
```ruby
|
||||
my_print("Hello world!")
|
||||
```
|
||||
|
||||
And spawn an entity with attached `Script` component with a handle to a script source file:
|
||||
|
||||
```rust,no_run
|
||||
# extern crate bevy;
|
||||
# extern crate bevy_scriptum;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::ruby::prelude::*;
|
||||
|
||||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_scripting::<RubyRuntime>(|runtime| {
|
||||
runtime.add_function(
|
||||
String::from("my_print"),
|
||||
|In((x,)): In<(String,)>| {
|
||||
println!("my_print: '{}'", x);
|
||||
},
|
||||
);
|
||||
})
|
||||
.add_systems(Startup,|mut commands: Commands, asset_server: Res<AssetServer>| {
|
||||
commands.spawn(Script::<RubyScript>::new(asset_server.load("script.rb")));
|
||||
})
|
||||
.run();
|
||||
}
|
||||
```
|
||||
|
||||
You should then see `my_print: 'Hello world!'` printed in your console.
|
||||
52
book/src/ruby/installation.md
Normal file
52
book/src/ruby/installation.md
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
# Installation
|
||||
|
||||
Ruby is currently only supported on Linux.
|
||||
|
||||
## Ruby
|
||||
|
||||
To build `bevy_scriptum` with Ruby support a Ruby installation is needed to be
|
||||
present on your development machine.
|
||||
|
||||
The easiest way to produce a compatible Ruby installation is to use [rbenv](https://rbenv.org/).
|
||||
|
||||
After installing `rbenv` along with its `ruby-build` plugin you can build and
|
||||
install a Ruby installation that will work with `bevy_scriptum` by executing:
|
||||
|
||||
```sh
|
||||
CC=clang rbenv install 3.4.4
|
||||
```
|
||||
|
||||
Above assumes that you also have `clang` installed on your system.
|
||||
For `clang` installation instruction consult your
|
||||
OS vendor provided documentation or [clang official webiste](https://clang.llvm.org).
|
||||
|
||||
If you rather not use `rbenv` you are free to supply your own installation of
|
||||
Ruby provided the following is true about it:
|
||||
|
||||
- it is compiled with `clang`
|
||||
- it is compiled as a static library
|
||||
- it is accessible as `ruby` within `PATH` or `RUBY` environment variable is set
|
||||
to path of desired `ruby` binary.
|
||||
|
||||
## Main Library
|
||||
|
||||
Add the following to your `Cargo.toml`:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
bevy = "0.16"
|
||||
bevy_scriptum = { version = "0.9", features = ["ruby"] }
|
||||
```
|
||||
|
||||
If you need a different version of bevy you need to use a matching bevy_scriptum
|
||||
version according to the [bevy support matrix](../bevy_support_matrix.md)
|
||||
|
||||
Ruby also needs dynamic symbol resolution and since `bevy_scriptum` links Ruby
|
||||
statically the following `build.rs` file is needed to be present in project
|
||||
root directory.
|
||||
|
||||
```rust
|
||||
fn main() {
|
||||
println!("cargo:rustc-link-arg=-rdynamic");
|
||||
}
|
||||
```
|
||||
83
book/src/ruby/interacting_with_bevy.md
Normal file
83
book/src/ruby/interacting_with_bevy.md
Normal file
|
|
@ -0,0 +1,83 @@
|
|||
# Interacting with bevy in callbacks
|
||||
|
||||
Every registered function is also just a regular Bevy system.
|
||||
|
||||
That allows you to do anything you would do in a Bevy system.
|
||||
|
||||
You could for example create a callback system function that prints names
|
||||
of all entities with `Player` component.
|
||||
|
||||
```rust,no_run
|
||||
# extern crate bevy;
|
||||
# extern crate bevy_ecs;
|
||||
# extern crate bevy_scriptum;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::ruby::prelude::*;
|
||||
|
||||
#[derive(Component)]
|
||||
struct Player;
|
||||
|
||||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_scripting::<RubyRuntime>(|runtime| {
|
||||
runtime.add_function(
|
||||
String::from("print_player_names"),
|
||||
|players: Query<&Name, With<Player>>| {
|
||||
for player in &players {
|
||||
println!("player name: {}", player);
|
||||
}
|
||||
},
|
||||
);
|
||||
})
|
||||
.run();
|
||||
}
|
||||
```
|
||||
|
||||
In script:
|
||||
|
||||
```ruby
|
||||
print_player_names
|
||||
```
|
||||
|
||||
You can use functions that interact with Bevy entities and resources and
|
||||
take arguments at the same time. It could be used for example to mutate a
|
||||
component.
|
||||
|
||||
```rust,no_run
|
||||
# extern crate bevy;
|
||||
# extern crate bevy_ecs;
|
||||
# extern crate bevy_scriptum;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::ruby::prelude::*;
|
||||
|
||||
#[derive(Component)]
|
||||
struct Player {
|
||||
health: i32
|
||||
}
|
||||
|
||||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_scripting::<RubyRuntime>(|runtime| {
|
||||
runtime.add_function(
|
||||
String::from("hurt_player"),
|
||||
|In((hit_value,)): In<(i32,)>, mut players: Query<&mut Player>| {
|
||||
let mut player = players.single_mut().unwrap();
|
||||
player.health -= hit_value;
|
||||
},
|
||||
);
|
||||
})
|
||||
.run();
|
||||
}
|
||||
```
|
||||
|
||||
And it could be called in script like:
|
||||
|
||||
```ruby
|
||||
hurt_player(5)
|
||||
```
|
||||
4
book/src/ruby/ruby.md
Normal file
4
book/src/ruby/ruby.md
Normal file
|
|
@ -0,0 +1,4 @@
|
|||
# Ruby
|
||||
|
||||
This chapter demonstrates how to work with bevy_scriptum when using Ruby language runtime.
|
||||
Ruby is currently only supported on Linux.
|
||||
42
book/src/ruby/spawning_scripts.md
Normal file
42
book/src/ruby/spawning_scripts.md
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
# Spawning scripts
|
||||
|
||||
To spawn a Ruby script you will need to get a handle to a script asset using
|
||||
bevy's `AssetServer`.
|
||||
|
||||
```rust
|
||||
# extern crate bevy;
|
||||
# extern crate bevy_scriptum;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::ruby::prelude::*;
|
||||
|
||||
fn my_spawner(mut commands: Commands, assets_server: Res<AssetServer>) {
|
||||
commands.spawn(Script::<RubyScript>::new(
|
||||
assets_server.load("my_script.rb"),
|
||||
));
|
||||
}
|
||||
```
|
||||
|
||||
After they scripts have been evaled by bevy_scriptum, the entities that they've
|
||||
been attached to will get the `Script::<RubyScript>` component stripped and instead
|
||||
```RubyScriptData``` component will be attached.
|
||||
|
||||
So to query scipted entities you could do something like:
|
||||
|
||||
```rust
|
||||
# extern crate bevy;
|
||||
# extern crate bevy_scriptum;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::ruby::prelude::*;
|
||||
|
||||
fn my_system(
|
||||
mut scripted_entities: Query<(Entity, &mut RubyScriptData)>,
|
||||
) {
|
||||
for (entity, mut script_data) in &mut scripted_entities {
|
||||
// do something with scripted entities
|
||||
}
|
||||
}
|
||||
```
|
||||
|
|
@ -2,25 +2,25 @@
|
|||
|
||||
## 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`
|
||||
|
||||
```
|
||||
bevy = { version = "0.13", features = ["file_watcher"] }
|
||||
```toml
|
||||
bevy = { version = "0.16", features = ["file_watcher"] }
|
||||
```
|
||||
|
||||
## Init-teardown pattern for game development
|
||||
## Init-teardown pattern
|
||||
|
||||
It is useful to structure your game in a way that would allow making changes to
|
||||
the scripting code without restarting the game.
|
||||
It is useful to structure your application in a way that would allow making changes to
|
||||
the scripting code without restarting the application.
|
||||
|
||||
A useful pattern is to hava three functions "init", "update" and "teardown".
|
||||
|
||||
- "init" function will take care of starting the game(spawning the player, the level etc)
|
||||
- "init" function will take care of starting the application(spawning the player, the level etc)
|
||||
|
||||
- "update" function will run the main game logic
|
||||
- "update" function will run the main application logic
|
||||
|
||||
- "teardown" function will despawn all the entities so game starts at fresh state.
|
||||
- "teardown" function will despawn all the entities so application starts at fresh state.
|
||||
|
||||
This pattern is very easy to implement in bevy_scriptum. All you need is to define all needed functions
|
||||
in script:
|
||||
|
|
@ -35,7 +35,7 @@ local function init()
|
|||
player.entity = spawn_player()
|
||||
end
|
||||
|
||||
-- game logic here, should be called in a bevy system using call_fn
|
||||
-- application logic here, should be called in a bevy system using call_fn
|
||||
local function update()
|
||||
(...)
|
||||
end
|
||||
|
|
@ -45,7 +45,7 @@ local function teardown()
|
|||
despawn(player.entity)
|
||||
end
|
||||
|
||||
-- call init to start the game, this will be called on each file-watcher script
|
||||
-- call init to start the application, this will be called on each file-watcher script
|
||||
-- reload
|
||||
init()
|
||||
```
|
||||
|
|
@ -53,6 +53,9 @@ init()
|
|||
The function calls can be implemented on Rust side the following way:
|
||||
|
||||
```rust
|
||||
# extern crate bevy;
|
||||
# extern crate bevy_scriptum;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::lua::prelude::*;
|
||||
|
|
@ -92,13 +95,14 @@ fn teardown(
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
```
|
||||
|
||||
And to tie this all together we do the following:
|
||||
|
||||
```rust
|
||||
```rust,no_run
|
||||
# extern crate bevy;
|
||||
# extern crate bevy_scriptum;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::lua::prelude::*;
|
||||
|
|
@ -116,24 +120,25 @@ fn main() {
|
|||
.run();
|
||||
}
|
||||
|
||||
fn init() {} // Implemented elsewhere
|
||||
fn update() {} // Implemented elsewhere
|
||||
fn despawn() {} // Implemented elsewhere
|
||||
fn teardown() {} // Implemented elsewhere
|
||||
fn spawn_player() {} // Implemented elsewhere
|
||||
# fn init() {}
|
||||
# fn update() {}
|
||||
# fn despawn() {}
|
||||
# fn teardown() {}
|
||||
# fn spawn_player() {}
|
||||
```
|
||||
|
||||
`despawn` can be implemented as:
|
||||
|
||||
```rust
|
||||
# extern crate bevy;
|
||||
# extern crate bevy_scriptum;
|
||||
|
||||
use bevy::prelude::*;
|
||||
use bevy_scriptum::runtimes::lua::prelude::*;
|
||||
|
||||
fn despawn(In((entity,)): In<(BevyEntity,)>, mut commands: Commands) {
|
||||
commands.entity(entity.0).despawn();
|
||||
}
|
||||
|
||||
fn main() {} // Implemented elsewhere
|
||||
```
|
||||
|
||||
Implementation of `spawn_player` has been left out as an exercise for the reader.
|
||||
|
|
|
|||
8
build.rs
Normal file
8
build.rs
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
fn main() {
|
||||
#[cfg(feature = "ruby")]
|
||||
{
|
||||
println!("cargo:rustc-link-arg=-rdynamic");
|
||||
println!("cargo:rustc-link-arg=-lz");
|
||||
println!("cargo:rustc-link-lib=z");
|
||||
}
|
||||
}
|
||||
BIN
demo.gif
Normal file
BIN
demo.gif
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 4.7 MiB |
|
|
@ -1,32 +1,15 @@
|
|||
use bevy::{app::AppExit, ecs::event::ManualEventReader, prelude::*};
|
||||
use bevy::{app::AppExit, prelude::*};
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::lua::prelude::*;
|
||||
|
||||
fn main() {
|
||||
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_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.send(AppExit);
|
||||
exit.write(AppExit::Success);
|
||||
});
|
||||
})
|
||||
.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| {
|
||||
builder.add_function(
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -1,24 +1,17 @@
|
|||
use bevy::{app::AppExit, ecs::event::ManualEventReader, prelude::*};
|
||||
use bevy::{app::AppExit, prelude::*};
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::lua::prelude::*;
|
||||
|
||||
fn main() {
|
||||
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 application
|
||||
// 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();
|
||||
if let Some(exit) = app.should_exit() {
|
||||
return exit;
|
||||
}
|
||||
}
|
||||
})
|
||||
.add_plugins(DefaultPlugins)
|
||||
|
|
@ -45,6 +38,6 @@ fn print_entity_names_and_quit(query: Query<&Name>, mut exit: EventWriter<AppExi
|
|||
for e in &query {
|
||||
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::runtimes::rhai::prelude::*;
|
||||
|
||||
fn main() {
|
||||
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_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.send(AppExit);
|
||||
exit.write(AppExit::Success);
|
||||
});
|
||||
})
|
||||
.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| {
|
||||
builder.add_function(
|
||||
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)
|
||||
|
|
|
|||
|
|
@ -1,24 +1,17 @@
|
|||
use bevy::{app::AppExit, ecs::event::ManualEventReader, prelude::*};
|
||||
use bevy::{app::AppExit, prelude::*};
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::rhai::prelude::*;
|
||||
|
||||
fn main() {
|
||||
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 application
|
||||
// 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();
|
||||
if let Some(exit) = app.should_exit() {
|
||||
return exit;
|
||||
}
|
||||
}
|
||||
})
|
||||
.add_plugins(DefaultPlugins)
|
||||
|
|
@ -45,6 +38,6 @@ fn print_entity_names_and_quit(query: Query<&Name>, mut exit: EventWriter<AppExi
|
|||
for e in &query {
|
||||
println!("{}", e);
|
||||
}
|
||||
exit.send(AppExit);
|
||||
exit.write(AppExit::Success);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
33
examples/ruby/call_function_from_rust.rs
Normal file
33
examples/ruby/call_function_from_rust.rs
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
use bevy::{app::AppExit, prelude::*};
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::ruby::prelude::*;
|
||||
|
||||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_systems(Startup, startup)
|
||||
.add_systems(Update, call_ruby_on_update_from_rust)
|
||||
.add_scripting::<RubyRuntime>(|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::<RubyScript>::new(
|
||||
assets_server.load("examples/ruby/call_function_from_rust.rb"),
|
||||
));
|
||||
}
|
||||
|
||||
fn call_ruby_on_update_from_rust(
|
||||
mut scripted_entities: Query<(Entity, &mut RubyScriptData)>,
|
||||
scripting_runtime: ResMut<RubyRuntime>,
|
||||
) {
|
||||
for (entity, mut script_data) in &mut scripted_entities {
|
||||
scripting_runtime
|
||||
.call_fn("on_update", &mut script_data, entity, ())
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
25
examples/ruby/current_entity.rs
Normal file
25
examples/ruby/current_entity.rs
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
use bevy::prelude::*;
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::ruby::prelude::*;
|
||||
|
||||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_scripting::<RubyRuntime>(|runtime| {
|
||||
runtime.add_function(
|
||||
String::from("get_name"),
|
||||
|In((BevyEntity(entity),)): In<(BevyEntity,)>, names: Query<&Name>| {
|
||||
names.get(entity).unwrap().to_string()
|
||||
},
|
||||
);
|
||||
})
|
||||
.add_systems(Startup, startup)
|
||||
.run();
|
||||
}
|
||||
|
||||
fn startup(mut commands: Commands, assets_server: Res<AssetServer>) {
|
||||
commands.spawn((
|
||||
Name::from("MyEntityName"),
|
||||
Script::<RubyScript>::new(assets_server.load("examples/ruby/current_entity.rb")),
|
||||
));
|
||||
}
|
||||
54
examples/ruby/custom_type.rs
Normal file
54
examples/ruby/custom_type.rs
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
use bevy::prelude::*;
|
||||
use bevy_scriptum::ScriptingError;
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::ruby::magnus;
|
||||
use bevy_scriptum::runtimes::ruby::magnus::Module as _;
|
||||
use bevy_scriptum::runtimes::ruby::magnus::Object as _;
|
||||
use bevy_scriptum::runtimes::ruby::prelude::*;
|
||||
|
||||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_scripting::<RubyRuntime>(|runtime| {
|
||||
runtime.add_function(String::from("hello_bevy"), || {
|
||||
println!("hello bevy, called from script");
|
||||
});
|
||||
})
|
||||
.add_systems(Startup, startup)
|
||||
.run();
|
||||
}
|
||||
|
||||
#[magnus::wrap(class = "MyType")]
|
||||
struct MyType {
|
||||
my_field: u32,
|
||||
}
|
||||
|
||||
impl MyType {
|
||||
fn new() -> Self {
|
||||
Self { my_field: 42 }
|
||||
}
|
||||
|
||||
fn my_method(&self) -> u32 {
|
||||
self.my_field
|
||||
}
|
||||
}
|
||||
|
||||
fn startup(
|
||||
mut commands: Commands,
|
||||
scripting_runtime: ResMut<RubyRuntime>,
|
||||
assets_server: Res<AssetServer>,
|
||||
) {
|
||||
scripting_runtime
|
||||
.with_engine_send(|ruby| {
|
||||
let my_type = ruby.define_class("MyType", ruby.class_object())?;
|
||||
my_type.define_singleton_method("new", magnus::function!(MyType::new, 0))?;
|
||||
my_type.define_method("my_method", magnus::method!(MyType::my_method, 0))?;
|
||||
|
||||
Ok::<(), ScriptingError>(())
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
commands.spawn(Script::<RubyScript>::new(
|
||||
assets_server.load("examples/ruby/custom_type.rb"),
|
||||
));
|
||||
}
|
||||
33
examples/ruby/ecs.rs
Normal file
33
examples/ruby/ecs.rs
Normal file
|
|
@ -0,0 +1,33 @@
|
|||
use bevy::prelude::*;
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::ruby::prelude::*;
|
||||
|
||||
#[derive(Component)]
|
||||
struct Player;
|
||||
|
||||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_scripting::<RubyRuntime>(|runtime| {
|
||||
runtime.add_function(
|
||||
String::from("print_player_names"),
|
||||
|players: Query<&Name, With<Player>>| {
|
||||
for player in &players {
|
||||
println!("player name: {}", player);
|
||||
}
|
||||
},
|
||||
);
|
||||
})
|
||||
.add_systems(Startup, startup)
|
||||
.run();
|
||||
}
|
||||
|
||||
fn startup(mut commands: Commands, assets_server: Res<AssetServer>) {
|
||||
commands.spawn((Player, Name::new("John")));
|
||||
commands.spawn((Player, Name::new("Mary")));
|
||||
commands.spawn((Player, Name::new("Alice")));
|
||||
|
||||
commands.spawn(Script::<RubyScript>::new(
|
||||
assets_server.load("examples/ruby/ecs.rb"),
|
||||
));
|
||||
}
|
||||
17
examples/ruby/entity_variable.rs
Normal file
17
examples/ruby/entity_variable.rs
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
use bevy::prelude::*;
|
||||
use bevy_scriptum::runtimes::ruby::prelude::*;
|
||||
use bevy_scriptum::{prelude::*, BuildScriptingRuntime};
|
||||
|
||||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_scripting::<RubyRuntime>(|_| {})
|
||||
.add_systems(Startup, startup)
|
||||
.run();
|
||||
}
|
||||
|
||||
fn startup(mut commands: Commands, assets_server: Res<AssetServer>) {
|
||||
commands.spawn(Script::<RubyScript>::new(
|
||||
assets_server.load("examples/ruby/entity_variable.rb"),
|
||||
));
|
||||
}
|
||||
52
examples/ruby/function_params.rs
Normal file
52
examples/ruby/function_params.rs
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
use bevy::prelude::*;
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::ruby::{RArray, prelude::*};
|
||||
|
||||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_scripting::<RubyRuntime>(|runtime| {
|
||||
runtime
|
||||
.add_function(String::from("fun_without_params"), || {
|
||||
println!("called without params");
|
||||
})
|
||||
.add_function(
|
||||
String::from("fun_with_string_param"),
|
||||
|In((x,)): In<(String,)>| {
|
||||
println!("called with string: '{}'", x);
|
||||
},
|
||||
)
|
||||
.add_function(
|
||||
String::from("fun_with_i64_param"),
|
||||
|In((x,)): In<(i64,)>| {
|
||||
println!("called with i64: {}", x);
|
||||
},
|
||||
)
|
||||
.add_function(
|
||||
String::from("fun_with_multiple_params"),
|
||||
|In((x, y)): In<(i64, String)>| {
|
||||
println!("called with i64: {} and string: '{}'", x, y);
|
||||
},
|
||||
)
|
||||
.add_function(
|
||||
String::from("fun_with_i64_and_array_param"),
|
||||
|In((x, y)): In<(i64, RArray)>, runtime: Res<RubyRuntime>| {
|
||||
runtime.with_engine_send(move |ruby| {
|
||||
println!(
|
||||
"called with i64: {} and dynamically typed array: {:?}",
|
||||
x,
|
||||
ruby.get_inner(y.0)
|
||||
);
|
||||
});
|
||||
},
|
||||
);
|
||||
})
|
||||
.add_systems(Startup, startup)
|
||||
.run();
|
||||
}
|
||||
|
||||
fn startup(mut commands: Commands, assets_server: Res<AssetServer>) {
|
||||
commands.spawn(Script::<RubyScript>::new(
|
||||
assets_server.load("examples/ruby/function_params.rb"),
|
||||
));
|
||||
}
|
||||
42
examples/ruby/function_return_value.rs
Normal file
42
examples/ruby/function_return_value.rs
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
use bevy::{app::AppExit, prelude::*};
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::ruby::prelude::*;
|
||||
use magnus::TryConvert;
|
||||
use magnus::value::InnerValue;
|
||||
|
||||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_systems(Startup, startup)
|
||||
.add_systems(Update, call_lua_on_update_from_rust)
|
||||
.add_scripting::<RubyRuntime>(|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::<RubyScript>::new(
|
||||
assets_server.load("examples/ruby/function_return_value.rb"),
|
||||
));
|
||||
}
|
||||
|
||||
fn call_lua_on_update_from_rust(
|
||||
mut scripted_entities: Query<(Entity, &mut RubyScriptData)>,
|
||||
scripting_runtime: ResMut<RubyRuntime>,
|
||||
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(|ruby| {
|
||||
let val: i32 = TryConvert::try_convert(val.get_inner_with(ruby)).unwrap();
|
||||
println!("script returned: {}", val);
|
||||
});
|
||||
exit.write(AppExit::Success);
|
||||
}
|
||||
}
|
||||
21
examples/ruby/hello_world.rs
Normal file
21
examples/ruby/hello_world.rs
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
use bevy::prelude::*;
|
||||
use bevy_scriptum::prelude::*;
|
||||
use bevy_scriptum::runtimes::ruby::prelude::*;
|
||||
|
||||
fn main() {
|
||||
App::new()
|
||||
.add_plugins(DefaultPlugins)
|
||||
.add_scripting::<RubyRuntime>(|runtime| {
|
||||
runtime.add_function(String::from("hello_bevy"), || {
|
||||
println!("hello bevy, called from script");
|
||||
});
|
||||
})
|
||||
.add_systems(Startup, startup)
|
||||
.run();
|
||||
}
|
||||
|
||||
fn startup(mut commands: Commands, assets_server: Res<AssetServer>) {
|
||||
commands.spawn(Script::<RubyScript>::new(
|
||||
assets_server.load("examples/ruby/hello_world.rb"),
|
||||
));
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue