Create an early scripting engine #2

Merged
SeanOMik merged 42 commits from feature/early-scripting into main 2024-03-02 22:28:57 -05:00
Owner

This pr adds a working Lua scripting engine. The engine is capable of reloading the scripts on a change, loading 3d models, spawning entities, moving them around, and even responding to keyboard input. Not everything is exposed to Lua yet, I need to figure out some easier ways to do it since currently its a massive pain and completely manual.

To be able to support scripts, other features were added to other crates, like asset change watching, and staged system execution, among many other things that I didn't keep track of. I tried to use mlua as the Lua library, but found it limiting so ended up just making my own: elua (short for "easy lua").

Loading a Lua script:

game.with_plugin(LuaScriptingPlugin);

// loading the script
let world = game.world_mut();
let mut res_man = world.get_resource_mut::<ResourceManager>();
let script = res_man.request::<LuaScript>("scripts/test.lua").unwrap();
res_man.watch("scripts/test.lua", false).unwrap();
drop(res_man);

// Adding the script to the world.
let script = Script::new("test.lua", script);
let scripts = ScriptList::new(vec![script]);
world.spawn((scripts,));

Every system tick the scripts will be executed. The scripting engine loads the Lua script and looks for functions in it with the name of on_<stage>, and will execute those functions on the ECS stage. The stages that are built into the engine are already supported by the scripting engine. So the function names in order of execution are, on_init, on_first, on_pre_update, on_update, on_post_update, on_last.

On the execution of each script, globals are set so the programmer can make changes to the world. The ECS world is exposed as world, and the entity that the script is on is exposed as entity.

Brief overview of World

Exposed methods:

  • request_res: Used to request assets.
  • add_resource: Used to add a resource to the ECS world.
  • resource: Used to get resources from the ECS world.
  • view: Used to view into the ECS world and query for components.
    world:view(function (t)
        -- Do things
    end, Transform)
    
    • The parameters of the method are system: Function(...comps) -> ...comps, ...comps
    • The second parameter is the requested components
    • The first parameter is the system that is provided the requested components through the parameters of the system. If the system makes any changes to the components, it must return them for the changes to take affect. The order doesn't matter.

Brief overview of Scripting Engine

The scripting engine exposes APIs through "Providers". The providers can register types to Lua. These types can be wrappers of Rust types (e.g., LuaModelComponent, LuaActionHandler, etc.), be converted to and from Lua types (e.g., LuaDeltaTime), or converted to and from Lua tables (no types use this currently, it was discovered to be slower than wrapped types). View the extension trait RegisterLuaType for World to see all the ways that types can be exposed to Lua.

This pr adds a working Lua scripting engine. The engine is capable of reloading the scripts on a change, loading 3d models, spawning entities, moving them around, and even responding to keyboard input. Not everything is exposed to Lua yet, I need to figure out some easier ways to do it since currently its a massive pain and completely manual. To be able to support scripts, other features were added to other crates, like asset change watching, and staged system execution, among many other things that I didn't keep track of. I tried to use [`mlua`](https://github.com/mlua-rs/mlua) as the Lua library, but found it limiting so ended up just making my own: [`elua`](https://git.seanomik.net/seanomik/elua) (short for "easy lua"). ### Loading a Lua script: ```rust game.with_plugin(LuaScriptingPlugin); // loading the script let world = game.world_mut(); let mut res_man = world.get_resource_mut::<ResourceManager>(); let script = res_man.request::<LuaScript>("scripts/test.lua").unwrap(); res_man.watch("scripts/test.lua", false).unwrap(); drop(res_man); // Adding the script to the world. let script = Script::new("test.lua", script); let scripts = ScriptList::new(vec![script]); world.spawn((scripts,)); ``` Every system tick the scripts will be executed. The scripting engine loads the Lua script and looks for functions in it with the name of `on_<stage>`, and will execute those functions on the ECS stage. The stages that are built into the engine are already supported by the scripting engine. So the function names in order of execution are, `on_init`, `on_first`, `on_pre_update`, `on_update`, `on_post_update`, `on_last`. On the execution of each script, globals are set so the programmer can make changes to the world. The ECS world is exposed as `world`, and the entity that the script is on is exposed as `entity`. ### Brief overview of World Exposed methods: * `request_res`: Used to request assets. * `add_resource`: Used to add a resource to the ECS world. * `resource`: Used to get resources from the ECS world. * `view`: Used to view into the ECS world and query for components. ```lua world:view(function (t) -- Do things end, Transform) ``` - The parameters of the method are `system: Function(...comps) -> ...comps, ...comps` - The second parameter is the requested components - The first parameter is the system that is provided the requested components through the parameters of the system. If the system makes any changes to the components, it must return them for the changes to take affect. The order doesn't matter. ### Brief overview of Scripting Engine The scripting engine exposes APIs through "Providers". The providers can register types to Lua. These types can be wrappers of Rust types (e.g., `LuaModelComponent`, `LuaActionHandler`, etc.), be converted to and from Lua types (e.g., `LuaDeltaTime`), or converted to and from Lua tables (no types use this currently, it was discovered to be slower than wrapped types). View the extension trait `RegisterLuaType` for World to see all the ways that types can be exposed to Lua.
SeanOMik added 42 commits 2024-03-02 21:50:55 -05:00
eb44aba3dc
reflect: Fix weird panics for rust-analyzer
Not sure why they were happening. These panics didn't happen on CI and my machine when building and running the tests.
639ec0ee42
resource: fix resource manager tests
A test was failing since 'watch_image' was deleting the file and recreating it while the other test was running
SeanOMik merged commit 71693971c2 into main 2024-03-02 22:28:57 -05:00
SeanOMik deleted branch feature/early-scripting 2024-03-02 22:28:57 -05:00
Sign in to join this conversation.
No reviewers
No Milestone
No project
No Assignees
1 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: SeanOMik/lyra-engine#2
No description provided.