use bevy::ecs::resource; use mlua::UserData; use mlua::Lua; use bevy::prelude::*; use mlua::UserDataFields; use mlua::UserDataMethods; use nameof::name_of_type; use std::ops::Deref; use std::ops::DerefMut; use include_dir::{include_dir, Dir}; static DATA_DIR: Dir<'_> = include_dir!("data"); struct Context<'a> { commands: Commands<'a, 'a>, resource: Option<&'a Resource> } #[derive(Resource)] struct Resource { default_script_context: Entity } impl Resource { fn new_from_world(world: &mut World) -> Self { let mut context = Context { commands: world.commands(), resource: Option::None }; let (entity_commands,_) = ScriptContext::new_entity( &mut context ); Resource { default_script_context: entity_commands.id() } } } // Id for this object to the server struct Netlink { } trait Class { // Class name for filtering fn class_name() -> String { name_of_type!(Self).into() } // Create a default object fn new_entity<'a>(context: &'a mut Context) -> (EntityCommands<'a>, Self) where Self: Sized; // fn clone(&self) -> Self; fn add_fields>(_fields: &mut F) {} fn add_methods>(_methods: &mut F) {} } #[derive(Component)] struct Instance { name: String, class: S, entity: Entity, netlink: Netlink } impl UserData for Instance { fn add_fields>(fields: &mut F) { S::add_fields::(fields); } fn add_methods>(methods: &mut M) { S::add_methods::(methods); } } impl Instance { fn new_entity(context: &'_ mut Context) -> Self { let (entity,sub) = S::new_entity(context); Instance { name: S::class_name(), class: sub, entity: entity.id(), netlink: Netlink {}, } } } struct Constructor; impl UserData for Constructor { fn add_methods>(methods: &mut M) { methods.add_method("part",|lua, this: &Constructor, ()| { Ok(IPart::new_entity(lua.app_data_mut::().unwrap().deref_mut())) }); methods.add_method("script",|lua, this: &Constructor, ()| { Ok(IScript::new_entity(lua.app_data_mut::().unwrap().deref_mut())) }); } } #[derive(Resource)] struct ScriptContext { lua: Lua } impl Class for ScriptContext { fn new_entity<'a>(context: &'a mut Context) -> (EntityCommands<'a>,Self) { ( context.commands.spawn_empty(), ScriptContext::new() ) } } impl ScriptContext { fn new() -> Self { let lua = Lua::new(); lua.sandbox(true); let globals = lua.globals(); globals.set("new",Constructor); ScriptContext { lua: lua } } } struct Script { context: Entity } impl Class for Script { fn new_entity<'a>(context: &'a mut Context) -> (EntityCommands<'a>, Self) { ( context.commands.spawn_empty(), Script { context: context.resource.as_ref().unwrap().default_script_context } ) } } // Attachment struct Node; impl Class for Node { fn new_entity<'a>(context: &'a mut Context) -> (EntityCommands<'a>, Self) { ( context.commands.spawn_empty(), Node {} ) } } struct Part { } impl Class for Part { fn new_entity<'a>(context: &'a mut Context) -> (EntityCommands<'a>, Self) { ( context.commands.spawn_empty(), Part {} ) } } impl UserData for Part {} struct Located { class: S } impl UserData for Located { fn add_fields>(fields: &mut F) { S::add_fields(fields); } fn add_methods>(methods: &mut M) { S::add_methods(methods); } } impl Class for Located { fn new_entity<'a>(context: &'a mut Context) -> (EntityCommands<'a>,Self) { let (entity,sub) = S::new_entity(context); ( entity, Located { class: sub } ) } } type IAttachment = Instance>; type IModel = Instance>; type IPart = Instance>; type IContext = Instance; type IScript = Instance