Description
Firstly, I love bevy_mod_scripting. It's a huge part of why I thought the prospect of Nano-9 seemed feasible. As an avid user I've developed some opinions. Let me relate them as issues.
Problem: ScriptAsset loading is script evaluation
I've got two problem instances for this general problem.
Problem Instance 1: Multiple scripts
In Nano-9 I'm trying to support someone providing multiple scripts in a shared context environment like this:
scripts = [
"vector.p8", // p8 is just the Pico-8 dialect of Lua, which I translate into vanilla Lua.
"actor.p8",
"platformer.p8",
"dolly.p8",
"main.lua",
]
This happens through an AssetLoader
, which is restricted environment; it's an async function where I don't have access to the world or resources, etc. Some of the scripts do depend on the preceding scripts. Although I load these ScriptAsset
s sequentially using an immediate loader, they are evaluated in an indeterminate order, which often means the wrong order.
Problem Instance 2: Can't setup the environment fast enough
I'd really like to be able to support having a hello world script that looked like this:
print("hello world")
However, because of this issue, it must currently look like this:
function _init()
print("hello world")
end
The reason is that in my config file where I load the code, I also load the sprite sheets and color palette. I need to set up the color palette before I can call print()
.
Solution A: Don't do that.
I could punt the loading of scripts outside of the AssetLoader
but images, sounds, fonts, etc. load this way, why not scripts?
Solution B: Separate script evaluation and script loading.
Let's evaluate scripts at another time, perhaps when they're added to a ScriptComponent.
Solution C: Evaluate scripts in order of load.
If we can't change the evaluation after loading can we ensure the order they're evaluated is the order they were loaded?
Problem: ScriptIds complicate everything
The script IDs have been a hassle for me to get right. I’ve added and removed and changed my asset path to script id mapper many times. And when it stops working, it’s hard for me to figure out why.
As an aside, I added Reflect to everything once so I could see what was going on in the inspector. (This was before it was part of BMS proper. Love seeing a changes that mimic my own homebrew!)
When I take a step back I mostly don’t understand why script IDs exist.
I thought maybe you’d want it like that so you could add ScriptComponent(["hello.lua"]) and then it would use the path to load the script, but we have to load the Handle for "hello.lua" ourselves anyway and store it, so we’re not saved from dealing with Handles by using Script IDs.
Solution A: Use the handles.
What if we used the prevalent Bevy pattern and used handles directly?
ScriptComponent([asset_server.load("foo.lua")])
You could even specify the language on load:
asset_server.load_with_settings("hello.p8", |settings: &mut ScriptSettings| {
settings.language = Language::Lua;
});
Maybe ScriptAsset
could look like this?
pub struct ScriptAsset {
/// The body of the script
pub content: Box<[u8]>,
/// The language of the script
pub language: Language,
}