.
This commit is contained in:
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
# Default ignored files
|
||||||
|
/shelf/
|
||||||
|
/workspace.xml
|
||||||
|
# Editor-based HTTP Client requests
|
||||||
|
/httpRequests/
|
||||||
|
# Datasource local storage ignored files
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
11
.idea/bevy2.iml
generated
Normal file
11
.idea/bevy2.iml
generated
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="EMPTY_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/bevy2.iml" filepath="$PROJECT_DIR$/.idea/bevy2.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -310,6 +310,7 @@ dependencies = [
|
|||||||
"include_dir",
|
"include_dir",
|
||||||
"mlua",
|
"mlua",
|
||||||
"nameof",
|
"nameof",
|
||||||
|
"thiserror 2.0.18",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ bevy = { version = "0.16", features = ["file_watcher"] }
|
|||||||
include_dir = "0.7.4"
|
include_dir = "0.7.4"
|
||||||
mlua = { version = "0.11.5", features = ["luau","luau-jit","luau-vector4","serde","send"] }
|
mlua = { version = "0.11.5", features = ["luau","luau-jit","luau-vector4","serde","send"] }
|
||||||
nameof = "1.3.0"
|
nameof = "1.3.0"
|
||||||
|
thiserror = "2.0.18"
|
||||||
|
|
||||||
[profile.dev.package."*"]
|
[profile.dev.package."*"]
|
||||||
opt-level = 3
|
opt-level = 3
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
use bevy::ecs::resource;
|
||||||
use mlua::UserData;
|
use mlua::UserData;
|
||||||
use mlua::Lua;
|
use mlua::Lua;
|
||||||
use bevy::prelude::*;
|
use bevy::prelude::*;
|
||||||
@@ -11,16 +12,23 @@ use include_dir::{include_dir, Dir};
|
|||||||
|
|
||||||
static DATA_DIR: Dir<'_> = include_dir!("data");
|
static DATA_DIR: Dir<'_> = include_dir!("data");
|
||||||
|
|
||||||
struct BevyContext<'a> {
|
struct Context<'a> {
|
||||||
commands: Commands<'a, 'a>
|
commands: Commands<'a, 'a>,
|
||||||
|
resource: Option<&'a Resource>
|
||||||
}
|
}
|
||||||
impl<'a> BevyContext<'a> {
|
|
||||||
fn from_raw(commands: Commands<'a,'a>) -> Self {
|
#[derive(Resource)]
|
||||||
BevyContext { commands: commands }
|
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()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
/*fn get_instance<T>(&self, entity: Entity) -> &T {
|
|
||||||
self.commands.entity(entity).
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Id for this object to the server
|
// Id for this object to the server
|
||||||
@@ -31,7 +39,7 @@ trait Class {
|
|||||||
// Class name for filtering
|
// Class name for filtering
|
||||||
fn class_name() -> String { name_of_type!(Self).into() }
|
fn class_name() -> String { name_of_type!(Self).into() }
|
||||||
// Create a default object
|
// Create a default object
|
||||||
fn new_entity<'a>(context: &BevyContext) -> (EntityCommands<'a>, Self);
|
fn new_entity<'a>(context: &'a mut Context) -> (EntityCommands<'a>, Self) where Self: Sized;
|
||||||
// fn clone(&self) -> Self;
|
// fn clone(&self) -> Self;
|
||||||
fn add_fields<T, F: UserDataFields<T>>(_fields: &mut F) {}
|
fn add_fields<T, F: UserDataFields<T>>(_fields: &mut F) {}
|
||||||
fn add_methods<T, F: UserDataMethods<T>>(_methods: &mut F) {}
|
fn add_methods<T, F: UserDataMethods<T>>(_methods: &mut F) {}
|
||||||
@@ -53,7 +61,7 @@ impl<S: Class> UserData for Instance<S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<S: Class> Instance<S> {
|
impl<S: Class> Instance<S> {
|
||||||
fn new(context: &BevyContext) -> Self {
|
fn new_entity(context: &'_ mut Context) -> Self {
|
||||||
let (entity,sub) = S::new_entity(context);
|
let (entity,sub) = S::new_entity(context);
|
||||||
Instance {
|
Instance {
|
||||||
name: S::class_name(),
|
name: S::class_name(),
|
||||||
@@ -68,9 +76,11 @@ struct Constructor;
|
|||||||
|
|
||||||
impl UserData for Constructor {
|
impl UserData for Constructor {
|
||||||
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
fn add_methods<M: UserDataMethods<Self>>(methods: &mut M) {
|
||||||
methods.add_method("part", |lua, this, ()| {
|
methods.add_method("part",|lua, this: &Constructor, ()| {
|
||||||
let part = IPart::new()
|
Ok(IPart::new_entity(lua.app_data_mut::<Context>().unwrap().deref_mut()))
|
||||||
|
});
|
||||||
|
methods.add_method("script",|lua, this: &Constructor, ()| {
|
||||||
|
Ok(IScript::new_entity(lua.app_data_mut::<Context>().unwrap().deref_mut()))
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -80,7 +90,7 @@ struct ScriptContext {
|
|||||||
lua: Lua
|
lua: Lua
|
||||||
}
|
}
|
||||||
impl Class for ScriptContext {
|
impl Class for ScriptContext {
|
||||||
fn new_entity(context: &BevyContext) -> (EntityCommands<'_>,Self) {
|
fn new_entity<'a>(context: &'a mut Context) -> (EntityCommands<'a>,Self) {
|
||||||
( context.commands.spawn_empty(), ScriptContext::new() )
|
( context.commands.spawn_empty(), ScriptContext::new() )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -98,21 +108,30 @@ struct Script {
|
|||||||
context: Entity
|
context: Entity
|
||||||
}
|
}
|
||||||
impl Class for Script {
|
impl Class for Script {
|
||||||
fn new_entity(context: &BevyContext) -> (Entity, Self) {
|
fn new_entity<'a>(context: &'a mut Context) -> (EntityCommands<'a>, Self) {
|
||||||
( context.)
|
(
|
||||||
|
context.commands.spawn_empty(),
|
||||||
|
Script {
|
||||||
|
context: context.resource.as_ref().unwrap().default_script_context
|
||||||
|
}
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Attachment
|
// Attachment
|
||||||
struct Node;
|
struct Node;
|
||||||
impl Class for Node {}
|
impl Class for Node {
|
||||||
|
fn new_entity<'a>(context: &'a mut Context) -> (EntityCommands<'a>, Self) {
|
||||||
|
( context.commands.spawn_empty(), Node {} )
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct Part {
|
struct Part {
|
||||||
|
|
||||||
}
|
}
|
||||||
impl Class for Part {
|
impl Class for Part {
|
||||||
fn new_entity(context: &BevyContext) -> Self {
|
fn new_entity<'a>(context: &'a mut Context) -> (EntityCommands<'a>, Self) {
|
||||||
commands.spawn()
|
( context.commands.spawn_empty(), Part {} )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl UserData for Part {}
|
impl UserData for Part {}
|
||||||
@@ -129,9 +148,9 @@ impl<S: Class> UserData for Located<S> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl<S: Class> Class for Located<S> {
|
impl<S: Class> Class for Located<S> {
|
||||||
fn new_entity(context: &BevyContext) -> Self {
|
fn new_entity<'a>(context: &'a mut Context) -> (EntityCommands<'a>,Self) {
|
||||||
let (entity,sub) = S::new_entity(context);
|
let (entity,sub) = S::new_entity(context);
|
||||||
Located { class: S::new_entity(context), }
|
( entity, Located { class: sub } )
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -152,15 +171,27 @@ enum AnyInstance {
|
|||||||
Part(IPart)
|
Part(IPart)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn script_executor() {
|
fn script_executor(mut commands: Commands, resource: Res<Resource>) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fn script_test(commands: Commands, resource: Res<Resource>) {
|
||||||
|
let mut context = Context {commands: commands, resource: Some(resource.as_ref())};
|
||||||
|
IScript::new_entity(&mut context);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn setup(world: &mut World) {
|
||||||
|
let res = Resource::new_from_world(world);
|
||||||
|
world.insert_resource(res);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct DuckPlugin;
|
pub struct DuckPlugin;
|
||||||
|
|
||||||
impl Plugin for DuckPlugin {
|
impl Plugin for DuckPlugin {
|
||||||
fn build(&self, app: &mut App) {
|
fn build(&self, app: &mut App) {
|
||||||
app.add_systems(Update,(script_executor));
|
app.add_systems(Startup,setup);
|
||||||
app.insert_resource(ScriptContext::new_entity())
|
app.add_systems(Update,script_executor);
|
||||||
|
app.add_systems(Startup,script_test);
|
||||||
|
app.insert_resource(ScriptContext::new());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
49
src/duck/instance.rs
Normal file
49
src/duck/instance.rs
Normal file
@@ -0,0 +1,49 @@
|
|||||||
|
use bevy::prelude::*;
|
||||||
|
use mlua::prelude::*;
|
||||||
|
|
||||||
|
use crate::duck::part::*;
|
||||||
|
use crate::duck::script::*;
|
||||||
|
|
||||||
|
pub trait Class {
|
||||||
|
fn new(entity: EntityWorldMut) -> AnyInstance;
|
||||||
|
fn add_fields<T, F: LuaUserDataFields<T>>(_fields: &mut F) {}
|
||||||
|
fn add_methods<T, F: LuaUserDataMethods<T>>(_methods: &mut F) {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Instance<S: Class>(pub S);
|
||||||
|
|
||||||
|
impl<S: Class> LuaUserData for Instance<S> {
|
||||||
|
fn add_fields<F: LuaUserDataFields<Self>>(fields: &mut F) {
|
||||||
|
S::add_fields(fields)
|
||||||
|
}
|
||||||
|
fn add_methods<M: LuaUserDataMethods<Self>>(methods: &mut M) {
|
||||||
|
S::add_methods(methods)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: Class> Instance<S> {
|
||||||
|
fn new_entity(world: &mut World) -> Entity {
|
||||||
|
let mut entity = world.spawn_empty();
|
||||||
|
entity.entry().or_insert(Name::new("Instance"));
|
||||||
|
entity.insert(AnyInstance {sub: S::new(entity)});
|
||||||
|
return entity.id();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Component)]
|
||||||
|
pub enum AnyInstance {
|
||||||
|
Script(Instance<Script>),
|
||||||
|
Part(Instance<Located<Part>>)
|
||||||
|
}
|
||||||
|
impl AnyInstance {
|
||||||
|
fn new(instance: Instance<Script>) -> AnyInstance {
|
||||||
|
AnyInstance::Script(instance)
|
||||||
|
}
|
||||||
|
fn new(instance: Instance<Located<Part>>) -> AnyInstance {
|
||||||
|
AnyInstance::Part(instance)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setup(app: &mut App) {
|
||||||
|
|
||||||
|
}
|
||||||
28
src/duck/mod.rs
Normal file
28
src/duck/mod.rs
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
use mlua::UserData;
|
||||||
|
use mlua::Lua;
|
||||||
|
use mlua::UserDataFields;
|
||||||
|
use bevy::prelude::*;
|
||||||
|
use mlua::UserDataMethods;
|
||||||
|
use nameof::name_of_type;
|
||||||
|
use std::ops::Deref;
|
||||||
|
use std::ops::DerefMut;
|
||||||
|
use thiserror::Error;
|
||||||
|
|
||||||
|
mod part;
|
||||||
|
mod script;
|
||||||
|
mod instance;
|
||||||
|
|
||||||
|
use include_dir::{include_dir, Dir};
|
||||||
|
|
||||||
|
static DATA_DIR: Dir<'_> = include_dir!("data");
|
||||||
|
|
||||||
|
pub struct DuckPlugin;
|
||||||
|
|
||||||
|
impl Plugin for DuckPlugin {
|
||||||
|
fn build(&self, app: &mut App) {
|
||||||
|
instance::setup(app);
|
||||||
|
part::setup(app);
|
||||||
|
script::setup(app);
|
||||||
|
instance::setup(app);
|
||||||
|
}
|
||||||
|
}
|
||||||
31
src/duck/part.rs
Normal file
31
src/duck/part.rs
Normal file
@@ -0,0 +1,31 @@
|
|||||||
|
use bevy::prelude::*;
|
||||||
|
use crate::duck::instance::*;
|
||||||
|
|
||||||
|
struct DefaultMaterial {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Located<S: Class>(pub S)
|
||||||
|
impl<S: Class> Class for Located<S> {
|
||||||
|
fn new(mut entity: EntityWorldMut) -> AnyInstance {
|
||||||
|
entity.insert(Transform::IDENTITY);
|
||||||
|
S::new(entity)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Part();
|
||||||
|
impl Class for Part {
|
||||||
|
fn new(mut entity: EntityWorldMut) -> AnyInstance {
|
||||||
|
let mut meshes = entity.world_mut().get_resource_mut::<Assets<Mesh>>().unwrap();
|
||||||
|
let mut materials = entity.world_mut().get_resource_mut::<Assets<StandardMaterial>>().unwrap();
|
||||||
|
entity.insert((
|
||||||
|
Mesh3d(meshes.add(Cuboid::new(2.0, 1.0, 4.0))),
|
||||||
|
MeshMaterial3d(materials.add(Color::srgb_u8(124, 144, 255)))
|
||||||
|
));
|
||||||
|
AnyInstance::Part(Instance(Located(Part())))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setup(app: &mut App) {
|
||||||
|
|
||||||
|
}
|
||||||
65
src/duck/script.rs
Normal file
65
src/duck/script.rs
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
use bevy::asset::AsyncReadExt;
|
||||||
|
use bevy::prelude::*;
|
||||||
|
use bevy::asset::{io::Reader, AssetLoader, LoadContext};
|
||||||
|
use thiserror::Error;
|
||||||
|
use crate::duck::instance::*;
|
||||||
|
|
||||||
|
#[derive(Asset, TypePath, Debug)]
|
||||||
|
struct ScriptAsset {
|
||||||
|
source: String
|
||||||
|
}
|
||||||
|
|
||||||
|
#[non_exhaustive]
|
||||||
|
#[derive(Debug, Error)]
|
||||||
|
enum ScriptAssetLoaderError {
|
||||||
|
#[error("Could not load script file: {0}")]
|
||||||
|
Io(#[from] std::io::Error)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Default, TypePath)]
|
||||||
|
struct ScriptAssetLoader;
|
||||||
|
impl AssetLoader for ScriptAssetLoader {
|
||||||
|
type Asset = ScriptAsset;
|
||||||
|
type Settings = ();
|
||||||
|
type Error = ScriptAssetLoaderError;
|
||||||
|
|
||||||
|
async fn load(
|
||||||
|
&self,
|
||||||
|
reader: &mut dyn Reader,
|
||||||
|
_settings: &(),
|
||||||
|
_load_context: &mut LoadContext<'_>
|
||||||
|
) -> Result<Self::Asset, Self::Error> {
|
||||||
|
info!("Loading Script...");
|
||||||
|
let mut raw = String::new();
|
||||||
|
reader.read_to_string(&mut raw).await?;
|
||||||
|
Ok(ScriptAsset { source: Source { raw } })
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Script();
|
||||||
|
impl Class for Script {
|
||||||
|
fn new(mut entity: EntityWorldMut) -> AnyInstance {
|
||||||
|
entity.entry().or_insert(
|
||||||
|
);
|
||||||
|
AnyInstance::Script(Instance(Script()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Resource, Component)]
|
||||||
|
struct DefaultScriptAsset(ScriptAsset);
|
||||||
|
|
||||||
|
pub fn startup(
|
||||||
|
mut script_assets: ResMut<Assets<ScriptAsset>>,
|
||||||
|
mut commands: Commands
|
||||||
|
) {
|
||||||
|
commands.insert_resource::<DefaultScriptAsset>(
|
||||||
|
DefaultScriptAsset(script_assets.add(
|
||||||
|
ScriptAsset { source: "print(\"Hello world!\")".to_string() }
|
||||||
|
))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn setup(app: &mut App) {
|
||||||
|
app.init_asset::<ScriptAsset>();
|
||||||
|
app.init_asset_loader::<ScriptAssetLoader>();
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user