makspll / bevy_mod_scripting

Bevy Scripting Plugin
Apache License 2.0
401 stars 31 forks source link

Rhai Runs Entire Script Body When Calling Hook #31

Closed katk0smos closed 1 year ago

katk0smos commented 2 years ago

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.

makspll commented 2 years ago

hi @TheWaffleDimension! Thanks so much for taking the time to file this issue!

Yes indeed, rhai does evaluate all the global statements in the AST when calling a function. I would note however for people browsing the issues:

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

print("outside")

would behave just as the above example when calling on_update, i.e. "no" would never be printed.

As to where the issue stems from, it'll be this bit of rust Rhai API: https://docs.rs/rhai/latest/rhai/struct.Engine.html#method.call_fn

specifially: "The AST is evaluated before calling the function. This allows a script to load the necessary modules. This is usually desired. If not, a specialized AST can be prepared that contains only function definitions without any body script via AST::clear_statements."

Now I am not sure if it's possible to fix this without preventing modules from being loaded correctly as I am not familiar with the interaction between modules and the functions in Rhai, but I could have a look.

I do agree that this behaviour should be consistent with Lua. Especially since the Lua behaviour is more intuitive.

The relevant code in this package can be found here: https://github.com/makspll/bevy_mod_scripting/blob/7d373424925598745bffa5185f1540481c4373c4/languages/bevy_mod_scripting_rhai/src/lib.rs#L159

makspll commented 1 year ago

This is now fixed in 0.2.0 clear_statements is called at the end of each execution meaning the execution logic is consistent with Lua