Create an early scripting engine #2
|
@ -1,7 +1,25 @@
|
|||
print("Hello World")
|
||||
|
||||
function update()
|
||||
print("updated")
|
||||
--printf("I love to eat formatted {}!", "food")
|
||||
--printf("World is {}", world)
|
||||
|
||||
function on_init()
|
||||
print("Lua script was initialized!")
|
||||
end
|
||||
|
||||
function on_first()
|
||||
print("Lua's first function was called")
|
||||
end
|
||||
|
||||
function on_pre_update()
|
||||
print("Lua's pre-update function was called")
|
||||
end
|
||||
|
||||
function on_update()
|
||||
print("Lua's update function was called")
|
||||
end
|
||||
|
||||
function on_post_update()
|
||||
print("Lua's post-update function was called")
|
||||
end
|
||||
|
||||
function on_last()
|
||||
print("Lua's last function was called")
|
||||
end
|
|
@ -1,6 +1,6 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use lyra_ecs::ResourceObject;
|
||||
use lyra_ecs::{ResourceObject, Entity};
|
||||
|
||||
use crate::ScriptWorldPtr;
|
||||
|
||||
|
@ -29,8 +29,12 @@ impl From<anyhow::Error> for ScriptError {
|
|||
|
||||
#[derive(Clone, Hash, PartialEq, Eq)]
|
||||
pub struct ScriptData {
|
||||
/// The script id
|
||||
pub script_id: u64,
|
||||
/// The name of the script
|
||||
pub name: String,
|
||||
/// The entity that this script exists on
|
||||
pub entity: Entity,
|
||||
}
|
||||
|
||||
/// Provides an API to a scripting context.
|
||||
|
@ -41,9 +45,7 @@ pub trait ScriptApiProvider {
|
|||
/// Exposes an API in the provided script context.
|
||||
fn expose_api(&mut self, ctx: &mut Self::ScriptContext) -> Result<(), ScriptError>;
|
||||
|
||||
/// Create a script in the script host.
|
||||
///
|
||||
/// This only creates the script for the host, it does not setup the script for execution. See [`ScriptHostProvider::setup_script`].
|
||||
/// Setup a script right before its 'init' method is called.
|
||||
fn setup_script(&mut self, data: &ScriptData, ctx: &mut Self::ScriptContext) -> Result<(), ScriptError>;
|
||||
|
||||
/// A function that is used to update a script's environment.
|
||||
|
@ -74,13 +76,18 @@ pub trait ScriptHost: Default + ResourceObject {
|
|||
/// Loads a script and creates a context for it.
|
||||
///
|
||||
/// Before the script is executed, the API providers are exposed to the script.
|
||||
fn load_script(&mut self, script: &[u8], script_data: &ScriptData, providers: &mut crate::ScriptApiProviders<Self>) -> Result<Self::ScriptContext, ScriptError>;
|
||||
fn load_script(&mut self, script: &[u8], script_data: &ScriptData,
|
||||
providers: &mut crate::ScriptApiProviders<Self>)
|
||||
-> Result<Self::ScriptContext, ScriptError>;
|
||||
|
||||
/// Setup a script for execution.
|
||||
fn setup_script(&mut self, script_data: &ScriptData, ctx: &mut Self::ScriptContext, providers: &mut ScriptApiProviders<Self>) -> Result<(), ScriptError>;
|
||||
fn setup_script(&mut self, script_data: &ScriptData, ctx: &mut Self::ScriptContext,
|
||||
providers: &mut ScriptApiProviders<Self>) -> Result<(), ScriptError>;
|
||||
|
||||
/// Executes the update step for the script.
|
||||
fn update_script(&mut self, world: ScriptWorldPtr, script_data: &crate::ScriptData, ctx: &mut Self::ScriptContext, providers: &mut crate::ScriptApiProviders<Self>) -> Result<(), ScriptError>;
|
||||
fn call_script(&mut self, world: ScriptWorldPtr, script_data: &crate::ScriptData,
|
||||
ctx: &mut Self::ScriptContext, providers: &mut crate::ScriptApiProviders<Self>,
|
||||
function_name: &str) -> Result<(), ScriptError>;
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
|
|
|
@ -2,7 +2,7 @@ pub mod dynamic_iter;
|
|||
pub use dynamic_iter::*;
|
||||
|
||||
pub mod world;
|
||||
use lyra_game::plugin::Plugin;
|
||||
use lyra_game::{plugin::Plugin, game::GameStages};
|
||||
use lyra_resource::ResourceManager;
|
||||
use tracing::{debug, error};
|
||||
pub use world::*;
|
||||
|
@ -13,20 +13,25 @@ pub use script::*;
|
|||
pub mod loader;
|
||||
pub use loader::*;
|
||||
|
||||
pub mod modules;
|
||||
pub use modules::*;
|
||||
|
||||
#[cfg(test)]
|
||||
mod test;
|
||||
|
||||
use std::{ptr::NonNull, sync::Mutex};
|
||||
|
||||
use lyra_ecs::{DynamicBundle, World};
|
||||
use lyra_reflect::{Reflect, RegisteredType, FromType, AsRegisteredType};
|
||||
use lyra_ecs::{DynamicBundle, World, query::{ResMut, View, Entities}};
|
||||
use lyra_reflect::{Reflect, FromType};
|
||||
|
||||
use mlua::{Lua, AnyUserDataExt};
|
||||
|
||||
pub type LuaContext = Mutex<mlua::Lua>;
|
||||
|
||||
pub const FN_NAME_INTERNAL_REFLECT_TYPE: &str = "__lyra_internal_reflect_type";
|
||||
pub const FN_NAME_INTERNAL_REFLECT: &str = "__lyra_internal_reflect";
|
||||
|
||||
use crate::{ScriptBorrow, ScriptDynamicBundle, ScriptApiProviders, ScriptContexts, ScriptWorldPtr, ScriptList, ScriptData, ScriptHost, ScriptError};
|
||||
use crate::{ScriptBorrow, ScriptDynamicBundle, ScriptApiProviders, ScriptContexts, ScriptWorldPtr, ScriptList, ScriptData, ScriptHost, ScriptError, GameScriptExt};
|
||||
|
||||
impl<'lua> mlua::FromLua<'lua> for ScriptBorrow {
|
||||
fn from_lua(value: mlua::Value<'lua>, _lua: &'lua Lua) -> mlua::Result<Self> {
|
||||
|
@ -115,18 +120,24 @@ impl mlua::UserData for ScriptDynamicBundle {
|
|||
}
|
||||
}
|
||||
|
||||
/// A system that updates the scripts that exist in the world
|
||||
pub fn lua_update_scripts(world: &mut World) -> anyhow::Result<()> {
|
||||
let world_ptr = ScriptWorldPtr::from_ref(&world);
|
||||
let mut host = world.get_resource_mut::<LuaHost>();
|
||||
let mut contexts = world.get_resource_mut::<ScriptContexts<Mutex<mlua::Lua>>>();
|
||||
let mut providers = world.get_resource_mut::<ScriptApiProviders<LuaHost>>();
|
||||
///
|
||||
/* fn lua_script_run_func(world: &mut World, function_name: &str) -> anyhow::Result<()> {
|
||||
|
||||
for scripts in world.view_iter::<&ScriptList<LuaScript>>() {
|
||||
} */
|
||||
|
||||
/// A system that creates the script contexts in the world as new scripts are found
|
||||
pub fn lua_scripts_create_contexts(mut host: ResMut<LuaHost>,
|
||||
mut contexts: ResMut<ScriptContexts<LuaContext>>,
|
||||
mut providers: ResMut<ScriptApiProviders<LuaHost>>,
|
||||
view: View<(Entities, &ScriptList<LuaScript>)>,
|
||||
) -> anyhow::Result<()> {
|
||||
|
||||
for (en, scripts) in view.into_iter() {
|
||||
for script in scripts.iter() {
|
||||
let script_data = ScriptData {
|
||||
name: script.name().to_string(),
|
||||
script_id: script.id(),
|
||||
entity: en,
|
||||
};
|
||||
|
||||
if !contexts.has_context(script.id()) {
|
||||
|
@ -144,18 +155,37 @@ pub fn lua_update_scripts(world: &mut World) -> anyhow::Result<()> {
|
|||
debug!("Script '{}' is not yet loaded, skipping", script.name());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
let ctx = contexts.get_context_mut(script.id()).unwrap();
|
||||
|
||||
debug!("Running 'update' function in script '{}'", script.name());
|
||||
match host.update_script(world_ptr.clone(), &script_data, ctx, &mut providers) {
|
||||
Ok(()) => {},
|
||||
Err(e) => match e {
|
||||
ScriptError::MluaError(m) => {
|
||||
error!("Script '{}' ran into an error: {}", script.name(), m);
|
||||
fn lua_call_script_function(world: &mut World, stage_name: &str) -> anyhow::Result<()> {
|
||||
let world_ptr = ScriptWorldPtr::from_ref(&world);
|
||||
let mut host = world.get_resource_mut::<LuaHost>();
|
||||
let mut contexts = world.get_resource_mut::<ScriptContexts<LuaContext>>();
|
||||
let mut providers = world.get_resource_mut::<ScriptApiProviders<LuaHost>>();
|
||||
|
||||
for (en, scripts) in world.view_iter::<(Entities, &ScriptList<LuaScript>)>() {
|
||||
for script in scripts.iter() {
|
||||
let script_data = ScriptData {
|
||||
name: script.name().to_string(),
|
||||
script_id: script.id(),
|
||||
entity: en,
|
||||
};
|
||||
|
||||
if let Some(ctx) = contexts.get_context_mut(script.id()) {
|
||||
debug!("Running '{}' function in script '{}'", stage_name, script.name());
|
||||
match host.call_script(world_ptr.clone(), &script_data, ctx, &mut providers, stage_name) {
|
||||
Ok(()) => {},
|
||||
Err(e) => match e {
|
||||
ScriptError::MluaError(m) => {
|
||||
error!("Script '{}' ran into an error: {}", script.name(), m);
|
||||
},
|
||||
ScriptError::Other(_) => return Err(e.into()),
|
||||
},
|
||||
ScriptError::Other(_) => return Err(e.into()),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -163,6 +193,36 @@ pub fn lua_update_scripts(world: &mut World) -> anyhow::Result<()> {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
/// This system executes the 'on_update' function of lua scripts in the world. It is meant to run
|
||||
/// during the 'GameStages::Update' stage.
|
||||
pub fn lua_script_update_stage_system(world: &mut World) -> anyhow::Result<()> {
|
||||
lua_call_script_function(world, "on_update")
|
||||
}
|
||||
|
||||
/// This system executes the 'on_pre_update' function of lua scripts in the world. It is meant to run
|
||||
/// during the 'GameStages::PreUpdate' stage.
|
||||
pub fn lua_script_pre_update_stage_system(world: &mut World) -> anyhow::Result<()> {
|
||||
lua_call_script_function(world, "on_pre_update")
|
||||
}
|
||||
|
||||
/// This system executes the 'on_post_update' function of lua scripts in the world. It is meant to run
|
||||
/// during the 'GameStages::PostUpdate' stage.
|
||||
pub fn lua_script_post_update_stage_system(world: &mut World) -> anyhow::Result<()> {
|
||||
lua_call_script_function(world, "on_post_update")
|
||||
}
|
||||
|
||||
/// This system executes the 'on_first' function of lua scripts in the world. It is meant to run
|
||||
/// during the 'GameStages::First' stage.
|
||||
pub fn lua_script_first_stage_system(world: &mut World) -> anyhow::Result<()> {
|
||||
lua_call_script_function(world, "on_first")
|
||||
}
|
||||
|
||||
/// This system executes the 'on_last' function of lua scripts in the world. It is meant to run
|
||||
/// during the 'GameStages::Last' stage.
|
||||
pub fn lua_script_last_stage_system(world: &mut World) -> anyhow::Result<()> {
|
||||
lua_call_script_function(world, "on_last")
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct LuaScriptingPlugin;
|
||||
|
||||
|
@ -172,13 +232,24 @@ impl Plugin for LuaScriptingPlugin {
|
|||
|
||||
world.add_resource_default::<LuaHost>();
|
||||
world.add_resource_default::<ScriptApiProviders<LuaHost>>();
|
||||
world.add_resource_default::<ScriptContexts<Mutex<mlua::Lua>>>();
|
||||
world.add_resource_default::<ScriptContexts<LuaContext>>();
|
||||
|
||||
let mut loader = world.try_get_resource_mut::<ResourceManager>()
|
||||
.expect("Add 'ResourceManager' to the world before trying to add this plugin");
|
||||
loader.register_loader::<LuaLoader>();
|
||||
drop(loader);
|
||||
|
||||
game.with_system("lua_update", lua_update_scripts, &[]);
|
||||
game.add_script_api_provider::<LuaHost, _>(UtilityApiProvider);
|
||||
|
||||
game
|
||||
.add_system_to_stage(GameStages::First, "lua_create_contexts", lua_scripts_create_contexts, &[])
|
||||
.add_system_to_stage(GameStages::First, "lua_first_stage", lua_script_first_stage_system, &["lua_create_contexts"])
|
||||
// cannot depend on 'lua_create_contexts' since it will cause a panic.
|
||||
// the staged executor separates the executor of a single stage so this system
|
||||
// cannot depend on the other one.
|
||||
.add_system_to_stage(GameStages::PreUpdate, "lua_pre_update", lua_script_pre_update_stage_system, &[])
|
||||
.add_system_to_stage(GameStages::Update, "lua_update", lua_script_update_stage_system, &[])
|
||||
.add_system_to_stage(GameStages::PostUpdate, "lua_post_update", lua_script_post_update_stage_system, &[])
|
||||
.add_system_to_stage(GameStages::Last, "lua_last_stage", lua_script_last_stage_system, &[]);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
use std::sync::{Mutex, Arc};
|
||||
|
||||
use crate::{ScriptApiProvider, ScriptData};
|
||||
|
||||
/// This Api provider provides some nice utility functions.
|
||||
///
|
||||
/// Functions:
|
||||
/// ```lua
|
||||
/// ---@param str (string) A format string.
|
||||
/// ---@param ... (any varargs) The variables to format into the string. These values must be
|
||||
/// primitives, or if UserData, have the '__tostring' meta method
|
||||
/// function printf(str, ...)
|
||||
/// ```
|
||||
#[derive(Default)]
|
||||
pub struct UtilityApiProvider;
|
||||
|
||||
impl ScriptApiProvider for UtilityApiProvider {
|
||||
type ScriptContext = Mutex<mlua::Lua>;
|
||||
|
||||
fn expose_api(&mut self, ctx: &mut Self::ScriptContext) -> Result<(), crate::ScriptError> {
|
||||
let ctx = ctx.lock().unwrap();
|
||||
|
||||
fn printf(lua: &mlua::Lua, (mut text, formats): (String, mlua::Variadic<mlua::Value>)) -> mlua::Result<()> {
|
||||
let mut formatted = String::new();
|
||||
let mut arg_num = 0;
|
||||
|
||||
while let Some(start) = text.find("{}") {
|
||||
let val_str = match formats.get(arg_num) {
|
||||
Some(v) => match v {
|
||||
mlua::Value::Nil => "nil".to_string(),
|
||||
mlua::Value::Boolean(b) => b.to_string(),
|
||||
mlua::Value::LightUserData(_) => {
|
||||
return Err(mlua::Error::RuntimeError(format!("unable to get string representation of LightUserData")));
|
||||
},
|
||||
mlua::Value::Integer(i) => i.to_string(),
|
||||
mlua::Value::Number(n) => n.to_string(),
|
||||
mlua::Value::String(s) => s.to_str().unwrap().to_string(),
|
||||
mlua::Value::Table(_) => {
|
||||
return Err(mlua::Error::RuntimeError(format!("unable to get string representation of Table")));
|
||||
},
|
||||
mlua::Value::Function(_) => {
|
||||
return Err(mlua::Error::RuntimeError(format!("unable to get string representation of Function")));
|
||||
},
|
||||
mlua::Value::Thread(_) => {
|
||||
return Err(mlua::Error::RuntimeError(format!("unable to get string representation of Thread")));
|
||||
},
|
||||
mlua::Value::UserData(ud) => {
|
||||
let metatable = ud.get_metatable()?;
|
||||
if let Ok(tos) = metatable.get::<mlua::Function>(mlua::MetaMethod::ToString) {
|
||||
tos.call::<_, String>((ud.clone(),))?
|
||||
} else {
|
||||
return Err(mlua::Error::RuntimeError(format!("UserData does not implement MetaMethod '__tostring'")));
|
||||
}
|
||||
},
|
||||
mlua::Value::Error(e) => e.to_string(),
|
||||
},
|
||||
None => {
|
||||
let got_args = arg_num;
|
||||
|
||||
// continue searching for {} to get the number of format spots for the error message.
|
||||
while let Some(start) = text.find("{}") {
|
||||
text = text[start + 2..].to_string();
|
||||
arg_num += 1;
|
||||
}
|
||||
|
||||
return Err(mlua::Error::BadArgument {
|
||||
to: Some("printf".to_string()),
|
||||
pos: 2,
|
||||
name: Some("...".to_string()),
|
||||
cause: Arc::new(mlua::Error::RuntimeError(format!("not enough args \
|
||||
given for the amount of format areas in the string. Expected {}, \
|
||||
got {}.", arg_num, got_args)))
|
||||
})
|
||||
},
|
||||
};
|
||||
|
||||
formatted = format!("{}{}{}", formatted, &text[0..start], val_str);
|
||||
|
||||
text = text[start + 2..].to_string();
|
||||
|
||||
arg_num += 1;
|
||||
}
|
||||
|
||||
if arg_num < formats.len() {
|
||||
return Err(mlua::Error::BadArgument {
|
||||
to: Some("printf".to_string()),
|
||||
pos: 2,
|
||||
name: Some("...".to_string()),
|
||||
cause: Arc::new(mlua::Error::RuntimeError(format!("got more args \
|
||||
than format areas in the string. Expected {}, got {}.", formats.len(), arg_num)))
|
||||
})
|
||||
}
|
||||
|
||||
formatted = format!("{}{}", formatted, text);
|
||||
|
||||
lua.globals()
|
||||
.get::<_, mlua::Function>("print")
|
||||
.unwrap()
|
||||
.call::<_, ()>(formatted)
|
||||
.unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
let printf_func = ctx.create_function(printf).unwrap();
|
||||
|
||||
let globals = ctx.globals();
|
||||
globals.set("printf", printf_func).unwrap();
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn setup_script(&mut self, _data: &ScriptData, _ctx: &mut Self::ScriptContext) -> Result<(), crate::ScriptError> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn update_script_environment(&mut self, _world: crate::ScriptWorldPtr, _data: &ScriptData, _ctx: &mut Self::ScriptContext) -> Result<(), crate::ScriptError> {
|
||||
Ok(())
|
||||
}
|
||||
}
|
|
@ -1,8 +1,9 @@
|
|||
use std::sync::Mutex;
|
||||
|
||||
use mlua::IntoLua;
|
||||
use tracing::debug;
|
||||
|
||||
use crate::{ScriptHost, ScriptError, ScriptWorldPtr};
|
||||
use crate::{ScriptHost, ScriptError, ScriptWorldPtr, ScriptEntity};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct LuaHost;
|
||||
|
@ -53,7 +54,7 @@ impl ScriptHost for LuaHost {
|
|||
}
|
||||
|
||||
let ctx = ctx.lock().expect("Failure to get Lua ScriptContext");
|
||||
try_call_lua_function(&ctx, "init")?;
|
||||
try_call_lua_function(&ctx, "on_init")?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -61,13 +62,20 @@ impl ScriptHost for LuaHost {
|
|||
/// Runs the update step of the lua script.
|
||||
///
|
||||
/// It looks for an `update` function with zero parameters in [`the ScriptContext`] and executes it.
|
||||
fn update_script(&mut self, world: ScriptWorldPtr, script_data: &crate::ScriptData, ctx: &mut Self::ScriptContext, providers: &mut crate::ScriptApiProviders<Self>) -> Result<(), ScriptError> {
|
||||
fn call_script(&mut self, world: ScriptWorldPtr, script_data: &crate::ScriptData,
|
||||
ctx: &mut Self::ScriptContext, providers: &mut crate::ScriptApiProviders<Self>,
|
||||
function_name: &str) -> Result<(), ScriptError> {
|
||||
for provider in providers.apis.iter_mut() {
|
||||
provider.update_script_environment(world.clone(), script_data, ctx)?;
|
||||
}
|
||||
|
||||
|
||||
let ctx = ctx.lock().expect("Failure to get Lua ScriptContext");
|
||||
try_call_lua_function(&ctx, "update")?;
|
||||
|
||||
let globals = ctx.globals();
|
||||
globals.set("world", world.into_lua(&ctx)?)?;
|
||||
globals.set("entity", ScriptEntity(script_data.entity).into_lua(&ctx)?)?;
|
||||
|
||||
try_call_lua_function(&ctx, function_name)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -1,16 +1,13 @@
|
|||
use std::{sync::{Mutex, Arc}, alloc::Layout, ptr::NonNull};
|
||||
use std::{sync::{Mutex, Arc}, ptr::NonNull};
|
||||
|
||||
use lyra_ecs::{World, query::{Res, View, Entities, ResMut}, Component, system::{GraphExecutor, IntoSystem}};
|
||||
use lyra_ecs::{World, system::{GraphExecutor, IntoSystem}};
|
||||
use lyra_resource::ResourceManager;
|
||||
use mlua::{IntoLua, AnyUserDataExt};
|
||||
use tracing::{debug, error};
|
||||
use tracing_subscriber::{layer::SubscriberExt, fmt, filter, util::SubscriberInitExt};
|
||||
use tracing_subscriber::{layer::SubscriberExt, fmt, util::SubscriberInitExt};
|
||||
|
||||
use crate::{ScriptHost, ScriptData, ScriptApiProvider, ScriptApiProviders, ScriptError, ScriptWorldPtr, ScriptList, Script, ScriptContexts};
|
||||
use crate::{ScriptData, ScriptApiProvider, ScriptApiProviders, ScriptError, ScriptList, Script, ScriptContexts};
|
||||
|
||||
use super::{LuaHost, LuaLoader, LuaScript, lua_update_scripts};
|
||||
|
||||
use crate::lyra_engine;
|
||||
use super::{LuaHost, LuaLoader, LuaScript, lua_script_update_stage_system, lua_scripts_create_contexts, LuaContext};
|
||||
|
||||
fn enable_tracing() {
|
||||
tracing_subscriber::registry()
|
||||
|
@ -148,7 +145,7 @@ pub fn lua_print() {
|
|||
|
||||
world.add_resource(host);
|
||||
world.add_resource(providers);
|
||||
world.add_resource(ScriptContexts::<Mutex<mlua::Lua>>::default());
|
||||
world.add_resource(ScriptContexts::<LuaContext>::default());
|
||||
|
||||
let mut res_loader = ResourceManager::new();
|
||||
res_loader.register_loader::<LuaLoader>();
|
||||
|
@ -174,6 +171,7 @@ pub fn lua_print() {
|
|||
world.spawn((scripts,));
|
||||
|
||||
let mut exec = GraphExecutor::new();
|
||||
exec.insert_system("lua_update_scripts", lua_update_scripts.into_system(), &[]);
|
||||
exec.insert_system("lua_create_contexts", lua_scripts_create_contexts.into_system(), &[]);
|
||||
exec.insert_system("lua_update_scripts", lua_script_update_stage_system.into_system(), &["lua_create_contexts"]);
|
||||
exec.execute(NonNull::from(&world), true).unwrap();
|
||||
}
|
|
@ -16,7 +16,13 @@ impl<'lua> mlua::FromLua<'lua> for ScriptEntity {
|
|||
}
|
||||
}
|
||||
|
||||
impl mlua::UserData for ScriptEntity {}
|
||||
impl mlua::UserData for ScriptEntity {
|
||||
fn add_methods<'lua, M: mlua::prelude::LuaUserDataMethods<'lua, Self>>(methods: &mut M) {
|
||||
methods.add_meta_method(mlua::MetaMethod::ToString, |_, this, ()| {
|
||||
Ok(format!("{:?}", this.0))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(thiserror::Error, Debug, Clone)]
|
||||
pub enum WorldError {
|
||||
|
|
|
@ -1,8 +1,12 @@
|
|||
use std::sync::atomic::{AtomicU64, Ordering};
|
||||
|
||||
use lyra_ecs::Component;
|
||||
use lyra_resource::ResHandle;
|
||||
|
||||
use crate::lyra_engine;
|
||||
|
||||
static SCRIPT_ID_COUNTER: AtomicU64 = AtomicU64::new(0);
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Script<T> {
|
||||
res: ResHandle<T>,
|
||||
|
@ -15,7 +19,7 @@ impl<T> Script<T> {
|
|||
Self {
|
||||
res: script,
|
||||
name: name.to_string(),
|
||||
id: 0 // TODO: make a counter
|
||||
id: SCRIPT_ID_COUNTER.fetch_add(1, Ordering::AcqRel)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,14 @@ use lyra_ecs::{world::World, Entity};
|
|||
#[derive(Clone)]
|
||||
pub struct ScriptEntity(pub Entity);
|
||||
|
||||
impl std::ops::Deref for ScriptEntity {
|
||||
type Target = Entity;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ScriptWorldPtr {
|
||||
pub inner: NonNull<World>,
|
||||
|
|
Loading…
Reference in New Issue