use crate::gameobject::{ Node, Transform, Spatial }; extern crate mlua; use mlua::Lua as LuaContext; use mlua::chunk; use std::rc::Rc; use std::cell::RefCell; pub trait ScriptLang { fn init(&mut self); fn update(&mut self, delta: f32); } pub struct Lua { ctx: LuaContext, } impl mlua::UserData for Node { fn add_methods<'lua, M: mlua::UserDataMethods<'lua, Self>>(methods: &mut M) { use crate::gameobject::GameObject::*; methods.add_method_mut("find_node", |_, this, name: String| { let child = this.find_node(&name); match child { Some(child) => Ok(child), None => Err(mlua::Error::RuntimeError("Could not find child".to_string())), } }); methods.add_method("get_transform", |_, this, _: ()| { match &this.gameobject { Mesh(mesh) => Ok(mesh.get_transform()), Camera(camera) => Ok(camera.get_transform()), _ => Err(mlua::Error::RuntimeError("Node does not implement get_transform".to_string())) } }); } } impl mlua::UserData for Transform {} impl Lua { pub fn new(root: Rc>) -> Self { // Create a lua context, load std libraries let ctx = LuaContext::new(); // Create the ``couch'' api let couch = ctx.create_table().unwrap(); couch.set("root", ctx.create_userdata(root).unwrap()).unwrap(); couch.set("debug", ctx.create_function(debug).unwrap()).unwrap(); couch.set("say_hello", ctx.create_function(say_hello).unwrap()).unwrap(); // Hook in to globals ctx.globals().set("couch", couch).unwrap(); let path = std::path::Path::new("main.lua"); let buf = std::fs::read(&path).expect("Could not find main.lua"); ctx.load(&buf).exec().unwrap(); Lua { ctx, } } } impl ScriptLang for Lua { fn init(&mut self) { self.ctx.load(&"init()").exec().ok(); } fn update(&mut self, delta: f32) { self.ctx.load(chunk! { update($delta) }).exec().ok(); } } macro_rules! luafuncs { ($($name:ident($($arg:ident: $type: ty),*) $body:block),*) => { $( fn $name(_: &LuaContext, ($($arg),*,): ($($type),*,)) -> Result<(), mlua::Error> $body )* }; } luafuncs!{ debug(msg: String) { println!("Couch Debug Message: {}", msg); Ok(()) }, say_hello(name: String, msg: String) { println!("Couch says {} to {}", msg, name); Ok(()) } }