Coder Social home page Coder Social logo

bevy_mod_scripting's People

Contributors

a-soulspark avatar baby-steve avatar connorbp avatar johnthecoolingfan avatar jrobsonchase avatar katk0smos avatar laserwitch avatar makspll avatar mistrustfully avatar opfromthestart avatar zwazel avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

bevy_mod_scripting's Issues

Serializing script variables

Two questions:

  1. Can you serialize scripts alongside the entities in scenes?
  2. Can you set variables in the script and serialize those as well?

When I work with scripts in Godot, I attach a script to a node, then export a variable from that script so that that particular script instance has a unique value. While there is no editor, is it possible to encode this data in a scene?

Bevy 0.12

I saw #62 for bevy 0.11 support, and it looks like bevy 0.12 was released a couple of weeks ago. I'm starting a new project where I'll lock into a certain version of bevy.

Given the last release in May covered bevy 0.10, should I leverage bevy 0.11 or bevy 0.12 in anticipation for the next release of this crate? I'm brand new, so I don't (and shouldn't) have much weight in the decision here. Just want to know if there are plans/expectations for one version over the other! ๐Ÿ˜„

I'd toss this into a discussion instead of an issue, but looks like discussions aren't enabled for this repository. So apologies if this clutters the issue section!

Rhai Bevy API

Now that the foundational work is done the Rhai API can be written as well, the work needed is as follows:

  • Rhai implementor in bevy_mod_scripting_derive which generates Rhai<Type> Wrappers similarly to the Lua implementor
  • Traits akin to LuaProxyable ToLuaProxy and FromLuaProxy
  • std implementations of primitives + Option and Vec for the traits at least

Customizable error handling

Right now errors are printed to the standard output,

It would be preferable to pass errors onto the user for further handlling.

For example, printing lua errors to an in game console

Benchmarking + Optimisation

The crate is very new, and I am not that familiar with Rust + Bevy,

Baseline benchmarks should be written, and code optimised.

A good start would be, not running scripts which do not have any callbacks corresponding to the set of events fired this frame.

Bevy 0.10 compatibility

Hey there, love the crate. Bevy 0.10 does away with stages in favour of system sets - is there any plan to update this library to support this?

Improved proxy generating macros

Current macros are very ugly, written before I had a full grasp of the capabilities of rust meta-programming,

I intend to make things like these possible:

#[derive(ScriptProxy, Reflect)]
#[proxy(languages("on_feature(lua)"))]
#[functions[

    #[lua(MutatingMetaMethod)]
    fn basd(mut self) {
            
    }

    #[lua(MetaMethod)]
    fn asd(self);

    #[lua(Function)]
    fn basda(self);
]]
pub struct Lol {}

Examples need better explanation

I'm reading examples to understand how exactly can I use this crate for my project. So far it wasn't very easy to understand, I had to go back and forth: exampels, script assets, API docs. And also I don't understand some comments completely, like this one. It looks like it's out of place.

This is why I think exampels need improvements to the explanation comments and more such comments.

add_default_component example?

I've been trying to use add_default_component from lua, and despite get_type_by_name returning apparently correct data, and the type definitely being a component, the add errors out claiming there's no component. I'm not sure if this is on my end or the crates end? If it's on my end I could use an example of how to do it right.

Seperate out languages into their own crates

To promote compartmentalisation, Rhai and Lua should be in their own crates in this repo, they should also be opt-in instead of provided by default to speed up compilation when they are not necessary

Docs.rs fails to build on latest version

Currently latest version availableon docs.rs is 0.1.2. All other versions fail to build with an error that is caused by some required features not being enabled.

docs.rs build log link

Also duplicating the full text here:

# rustc version
rustc 1.68.0-nightly (0b90256ad 2023-01-13)
# docs.rs version
docsrs 0.6.0 (19c77a92 2023-01-08)

# build log
[INFO] running `Command { std: "docker" "create" "-v" "/home/cratesfyi/workspace/builds/bevy_mod_scripting-0.2.2/target:/opt/rustwide/target:rw,Z" "-v" "/home/cratesfyi/workspace/builds/bevy_mod_scripting-0.2.2/source:/opt/rustwide/workdir:ro,Z" "-v" "/home/cratesfyi/workspace/cargo-home:/opt/rustwide/cargo-home:ro,Z" "-v" "/home/cratesfyi/workspace/rustup-home:/opt/rustwide/rustup-home:ro,Z" "-e" "SOURCE_DIR=/opt/rustwide/workdir" "-e" "CARGO_TARGET_DIR=/opt/rustwide/target" "-e" "DOCS_RS=1" "-e" "CARGO_HOME=/opt/rustwide/cargo-home" "-e" "RUSTUP_HOME=/opt/rustwide/rustup-home" "-w" "/opt/rustwide/workdir" "-m" "3221225472" "--cpus" "3" "--user" "1001:1001" "--network" "none" "ghcr.io/rust-lang/crates-build-env/linux@sha256:9042d5c95763f71f7b0904716b98ccadf9fc47b0f382ee962aaaed2ac70c9b8d" "/opt/rustwide/cargo-home/bin/cargo" "+nightly" "rustdoc" "--lib" "-Zrustdoc-map" "--features" "lua rhai lua_script_api rhai_script_api teal" "-Z" "unstable-options" "--config" "build.rustdocflags=[\"-Z\", \"unstable-options\", \"--emit=invocation-specific\", \"--resource-suffix\", \"-20230113-1.68.0-nightly-0b90256ad\", \"--static-root-path\", \"/-/rustdoc.static/\", \"--cap-lints\", \"warn\", \"--disable-per-crate-search\", \"--extern-html-root-takes-precedence\"]" "--offline" "-Zunstable-options" "--config=doc.extern-map.registries.crates-io=\"https://docs.rs/{pkg_name}/{version}/x86_64-unknown-linux-gnu\"" "-Zrustdoc-scrape-examples" "-j3" "--target" "x86_64-unknown-linux-gnu", kill_on_drop: false }`
[INFO] [stdout] 174db56665a4e7c628ba6a7b5cf800ee417f0556e9d9af23b34586d031af6fc0
[INFO] [stderr] WARNING: Your kernel does not support swap limit capabilities or the cgroup is not mounted. Memory limited without swap.
[INFO] running `Command { std: "docker" "start" "-a" "174db56665a4e7c628ba6a7b5cf800ee417f0556e9d9af23b34586d031af6fc0", kill_on_drop: false }`
[INFO] [stderr] warning: Rustdoc did not scrape the following examples because they require dev-dependencies: console_integration_lua, console_integration_rhai, complex_game_loop_lua, game_of_life_lua, game_of_life_rhai, event_recipients_lua, coroutines_lua, documentation_gen_lua, bevy_api_lua, bevy_api_rhai, wrappers
[INFO] [stderr]     If you want Rustdoc to scrape these examples, then add `doc-scrape-examples = true`
[INFO] [stderr]     to the [[example]] target configuration of at least one example.
[INFO] [stderr] warning: Target filter specified, but no targets matched. This is a no-op
[INFO] [stderr]     Checking bevy_ui v0.9.1
[INFO] [stderr]    Compiling mlua v0.8.7
[INFO] [stderr]    Compiling rustls v0.20.8
[INFO] [stderr] error: You must enable one of the features: lua54, lua53, lua52, lua51, luajit, luajit52, luau
[INFO] [stderr]   --> /opt/rustwide/cargo-home/registry/src/github.com-1ecc6299db9ec823/mlua-0.8.7/build/main.rs:52:5
[INFO] [stderr]    |
[INFO] [stderr] 52 | /     compile_error!(
[INFO] [stderr] 53 | |         "You must enable one of the features: lua54, lua53, lua52, lua51, luajit, luajit52, luau"
[INFO] [stderr] 54 | |     );
[INFO] [stderr]    | |_____^
[INFO] [stderr] 
[INFO] [stderr] error: could not compile `mlua` due to previous error
[INFO] [stderr] warning: build failed, waiting for other jobs to finish...
[INFO] running `Command { std: "docker" "inspect" "174db56665a4e7c628ba6a7b5cf800ee417f0556e9d9af23b34586d031af6fc0", kill_on_drop: false }`
[INFO] running `Command { std: "docker" "rm" "-f" "174db56665a4e7c628ba6a7b5cf800ee417f0556e9d9af23b34586d031af6fc0", kill_on_drop: false }`
[INFO] [stdout] 174db56665a4e7c628ba6a7b5cf800ee417f0556e9d9af23b34586d031af6fc0

Can't run wrappers example

I've cloned the repository locally and tried to run the wrappers example from it with cargo run --example wrappers --features="lua lua54 lua_script_api". I get this result after the initial startup info line

ERROR bevy_mod_scripting_lua: Runtime error in script `script.lua` callback error
stack traceback:
        [C]: in field 'make_ref_to_my_resource'
        [string "script.lua"]:3: in function 'once'
caused by: error converting Lua nil to userdata
After script run: MyThing {
    usize: 420,
    string: "I live in the bevy world, you can't touch me!",
}

I've tried this test on both the main branch and the 0.11 branch with the same result

If I read the code correctly, I believe it's supposed to error in the second script run, but not the first. It appears that the issue comes from

fn "make_ref_to_my_resource" => |ctx,()| {
    let globals = ctx.globals();
    let lua_world : LuaWorld = globals.("world")?; //This lineA

I changed it to

let lua_world_o = globals.get("world");
info!("{:#?}",lua_world_o);
let lua_world  :LuaWorld = lua_world_o.unwrap();

and got

wrappers: 
INFO wrappers: Err(
    FromLuaConversionError {
        from: "nil",
        to: "userdata",
        message: None,
    },
)
thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: FromLuaConversionError { from: "nil", to: "userdata", message: None }', examples/wrappers.rs:69:52
)

Getting access to the world like this is really the thing I need most out of the crate right now, so any help would be very appreciated.

gazebo_ros_2Dmap_plugin

Hey,

sorry to bother you. I found you issue post (2021): marinaKollmitz/gazebo_ros_2Dmap_plugin#11

Could you remeber how to use the plugin?

I tried it with simple turtlebot3_world map but it doesn't work.

  1. I include the plugin into my .world file
  2. I started tb3: roslaunch turtlebot3_gazebo turtlebot3_world.launch
  3. I call the service rosservice call /gazebo_2Dmap_plugin/generate_map (After i call the servicei getting the following message: Occupancy Map generation completed )
  4. Lastly i saved the map: rosrun map_server map_saver -f test /map:=/map2d

After step 4, i got 2 files:

  1. test.yaml
  2. test.pgm

But the pgm is not the desire grid map of the turtlbot3 world: https://ibb.co/wNB2HdN

I really appreciate your time. Thank you.

console_integration outdate

The example file for console integration seem out date. I can get part of it working. There not much example of set up the Cargo.toml.

Try work on windows.

[dependencies]
bevy = "0.9"
clap = "4.0.32"
bevy_console = "0.6.0"
bevy_mod_scripting = {version = "0.2.2", features =["lua","lua54"]}

Found the bevy_console has change some set up.

#[derive(Parser, ConsoleCommand)]
#[command(name = "run_script")]
//  no method named `get_world` found for reference `&bevy_mod_scripting::prelude::Lua` in the current scope
let world = ctx.get_world()?
//method not found in `&bevy_mod_scripting::prelude::Lua`
//mismatched types
events.send(PrintConsoleLine { line: msg });
//expected struct `clap::builder::StyledStr`, found struct `std::string::String`

There are some area can't figure since wanted to keep it simple. Still learning how to get part example working. Not sure how to config them right.

error compiling bevy_script_api

I'm trying to get a working example of this running and have found it to be quite difficult, the examples are quite difficult to understand.

also running into this error when I generate a blank project with bevy + bevy_mod_scripting:

error[E0308]: `?` operator has incompatible types
    --> /Users/xx/.cargo/registry/src/index.crates.io-6f17d22bba15001f/bevy_script_api-0.3.0/src/generated.rs:4266:17
     |
4266 |     #[languages(on_feature(lua))]
     |                 ^^^^^^^^^^^^^^^ expected `BVec4`, found `BVec4A`
     |
     = note: `?` operator cannot convert from `BVec4A` to `BVec4`
     = note: this error originates in the macro `impl_lua_newtype` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0308]: mismatched types
    --> /Users/xx/.cargo/registry/src/index.crates.io-6f17d22bba15001f/bevy_script_api-0.3.0/src/generated.rs:4266:17
     |
4266 |     #[languages(on_feature(lua))]
     |                 ^^^^^^^^^^^^^^^
     |                 |
     |                 expected `BVec4A`, found `BVec4`
     |                 arguments to this function are incorrect
     |
note: associated function defined here
    --> /Users/xx/.cargo/registry/src/index.crates.io-6f17d22bba15001f/bevy_script_api-0.3.0/src/wrappers.rs:38:16
     |
38   |         pub fn new(b: $type_) -> Self {
     |                ^^^ ---------
     |
    ::: /Users/xx/.cargo/registry/src/index.crates.io-6f17d22bba15001f/bevy_script_api-0.3.0/src/generated.rs:4770:17
     |
4770 |     #[languages(on_feature(lua))]
     |                 --------------- in this macro invocation
     = note: this error originates in the macro `impl_lua_newtype` (in Nightly builds, run with -Z macro-backtrace for more info)

For more information about this error, try `rustc --explain E0308`.
error: could not compile `bevy_script_api` (lib) due to 2 previous errors

Compiling on the latest stable version rustc 1.70.0 (90c541806 2023-05-31) and I tried on nightly.

Prettify lua documentation

Tealr now supports custom templating in documentation generation. With that newfound power we should upgrade the template

lua require not loading from assets dir

In testing, using require "common" with the require feature gets me the output

2023-08-27T22:50:30.267464Z  WARN bevy_mod_scripting_core::hosts: Error in loading script AssetPath {
    path: "scripts/1.lua",
    label: None,
}:
Failed to load script asset for `AssetPath {
    path: "scripts/1.lua",
    label: None,
}` runtime error: [string "AssetPath {..."]:1: module 'common' not found:
        no field package.preload['common']
        no file 'D:\Code\luademo\target\debug\lua\common.lua'
        no file 'D:\Code\luademo\target\debug\lua\common\init.lua'
        no file 'D:\Code\luademo\target\debug\common.lua'
        no file 'D:\Code\luademo\target\debug\common\init.lua'
        no file 'D:\Code\luademo\target\debug\..\share\lua\5.4\common.lua'
        no file 'D:\Code\luademo\target\debug\..\share\lua\5.4\common\init.lua'
        no file '.\common.lua'
        no file '.\common\init.lua'
        no file 'D:\Code\luademo\target\debug\common.dll'
        no file 'D:\Code\luademo\target\debug\..\lib\lua\5.4\common.dll'
        no file 'D:\Code\luademo\target\debug\loadall.dll'
        no file '.\common.dll'
stack traceback:
        [C]: in ?
        [C]: in function 'require'
        [string "AssetPath {..."]:1: in main chunk

common.lua is in this case sitting in my project's assets\scripts directory right next to my other lua files, it's actually being loaded by bevy's asset server even. To get it to load I must use require "assets/scripts/common" (running via cargo from the project root dir)

Ultimately, for my ends I think I want require to load from bevy's asset server somehow as part of a sandboxing effort. That feels potentially out of scope as a core feature, but it seems like this crate should probably at the least add the assets directory to the searcher paths.

Can't compile with mlua anymore

I started towards trying to do my own update to bevy 0.12(haven't not noticed the issue here recently that mentioned it being possibly coming soon), and I've found that I can't build from the repo at all now when I use the lua-api and lua54 features. I get a bunch of errors from tealr macros. tealr_derive::TypeName, ToTypename, IntoLua... I'm thinking there's been some poorly-versioned breaking changes up stream but haven't yet found a correct combination of version specifications to get back to buildable.

fix bevy_api_gen regression

A breaking change happened either in rustdoc --json or in the bevy docs which removed import paths for many items, as well as their trait implementations, meaning make generate_api currently breaks.

Rhai Events are overriding each other

Hi!
Could be that I completely misunderstand events in this crate.
I've implemented a function that allows me to spawn a mod.
So via script, i can just spawn other mods.
and those spawned mods then get called the "on_init" function in their script!

problem is, as soon as there is more than just one at the same time, only one of them gets the init method called.

same thing for the Update call.
I can't use Recipients::All because i need to do some additional checks before calling on_update on that entity, so i use Recipient::Entity, and loop through all of them. and here the same problem!

Am I misunderstanding something or is this a "design flaw"?
Noticed that this is a bug in the rhai implementation. Lua did not behave Like this.

More high level documentation

I want to expose sort of a plugin system for my bevy app.
and i don't want different plugins to be using the same lua vm for four reasons:

  1. mix up of different variable names and their data (atleast in global scope) leading to different weird (or even malicious) errors.
  2. security. one plugin might require some kind of api key and this should not be accessed by other plugins.
  3. one plugin might accidentally mess up the whole global table and cause others to go down with it.
  4. run different plugins in different lua instances concurrently when they are not interacting with any global bevy data.

so, when i create a LuaScriptCollection, i want it to have its own lua vm.

is this possible right now?

also, I am wondering there could be a small Architecture.md explaining at a high level how this works. I am not familiar with what the terms ScriptHost or ScriptCollection really mean in the abstract concept sense.

Incompatible types when compiling on Arm64

I am facing a similar set of errors to #61 with bevy 0.11.2 and bevy_mod_scripting commit 8bf3796 with the lua_script_api flag enabled

cargo run
    Updating git repository `https://github.com/makspll/bevy_mod_scripting`
   Compiling bevy_script_api v0.3.0 (https://github.com/makspll/bevy_mod_scripting?rev=8bf3796#8bf37962)
error[E0599]: no variant or associated item named `Pairs` found for enum `LuaMetaMethod` in the current scope
   --> /Users/videah/.cargo/git/checkouts/bevy_mod_scripting-66f82db9d3a19d6f/8bf3796/bevy_script_api/src/lua/std.rs:317:45
    |
317 |         methods.add_meta_method(MetaMethod::Pairs, |ctx, s, _: ()| {
    |                                             ^^^^^ variant or associated item not found in `LuaMetaMethod`

error[E0308]: `?` operator has incompatible types
    --> /Users/videah/.cargo/git/checkouts/bevy_mod_scripting-66f82db9d3a19d6f/8bf3796/bevy_script_api/src/generated.rs:4501:17
     |
4501 |     #[languages(on_feature(lua))]
     |                 ^^^^^^^^^^^^^^^ expected `BVec4`, found `BVec4A`
     |
     = note: `?` operator cannot convert from `BVec4A` to `BVec4`
     = note: this error originates in the macro `impl_lua_newtype` (in Nightly builds, run with -Z macro-backtrace for more info)

error[E0308]: mismatched types
    --> /Users/videah/.cargo/git/checkouts/bevy_mod_scripting-66f82db9d3a19d6f/8bf3796/bevy_script_api/src/generated.rs:4501:17
     |
4501 |     #[languages(on_feature(lua))]
     |                 ^^^^^^^^^^^^^^^
     |                 |
     |                 expected `BVec4A`, found `BVec4`
     |                 arguments to this function are incorrect
     |
note: associated function defined here
    --> /Users/videah/.cargo/git/checkouts/bevy_mod_scripting-66f82db9d3a19d6f/8bf3796/bevy_script_api/src/wrappers.rs:38:16
     |
38   |         pub fn new(b: $type_) -> Self {
     |                ^^^ ---------
     |
    ::: /Users/videah/.cargo/git/checkouts/bevy_mod_scripting-66f82db9d3a19d6f/8bf3796/bevy_script_api/src/generated.rs:5050:17
     |
5050 |     #[languages(on_feature(lua))]
     |                 --------------- in this macro invocation
     = note: this error originates in the macro `impl_lua_newtype` (in Nightly builds, run with -Z macro-backtrace for more info)

Some errors have detailed explanations: E0308, E0599.
For more information about an error, try `rustc --explain E0308`.
error: could not compile `bevy_script_api` (lib) due to 3 previous errors

My Cargo.toml looks like this:

[package]
name = "myrrh"
version = "0.1.0"
edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

# Enable a small amount of optimization in debug mode
[profile.dev]
opt-level = 1

# Enable high optimizations for dependencies (incl. Bevy), but not for our code:
[profile.dev.package."*"]
opt-level = 3

[dependencies]
bevy = { version = "0.11.2", features = ["dynamic_linking"] }
bevy_mod_scripting = { git = "https://github.com/makspll/bevy_mod_scripting", rev = "8bf3796", version = "0.3.0", features = ["luajit", "teal", "lua_script_api"] }

Event Recipients

Ability to send events to a subset of scripts, currently is not supported

Gluon Language Implementation for ScriptHost

I would like to implement a ScriptHost for Gluon.
Is there any contributing rules or conventions that I should be aware of?

Some information about Gluon:

Gluon is a small, statically-typed, functional programming language designed for application embedding.

How to turn a ReflectedValue into a specfic type?

Following scenario, i get a resource

let lobby_list_type = world.get_type_by_name("blablabla::LobbyListResource");
if world.has_resource(lobby_list_type) {
    let lobby_list = world.get_resource(lobby_list_type);
    print(`lobby list type: ${type_of(lobby_list)}, lobby list: ${lobby_list}`);
}

This resource looks like this:

#[derive(Resource, Reflect, Default, Clone)]
#[reflect(Resource)]
pub struct LobbyListResource(pub Vec<u64>);

Quite simple.
I now want to access the different lobbies from the vec, I figured out that I can just access them by indexing.

print(`lobby list: ${lobby_list[0]}`);

this works.
But I'd like to loop through them:

for lobby in lobby_list {
    print(`lobby: ${lobby}`);
}

Which gives me following error: Runtime error in script "script_name.rhai" For loop expects iterable type.
So I looked into Rhai and how you've implemented some things.
For example, I can use the api.build_type in the attach_api of an APIProvider, and register some functions as well as it being iterable:

#[derive(Resource, Reflect, Default, Clone)]
#[reflect(Resource)]
pub struct LobbyListResource(pub Vec<u64>);

impl IntoIterator for LobbyListResource {
    type Item = u64;

    type IntoIter = std::vec::IntoIter<Self::Item>;

    fn into_iter(self) -> Self::IntoIter {
        self.0.into_iter()
    }
}

impl CustomType for LobbyListResource {
    fn build(mut builder: rhai::TypeBuilder<Self>) {
        builder
            .with_name("LobbyListResource")
            .with_indexer_get(LobbyListResource::get_field).is_iterable();
    }
}

struct HandleLobbyApiProvider;

impl APIProvider for HandleLobbyApiProvider {
    type APITarget = Engine;
    type ScriptContext = RhaiContext;
    type DocTarget = RhaiDocFragment;

    fn attach_api(
        &mut self,
        api: &mut Self::APITarget,
    ) -> Result<(), bevy_mod_scripting::prelude::ScriptError> {
        api.build_type::<LobbyListResource>();

        Ok(())
    }
}

But that doesn't solve my problem, because the script only gets a ReflectedValue. So i'm wondering if there is a way for me to turn a ReflectedValue into a specific Type?

How to implement deferred dependency loading in bevy

Hello, first thank you for this great crate.

I am currently using your project to implement scripting support in a project using bevy. However, I got the following issue:

  • Scripts depend on each other in an unknown (or lets say cumbersome to maintain) way
  • All scripts are loaded buy an AssetIO override that maps the path to a path into a zip file

So in all loading, the asset server is involved - and that would include loading dependencies.
Now I got the the issue that e.g. a lua snippet wants to run

dofile '/some/path/to/a/script.lua'

and would require to be paused, until the resource is available and the string contents are injected. The lua engine used (Luajit) claims to be fully resumable, so it should be possible to yield across the language barriers, however that exactly is not working with the error:

attempt to yield across C-call boundary

Is there another approach I should take when lua wants to load a resource that involves async loading from the asset server?

How do I correctly despawn Entities with scripts?

I despawn an entity (recursively) that has a script attached to it. but the script still "exists" and receives the events.

I'm currently only working with the Rhai implementation, so idk if this is a general problem or not. but its definitely not what i expect it to work like XD

A bug in `generated.rs`

I get a compiler error due to a bug in generated.rs :

Compiling bevy_mod_scripting v0.1.1
error[E0283]: type annotations needed
    --> C:\Users\HP\.cargo\registry\src\mirrors.tuna.tsinghua.edu.cn-df7c3c540f42cdbd\bevy_mod_scripting-0.1.1\src\api\generated.rs:9197:39
     |
9197 |         instances.add_instance("Name".into(), tealr::mlu::UserDataProxy::<LuaName>::new)?;
     |                   ------------        ^^^^
     |                   required by a bound introduced by this call
     |
     = note: cannot satisfy `_: Into<Cow<'static, str>>`
note: required by a bound in `add_instance`
    --> C:\Users\HP\.cargo\registry\src\mirrors.tuna.tsinghua.edu.cn-df7c3c540f42cdbd\tealr-0.9.0-alpha3\src\mlu\teal_data_methods.rs:107:12
     |
107  |         P: Into<Cow<'static, str>>,
     |            ^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `add_instance`
help: try using a fully qualified path to specify the expected types
     |
9197 |         instances.add_instance(<&str as Into<T>>::into("Name"), tealr::mlu::UserDataProxy::<LuaName>::new)?;
     |                                ++++++++++++++++++++++++      ~

After I manually resplaced all instances.add_instance("xxx".into() , tealr::mlu::UserDataProxy::<LuaName>::new) with instances.add_instance("xxx", tealr::mlu::UserDataProxy::<LuaName>::new), it successfully complied.

Here are my dependencies:

[dependencies]
rand = "0.8.5"
bevy = { version = "0.8.0", features = ["dynamic"] }
bevy-inspector-egui = "0.13.0"
bevy_mod_scripting = { version = "0.1.1", features = ["lua54", "mlua_macros", "mlua_serialize", "unsafe_lua_modules"]}

WorldPointer is unsound

Like, really really unsound.

Paraphrasing dtonlnay, an API is unsound if it's possible to break its intended invariants in safe code.

WorldPointer's stated invariant is:

This pointer does not prevent dangling pointers, i.e. you must ensure the world is not dropped while any world pointers still exist, the world must also not change, from the moment a world pointer is created it must always point to the same world.

This isn't entirely correct, and is also incomplete and trivially broken in safe third-party code. The "you must ensure the world is not dropped while any world pointers still exist" bit implies that it's the pointed-to World that can't be dropped, while it's actually the mutable reference itself that determines the maximum lifetime of a WorldPointer. Where the World lives is entirely the purview of the bevy internals, and it may be moved around without warning, thus invalidating any previous references to it. Additionally, since the WorldPointer creates a second, sharable mutable reference to the World, it also needs to include the invariant that the original &mut World may only be used through the WorldPointer while it's in scope. Otherwise, it would violate Rust's aliasing rules.

The first invariant, that the WorldPointer must not outlive the &mut World, is broken as soon as ownership gets passed to another function. Since it's 'static, nothing stops other functions from squirreling it away somewhere that will outlive the &mut World. Since it's also Clone, this isn't even preventable by only passing around reference to it, since callees can simply .clone() it to get an owned version of it, and then do with that whatever they will. The clone method should probably be changed to be an unsafe struct method rather than the safe trait method that it currently is. Then, if only references to the WorldPointer are handed out, the onus is on the callees of the unsafe clone method to ensure that the invariants are upheld.

The second invariant, that the original &mut World must only be used through the WorldPointer is, for the most part, only the concern of the original creator of the pointer, since they're the only one who ever has access to the original &mut World to violate it. So long as the first invariant is upheld, it should be possible to guarantee that the second is also upheld entirely within the scope that the WorldPointer was created.

As far as current invalid usage goes, I believe that any APIProvider that stores the world in a script context (both the rhai and lua BevyAPIProviders for instance) technically violate this, since there's no way for these providers to "un-setup" the script runtime, and destroy their stored WorldPointer before the ScriptHost's handle_events method returns and invalidates the &mut World.

General Script API + Lua Implementation

Features every script should have access to, i.e.:

  • AddComponent
  • RemoveComponent
  • SpawnEntity

Lua API has been completed with a general framework extendable by other languages. Rhai will be supported in another release

Rhai Runs Entire Script Body When Calling Hook

Using Lua (specifically LuaJIT, I haven't tested the other available versions of Lua), while running a script that looks like this:

function on_update()
    print("inside")
end

print("outside")

The behavior is as expected: when the script is loaded and the hook is called for the first time, both outside and inside are printed. Any subsequent hook calls result in solely inside being printed, as it does not re-run the main body of the script. e.g.

outside
inside
inside
inside
...

This behavior is not the same when using Rhai. When using Rhai, running a script that looks like this:

fn on_update() {
    print("inside")
}

print("outside")

does not produce the expected output. Instead, the entire script is run when it is loaded, printing both outside and inside, as expected. Then, whenever the hook is called, the main body of the script is ran again before it runs the hook, meaning it prints both outside and inside again, rather than just inside as expected. e.g.

outside
inside
outside
inside
outside
inside
...

I believe this behavior is a bug, as it's not obvious it would do this by looking at the code, and also doesn't match the behavior when using Lua.

Examples don't compile anymore due to conflicting deps?

I'm not sure if this is a problem on my side, though the examples I've tried all seem to fail because two versions of nix are in use, e.g. when I run this on main

cargo run --example complex_game_loop_lua --features lua54

I get the following error

$ cargo run --example complex_game_loop_lua --features lua54                main@781754a
   Compiling syn v1.0.103
   Compiling serde v1.0.147
   Compiling rand_chacha v0.3.1
   Compiling rand v0.8.5
   Compiling encase_derive_impl v0.3.0
   Compiling toml v0.5.9
   Compiling bevy_macro_utils v0.8.1
   Compiling serde_derive v1.0.147
   Compiling thiserror-impl v1.0.37
   Compiling bytemuck_derive v1.2.1
   Compiling bevy_reflect_derive v0.8.1
   Compiling bevy_ecs_macros v0.8.1
   Compiling bevy_derive v0.8.1
   Compiling encase_derive v0.3.0
   Compiling bevy_encase_derive v0.8.1
   Compiling bevy_render_macros v0.8.1
   Compiling gltf-derive v1.0.0
   Compiling hash32-derive v0.1.1
   Compiling tealr_derive v0.9.0-alpha3
   Compiling taffy v0.1.0
   Compiling bytemuck v1.12.1
   Compiling image v0.24.4
   Compiling thiserror v1.0.37
   Compiling smallvec v1.10.0
   Compiling hashbrown v0.12.3
   Compiling glam v0.21.3
   Compiling uuid v1.2.1
   Compiling erased-serde v0.3.23
   Compiling serde_json v1.0.87
   Compiling ron v0.7.1
   Compiling tealr v0.9.0-alpha3
   Compiling parking_lot_core v0.9.4
   Compiling tracing-subscriber v0.3.16
   Compiling parking_lot_core v0.8.5
   Compiling parking_lot v0.12.1
   Compiling parking_lot v0.11.2
   Compiling gilrs-core v0.4.1
   Compiling bevy_utils v0.8.1
   Compiling indexmap v1.9.1
   Compiling gpu-descriptor v0.2.3
   Compiling cpal v0.13.5
   Compiling winit v0.26.1
   Compiling gilrs v0.9.0
error[E0308]: mismatched types
   --> /home/darth/.cargo/registry/src/github.com-1ecc6299db9ec823/cpal-0.13.5/src/host/alsa/mod.rs:245:21
    |
244 |         let handle = match handle_result {
    |                            ------------- this expression has type `std::result::Result<host::alsa::alsa::PCM, (host::alsa::alsa::Error, host::alsa::alsa::nix::errno::Errno)>`
245 |             Err((_, nix::errno::Errno::EBUSY)) => return Err(BuildStreamError::DeviceNotAvailable),
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `host::alsa::alsa::nix::errno::Errno`, found enum `nix::errno::Errno`
    |
    = note: enum `nix::errno::Errno` and enum `host::alsa::alsa::nix::errno::Errno` have similar names, but are actually distinct types
note: enum `nix::errno::Errno` is defined in crate `nix`
   --> /home/darth/.cargo/registry/src/github.com-1ecc6299db9ec823/nix-0.23.1/src/errno.rs:774:5
    |
774 |     pub enum Errno {
    |     ^^^^^^^^^^^^^^
note: enum `host::alsa::alsa::nix::errno::Errno` is defined in crate `nix`
   --> /home/darth/.cargo/registry/src/github.com-1ecc6299db9ec823/nix-0.24.2/src/errno.rs:776:5
    |
776 |     pub enum Errno {
    |     ^^^^^^^^^^^^^^
    = note: perhaps two different versions of crate `nix` are being used?

error[E0308]: mismatched types
   --> /home/darth/.cargo/registry/src/github.com-1ecc6299db9ec823/cpal-0.13.5/src/host/alsa/mod.rs:246:21
    |
244 |         let handle = match handle_result {
    |                            ------------- this expression has type `std::result::Result<host::alsa::alsa::PCM, (host::alsa::alsa::Error, host::alsa::alsa::nix::errno::Errno)>`
245 |             Err((_, nix::errno::Errno::EBUSY)) => return Err(BuildStreamError::DeviceNotAvailable),
246 |             Err((_, nix::errno::Errno::EINVAL)) => return Err(BuildStreamError::InvalidArgument),
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `host::alsa::alsa::nix::errno::Errno`, found enum `nix::errno::Errno`
    |
    = note: enum `nix::errno::Errno` and enum `host::alsa::alsa::nix::errno::Errno` have similar names, but are actually distinct types
note: enum `nix::errno::Errno` is defined in crate `nix`
   --> /home/darth/.cargo/registry/src/github.com-1ecc6299db9ec823/nix-0.23.1/src/errno.rs:774:5
    |
774 |     pub enum Errno {
    |     ^^^^^^^^^^^^^^
note: enum `host::alsa::alsa::nix::errno::Errno` is defined in crate `nix`
   --> /home/darth/.cargo/registry/src/github.com-1ecc6299db9ec823/nix-0.24.2/src/errno.rs:776:5
    |
776 |     pub enum Errno {
    |     ^^^^^^^^^^^^^^
    = note: perhaps two different versions of crate `nix` are being used?

error[E0308]: mismatched types
   --> /home/darth/.cargo/registry/src/github.com-1ecc6299db9ec823/cpal-0.13.5/src/host/alsa/mod.rs:302:21
    |
301 |         let handle = match handle_result {
    |                            ------------- this expression has type `std::result::Result<&mut host::alsa::alsa::PCM, (host::alsa::alsa::Error, host::alsa::alsa::nix::errno::Errno)>`
302 |             Err((_, nix::errno::Errno::ENOENT)) | Err((_, nix::errno::Errno::EBUSY)) => {
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `host::alsa::alsa::nix::errno::Errno`, found enum `nix::errno::Errno`
    |
    = note: enum `nix::errno::Errno` and enum `host::alsa::alsa::nix::errno::Errno` have similar names, but are actually distinct types
note: enum `nix::errno::Errno` is defined in crate `nix`
   --> /home/darth/.cargo/registry/src/github.com-1ecc6299db9ec823/nix-0.23.1/src/errno.rs:774:5
    |
774 |     pub enum Errno {
    |     ^^^^^^^^^^^^^^
note: enum `host::alsa::alsa::nix::errno::Errno` is defined in crate `nix`
   --> /home/darth/.cargo/registry/src/github.com-1ecc6299db9ec823/nix-0.24.2/src/errno.rs:776:5
    |
776 |     pub enum Errno {
    |     ^^^^^^^^^^^^^^
    = note: perhaps two different versions of crate `nix` are being used?

error[E0308]: mismatched types
   --> /home/darth/.cargo/registry/src/github.com-1ecc6299db9ec823/cpal-0.13.5/src/host/alsa/mod.rs:302:59
    |
301 |         let handle = match handle_result {
    |                            ------------- this expression has type `std::result::Result<&mut host::alsa::alsa::PCM, (host::alsa::alsa::Error, host::alsa::alsa::nix::errno::Errno)>`
302 |             Err((_, nix::errno::Errno::ENOENT)) | Err((_, nix::errno::Errno::EBUSY)) => {
    |                                                           ^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `host::alsa::alsa::nix::errno::Errno`, found enum `nix::errno::Errno`
    |
    = note: enum `nix::errno::Errno` and enum `host::alsa::alsa::nix::errno::Errno` have similar names, but are actually distinct types
note: enum `nix::errno::Errno` is defined in crate `nix`
   --> /home/darth/.cargo/registry/src/github.com-1ecc6299db9ec823/nix-0.23.1/src/errno.rs:774:5
    |
774 |     pub enum Errno {
    |     ^^^^^^^^^^^^^^
note: enum `host::alsa::alsa::nix::errno::Errno` is defined in crate `nix`
   --> /home/darth/.cargo/registry/src/github.com-1ecc6299db9ec823/nix-0.24.2/src/errno.rs:776:5
    |
776 |     pub enum Errno {
    |     ^^^^^^^^^^^^^^
    = note: perhaps two different versions of crate `nix` are being used?

error[E0308]: mismatched types
   --> /home/darth/.cargo/registry/src/github.com-1ecc6299db9ec823/cpal-0.13.5/src/host/alsa/mod.rs:305:21
    |
301 |         let handle = match handle_result {
    |                            ------------- this expression has type `std::result::Result<&mut host::alsa::alsa::PCM, (host::alsa::alsa::Error, host::alsa::alsa::nix::errno::Errno)>`
...
305 |             Err((_, nix::errno::Errno::EINVAL)) => {
    |                     ^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `host::alsa::alsa::nix::errno::Errno`, found enum `nix::errno::Errno`
    |
    = note: enum `nix::errno::Errno` and enum `host::alsa::alsa::nix::errno::Errno` have similar names, but are actually distinct types
note: enum `nix::errno::Errno` is defined in crate `nix`
   --> /home/darth/.cargo/registry/src/github.com-1ecc6299db9ec823/nix-0.23.1/src/errno.rs:774:5
    |
774 |     pub enum Errno {
    |     ^^^^^^^^^^^^^^
note: enum `host::alsa::alsa::nix::errno::Errno` is defined in crate `nix`
   --> /home/darth/.cargo/registry/src/github.com-1ecc6299db9ec823/nix-0.24.2/src/errno.rs:776:5
    |
776 |     pub enum Errno {
    |     ^^^^^^^^^^^^^^
    = note: perhaps two different versions of crate `nix` are being used?

error[E0308]: mismatched types
   --> /home/darth/.cargo/registry/src/github.com-1ecc6299db9ec823/cpal-0.13.5/src/host/alsa/mod.rs:720:36
    |
720 |         Err(err) if err.errno() == nix::errno::Errno::EPIPE => {
    |                                    ^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `host::alsa::alsa::nix::errno::Errno`, found enum `nix::errno::Errno`
    |
    = note: enum `nix::errno::Errno` and enum `host::alsa::alsa::nix::errno::Errno` have similar names, but are actually distinct types
note: enum `nix::errno::Errno` is defined in crate `nix`
   --> /home/darth/.cargo/registry/src/github.com-1ecc6299db9ec823/nix-0.23.1/src/errno.rs:774:5
    |
774 |     pub enum Errno {
    |     ^^^^^^^^^^^^^^
note: enum `host::alsa::alsa::nix::errno::Errno` is defined in crate `nix`
   --> /home/darth/.cargo/registry/src/github.com-1ecc6299db9ec823/nix-0.24.2/src/errno.rs:776:5
    |
776 |     pub enum Errno {
    |     ^^^^^^^^^^^^^^
    = note: perhaps two different versions of crate `nix` are being used?

error[E0308]: mismatched types
   --> /home/darth/.cargo/registry/src/github.com-1ecc6299db9ec823/cpal-0.13.5/src/host/alsa/mod.rs:803:40
    |
803 |             Err(err) if err.errno() == nix::errno::Errno::EPIPE => {
    |                                        ^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `host::alsa::alsa::nix::errno::Errno`, found enum `nix::errno::Errno`
    |
    = note: enum `nix::errno::Errno` and enum `host::alsa::alsa::nix::errno::Errno` have similar names, but are actually distinct types
note: enum `nix::errno::Errno` is defined in crate `nix`
   --> /home/darth/.cargo/registry/src/github.com-1ecc6299db9ec823/nix-0.23.1/src/errno.rs:774:5
    |
774 |     pub enum Errno {
    |     ^^^^^^^^^^^^^^
note: enum `host::alsa::alsa::nix::errno::Errno` is defined in crate `nix`
   --> /home/darth/.cargo/registry/src/github.com-1ecc6299db9ec823/nix-0.24.2/src/errno.rs:776:5
    |
776 |     pub enum Errno {
    |     ^^^^^^^^^^^^^^
    = note: perhaps two different versions of crate `nix` are being used?

For more information about this error, try `rustc --explain E0308`.
error: could not compile `cpal` due to 7 previous errors

Crash when trying to loop through empty Vec

I got following struct:

#[derive(Resource, Reflect, Default, Clone)]
#[reflect(Resource)]
pub struct LobbyListResource {
    pub lobbies: Vec<u64>,
}

I register all the needed things to correctly access the vec and loop through it via scripts:

struct HandleLobbyApiProvider;

impl APIProvider for HandleLobbyApiProvider {
    type APITarget = Engine;
    type ScriptContext = RhaiContext;
    type DocTarget = RhaiDocFragment;

    fn register_with_app(&self, app: &mut App) {
        app.register_foreign_rhai_type::<Vec<u64>>();
    }

    fn attach_api(
        &mut self,
        api: &mut Self::APITarget,
    ) -> Result<(), bevy_mod_scripting::prelude::ScriptError> {
        api.register_vec_functions::<u64>();
        Ok(())
    }
}

With this I can then loop through the lobbies in Rhai like this:

let lobby_list_type = world.get_type_by_name(blablabla::LobbyListResource");
if world.has_resource(lobby_list_type) {
    let lobbies = world.get_resource(lobby_list_type).lobbies;
    for lobby in lobbies {
        print(`lobby: ${lobby}`);
    }
}

And this works... as long as the vec is not empty!
When it's empty i get following error and it crashes:

thread 'main' panicked at 'attempt to subtract with overflow', C:\...\.cargo\git\checkouts\bevy_mod_scripting-ff78cea4271e6409\8879577\bevy_script_api\src\common\std.rs:136:26
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
Encountered a panic in exclusive system `bevy_mod_scripting_core::systems::script_event_handler<bevy_mod_scripting_rhai::RhaiScriptHost<pgc::modding::ModdedScriptRuntimeArguments>, 0, 10>`!
Encountered a panic in system `bevy_app::main_schedule::Main::run_main`!

As I'm only using Rhai, I don't know if this error exists in Lua too.

The current workaround is to just check if the vec is empty before trying to loop through it:

let lobby_list_type = world.get_type_by_name(blablabla::LobbyListResource");
if world.has_resource(lobby_list_type) {
    let lobbies = world.get_resource(lobby_list_type).lobbies;
    if !lobbies.is_empty() {
        for lobby in lobbies {
            print(`lobby: ${lobby}`);
        }
    }
}

Demo project for comment, and my own thoughts on the Bevy API.

As touched on in #65 I have a little demo project that I've been using for prototyping, and it encapsulates both my expected usage and my hacks in service of #65 and #69 pretty well. That project is now public at https://github.com/LaserWitch/lw_bevy_lua_demo. The code is rough in spots, and probably the documenting too, but it currently checks all the boxes I expect to need checked for my game project. Any pointers for improvement or other thoughts on it would be useful, and anything that can be made a crate feature you're welcome to lift of course.

After working with it a bit, the provided bevy API is surprisingly solid in many ways. I originally expected to need to do more work myself when it came to providing direct access to fields on components. My thoughts on potential areas of improvement might show in where I wrote helpers, but I'll try to think of them now...

  • Adding functions to an API is somewhat crunchy syntax. A few macros to ease that might make sense, though just helper functions might be as good in many cases...
  • Which brings to mind a more meta point: the crate can take a long time to build, which I found when I was making and testing changes on pr branches. Not sure if macros are the cause or not, or if it's avoidable, but seems worth mentioning.
  • I have (Vec3) component that's Deref and DerefMut, and if memory serves I needed to do v.1 in lua to get at it's components at all. That surprised me.
  • I believe at one point I had a Vec<> that was exposed to lua, and I found that it was 0-indexed and lua's length() reported it one element shorter than it actually was.
  • I think we have to register any tuple type we're going to expose to Lua, which might be unavoidable but was an unpleasant surprise.
  • How we're able to just stack up API providers is quite nice. The one questionmark I am left with is if it's possible to for two API providers to provide world methods without conflict...
  • Also it'd be nice if we could iterate over userdata members with pairs() but I think that's probably deeper Lua nits.

That's what I can recall right now!

Dynamic queries

Allow scripts querying for entities with different components.

  • Write (Owned only) Lua wrappers around bevy_ecs_dynamic
  • Add them to the APIProvider

Send Priority event from ScriptWorld

Hi, love this crate!

I just came across a small issue.
I need to send out PriorityEvents from a rust function that is registered as a script function.
So it has only access to the ScriptWorld.

With the Normal Bevy Events I can just use world.send_event().
But I can't seem to figure out how to send out priority events with only having the ScriptWorld.

Did I miss anything?

Project needing maintainers

Bevy scripting needs you!

So far I am the only committed maintainer of this crate. This has worked very well when I didn't have any other major responsibilities, but since getting a full time job, I've been struggling to keep the updates coming.

Do not be scared, I am not pausing development or anything of the sort, I will eventually be able to fall back into the rhythm and keep improving the crate. In fact I am looking forward to a big re-write when dynamic systems are possible in Bevy!

Having additional maintainers would mean a much more predictable release cycle, and at the very least keeping up with the Bevy train on time.

Scope

At the beginning, this library was just a single crate, and everything was simple. Then the scope increased, and suddenly I was supporting an ever changing bevy scripting API, which is still unfinished, as well as keeping up with a multitude of tools including tealr, teal, rhai etc..

The library reached the point where coming back to it after long breaks means re-discovering all the design choices I have made. This means that new people joining the project wouldn't be far behind me in understanding everything ;)

At the very least I am looking for a dedicated person able to commit to keeping this crate updated whenever Bevy changes (which usually isn't that much work), so I can focus on improving the library. Ideally we'd have more people, a subject matter expert for every language we support, and maybe some people dedicated to other bits and bobs (like docs, optimisation etc..). I am aware this might be a bit much considering the library isn't that popular, but one can hope :)

Contact

If you're at all interested in using this crate, and would like to contribute, reach out to me over at [email protected], nothing formal, just tell me about yourself, how you use this library and/or how/to what extent you'd like to help out! Alternatively use this google form: https://forms.gle/vTQnrj2nf8e4n97F9 if that's more your speed!

Thanks

I'd also love to thank everybody who helped out in the past again (in no particular order)!

Code contributions:

Issue contributions (yes these matter too!):

Every issue, line of code, and piece of grammar checking helps!

Reduce size of ScriptRef

It is quite important to minimize the size of this structure, since it's widely used,created and passed around, Ideally this should be a Copy type

Can persistant, shared globals state be enabled?

I'm not sure if this is a FR or something else, but here goes.

In my testing I've found global state isn't behaving how I expect Lua state in a game to act. It appears that each script runs inside it's own, enviroment/context. A global defined by one script is nil when another script tries to access it. I can see some cases for this, but it also seems to inhibit many of the approaches to scripting that I want to enable unless I go through a lot of effort to essentially reimplement parts of Lua as resources.

Perhaps relatedly, when a script is reloaded the original global state seems to be discarded and a fresh one replaces it. for instance this hook:

function on_level()
    if type(_G.i) == 'nil' then _G.i = 0 end
    if(i%200 == 0) then
        print("\n******** " .. i )
    end
    i=i+1
end

In theory the count should persist between reloads, if there was a single context and the hook function was simply replaced by executing the changed file. It appears that it's a clean new context though. Any stateful gameplay scripting live development is going to be really awkward this way. If I make use of require then it may be viable to code around this to a limited degree inside lua itself, but I'm not sure that can cover everything.

Do you think it'd be feasible for a game to get around either of those with custom ScriptHost implementations? If not, is it conceivable to make those alternate behaviors available somehow, likely optionally? I've only got a loose grasp of the internals of the crate so far, so I'm not able to make a confident guess myself.

Task Scheduler

So this is more of a general feature request/enhancement (also a question), but something that would be extremely useful in my use cases would be having a task scheduler so that scripts could, for example, yield back to the engine for a specified duration (like a sleep function). This could also potentially be used for calling callback functions bound to specific events through functions, rather than having specific hook functions.

An example of this might look like this:

-- another benefit of this is having multiple callbacks defined per script
physics_stepped_event:bind(function()
  -- do something
  sleep(5) -- sleep for 5 seconds
  -- do something else
end)

Rather than the current hook-based system:

-- it's a hook so it can only be defined once per script
function physics_stepped_event()
  -- do something
  -- no idea how you'd wait here, maybe call a function and pass the name of another hook to call as well as the time to sleep?
end

I do know this isn't currently possible with the current language implementations, but could something like this be implemented on top of the existing traits? I do know the current system probably works better under Bevy's ECS system, but for me the benefits from having this outweighs the extra work I'd have to do to create the necessary APIs.

It's something that would be extremely useful for my projects, and would be something I would consider implementing myself as well (and of course I'd be willing to consider submitting a PR if you think it'd be a worthy addition). I just don't know enough about how the code is structured to know if I could implement this on top of it or not.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.