entities
This commit is contained in:
parent
04d8845729
commit
fccc822f9a
8 changed files with 136 additions and 27 deletions
0
assets/tests/lua/entity_variable.lua
Normal file
0
assets/tests/lua/entity_variable.lua
Normal file
0
assets/tests/lua/entity_variable_eval.lua
Normal file
0
assets/tests/lua/entity_variable_eval.lua
Normal file
0
assets/tests/rhai/entity_variable.rhai
Normal file
0
assets/tests/rhai/entity_variable.rhai
Normal file
0
assets/tests/rhai/entity_variable_eval.rhai
Normal file
0
assets/tests/rhai/entity_variable_eval.rhai
Normal file
3
assets/tests/ruby/entity_variable.rb
Normal file
3
assets/tests/ruby/entity_variable.rb
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
def test_func
|
||||||
|
rust_func($entity.index)
|
||||||
|
end
|
||||||
6
assets/tests/ruby/entity_variable_eval.rb
Normal file
6
assets/tests/ruby/entity_variable_eval.rb
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
$index = $entity.index
|
||||||
|
|
||||||
|
def test_func
|
||||||
|
print($index)
|
||||||
|
rust_func($index)
|
||||||
|
end
|
||||||
|
|
@ -12,22 +12,23 @@ use std::{
|
||||||
|
|
||||||
use bevy::{
|
use bevy::{
|
||||||
asset::Asset,
|
asset::Asset,
|
||||||
ecs::{component::Component, resource::Resource, schedule::ScheduleLabel},
|
ecs::{component::Component, entity::Entity, resource::Resource, schedule::ScheduleLabel},
|
||||||
|
math::Vec3,
|
||||||
reflect::TypePath,
|
reflect::TypePath,
|
||||||
tasks::futures_lite::io,
|
tasks::futures_lite::io,
|
||||||
};
|
};
|
||||||
use magnus::prelude::*;
|
|
||||||
use magnus::{
|
use magnus::{
|
||||||
block::Proc, data_type_builder, function, value::Lazy, DataType, DataTypeFunctions, IntoValue,
|
block::Proc, data_type_builder, function, value::Lazy, DataType, DataTypeFunctions, IntoValue,
|
||||||
RClass, Ruby, TryConvert, TypedData,
|
RClass, Ruby, TryConvert, TypedData,
|
||||||
};
|
};
|
||||||
|
use magnus::{method, prelude::*};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
assets::GetExtensions,
|
assets::GetExtensions,
|
||||||
callback::{FromRuntimeValueWithEngine, IntoRuntimeValueWithEngine},
|
callback::{FromRuntimeValueWithEngine, IntoRuntimeValueWithEngine},
|
||||||
promise::Promise,
|
promise::Promise,
|
||||||
FuncArgs, Runtime, ScriptingError,
|
FuncArgs, Runtime, ScriptingError, ENTITY_VAR_NAME,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Resource)]
|
#[derive(Resource)]
|
||||||
|
|
@ -142,6 +143,32 @@ fn then(r_self: magnus::Value) -> magnus::Value {
|
||||||
.into_value()
|
.into_value()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[magnus::wrap(class = "BevyEntity")]
|
||||||
|
pub struct BevyEntity(pub Entity);
|
||||||
|
|
||||||
|
impl BevyEntity {
|
||||||
|
fn index(&self) -> u32 {
|
||||||
|
self.0.index()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[magnus::wrap(class = "BevyVec3")]
|
||||||
|
pub struct BevyVec3(pub Vec3);
|
||||||
|
|
||||||
|
impl BevyVec3 {
|
||||||
|
fn x(&self) -> f32 {
|
||||||
|
self.0.x
|
||||||
|
}
|
||||||
|
|
||||||
|
fn y(&self) -> f32 {
|
||||||
|
self.0.y
|
||||||
|
}
|
||||||
|
|
||||||
|
fn z(&self) -> f32 {
|
||||||
|
self.0.z
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Default for RubyRuntime {
|
impl Default for RubyRuntime {
|
||||||
fn default() -> Self {
|
fn default() -> Self {
|
||||||
let (lock, cvar) = &*Arc::clone(&RUBY_THREAD);
|
let (lock, cvar) = &*Arc::clone(&RUBY_THREAD);
|
||||||
|
|
@ -159,29 +186,20 @@ impl Default for RubyRuntime {
|
||||||
promise
|
promise
|
||||||
.define_method("and_then", magnus::method!(then, 0))
|
.define_method("and_then", magnus::method!(then, 0))
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
|
let entity = ruby
|
||||||
|
.define_class("BevyEntity", ruby.class_object())
|
||||||
|
.unwrap();
|
||||||
|
entity
|
||||||
|
.define_method("index", method!(BevyEntity::index, 0))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let vec3 = ruby.define_class("BevyVec3", ruby.class_object()).unwrap();
|
||||||
|
vec3.define_method("x", method!(BevyVec3::x, 0)).unwrap();
|
||||||
|
vec3.define_method("y", method!(BevyVec3::y, 0)).unwrap();
|
||||||
|
vec3.define_method("z", method!(BevyVec3::z, 0)).unwrap();
|
||||||
}));
|
}));
|
||||||
// TODO: add test for those types for every runtime
|
// TODO: add test for those types for every runtime
|
||||||
// engine
|
|
||||||
// .register_userdata_type::<BevyEntity>(|typ| {
|
|
||||||
// typ.add_field_method_get("index", |_, entity| Ok(entity.0.index()));
|
|
||||||
// })
|
|
||||||
// .expect("Failed to register BevyEntity userdata type");
|
|
||||||
//
|
|
||||||
// engine
|
|
||||||
// .register_userdata_type::<Promise<(), LuaValue>>(|typ| {
|
|
||||||
// typ.add_method_mut("and_then", |engine, promise, callback: Function| {
|
|
||||||
// Ok(Promise::then(promise, LuaValue::new(engine, callback)))
|
|
||||||
// });
|
|
||||||
// })
|
|
||||||
// .expect("Failed to register Promise userdata type");
|
|
||||||
//
|
|
||||||
// engine
|
|
||||||
// .register_userdata_type::<BevyVec3>(|typ| {
|
|
||||||
// typ.add_field_method_get("x", |_engine, vec| Ok(vec.0.x));
|
|
||||||
// typ.add_field_method_get("y", |_engine, vec| Ok(vec.0.y));
|
|
||||||
// typ.add_field_method_get("z", |_engine, vec| Ok(vec.0.z));
|
|
||||||
// })
|
|
||||||
// .expect("Failed to register BevyVec3 userdata type");
|
|
||||||
// let vec3_constructor = engine
|
// let vec3_constructor = engine
|
||||||
// .create_function(|_, (x, y, z)| Ok(BevyVec3(Vec3::new(x, y, z))))
|
// .create_function(|_, (x, y, z)| Ok(BevyVec3(Vec3::new(x, y, z))))
|
||||||
// .expect("Failed to create Vec3 constructor");
|
// .expect("Failed to create Vec3 constructor");
|
||||||
|
|
@ -262,14 +280,23 @@ impl Runtime for RubyRuntime {
|
||||||
fn eval(
|
fn eval(
|
||||||
&self,
|
&self,
|
||||||
script: &Self::ScriptAsset,
|
script: &Self::ScriptAsset,
|
||||||
_entity: bevy::prelude::Entity,
|
entity: bevy::prelude::Entity,
|
||||||
) -> Result<Self::ScriptData, crate::ScriptingError> {
|
) -> Result<Self::ScriptData, crate::ScriptingError> {
|
||||||
let script = script.0.clone();
|
let script = script.0.clone();
|
||||||
self.ruby_thread
|
self.ruby_thread
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.execute(Box::new(move |ruby| {
|
.execute(Box::new(move |ruby| {
|
||||||
|
let var = ruby
|
||||||
|
.define_variable(ENTITY_VAR_NAME, BevyEntity(entity))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let value = ruby.eval::<magnus::value::Value>(&script).unwrap();
|
let value = ruby.eval::<magnus::value::Value>(&script).unwrap();
|
||||||
|
|
||||||
|
// SAFETY: this is guaranteed to be executed on a single thread
|
||||||
|
// so should be safe according to Magnus documentation
|
||||||
|
unsafe { *var = ruby.qnil().as_value() };
|
||||||
|
|
||||||
RubyValue::new(value)
|
RubyValue::new(value)
|
||||||
}));
|
}));
|
||||||
Ok(RubyScriptData)
|
Ok(RubyScriptData)
|
||||||
|
|
@ -336,7 +363,7 @@ impl Runtime for RubyRuntime {
|
||||||
&self,
|
&self,
|
||||||
name: &str,
|
name: &str,
|
||||||
_script_data: &mut Self::ScriptData,
|
_script_data: &mut Self::ScriptData,
|
||||||
_entity: bevy::prelude::Entity,
|
entity: bevy::prelude::Entity,
|
||||||
args: impl for<'a> crate::FuncArgs<'a, Self::Value, Self> + Send + 'static,
|
args: impl for<'a> crate::FuncArgs<'a, Self::Value, Self> + Send + 'static,
|
||||||
) -> Result<Self::Value, crate::ScriptingError> {
|
) -> Result<Self::Value, crate::ScriptingError> {
|
||||||
let name = name.to_string();
|
let name = name.to_string();
|
||||||
|
|
@ -344,6 +371,10 @@ impl Runtime for RubyRuntime {
|
||||||
.as_ref()
|
.as_ref()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.execute(Box::new(move |ruby| {
|
.execute(Box::new(move |ruby| {
|
||||||
|
let var = ruby
|
||||||
|
.define_variable(ENTITY_VAR_NAME, BevyEntity(entity))
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let args: Vec<_> = args
|
let args: Vec<_> = args
|
||||||
.parse(&ruby)
|
.parse(&ruby)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
|
|
@ -355,6 +386,11 @@ impl Runtime for RubyRuntime {
|
||||||
.map_err(|e| {
|
.map_err(|e| {
|
||||||
ScriptingError::RuntimeError(Box::new(io::Error::other(e.to_string())))
|
ScriptingError::RuntimeError(Box::new(io::Error::other(e.to_string())))
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
|
// SAFETY: this is guaranteed to be executed on a single thread
|
||||||
|
// so should be safe according to Magnus documentation
|
||||||
|
unsafe { *var = ruby.qnil().as_value() };
|
||||||
|
|
||||||
Ok(RubyValue::new(return_value))
|
Ok(RubyValue::new(return_value))
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
@ -391,7 +427,7 @@ impl Runtime for RubyRuntime {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub mod prelude {
|
pub mod prelude {
|
||||||
pub use super::{RubyRuntime, RubyScript, RubyScriptData};
|
pub use super::{BevyEntity, BevyVec3, RubyRuntime, RubyScript, RubyScriptData};
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: TryConvert> FromRuntimeValueWithEngine<'_, RubyRuntime> for T {
|
impl<T: TryConvert> FromRuntimeValueWithEngine<'_, RubyRuntime> for T {
|
||||||
|
|
|
||||||
|
|
@ -378,6 +378,70 @@ macro_rules! scripting_tests {
|
||||||
1
|
1
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn entity_variable_is_available_in_callback() {
|
||||||
|
let mut app = build_test_app();
|
||||||
|
|
||||||
|
#[derive(Default, Resource)]
|
||||||
|
struct State {
|
||||||
|
index: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
app.world_mut().init_resource::<State>();
|
||||||
|
|
||||||
|
app.add_scripting::<$runtime>(|runtime| {
|
||||||
|
runtime.add_function(
|
||||||
|
String::from("rust_func"),
|
||||||
|
|In((index,)): In<(u32,)>, mut res: ResMut<State>| {
|
||||||
|
res.index = index;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
let entity = run_script::<$runtime, _, _>(
|
||||||
|
&mut app,
|
||||||
|
format!("tests/{}/entity_variable.{}", $script, $extension).to_string(),
|
||||||
|
call_script_on_update_from_rust::<$runtime>,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
app.world().get_resource::<State>().unwrap().index,
|
||||||
|
entity.index()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn entity_variable_is_available_in_eval() {
|
||||||
|
let mut app = build_test_app();
|
||||||
|
|
||||||
|
#[derive(Default, Resource)]
|
||||||
|
struct State {
|
||||||
|
index: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
app.world_mut().init_resource::<State>();
|
||||||
|
|
||||||
|
app.add_scripting::<$runtime>(|runtime| {
|
||||||
|
runtime.add_function(
|
||||||
|
String::from("rust_func"),
|
||||||
|
|In((index,)): In<(u32,)>, mut res: ResMut<State>| {
|
||||||
|
res.index = index;
|
||||||
|
},
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
let entity = run_script::<$runtime, _, _>(
|
||||||
|
&mut app,
|
||||||
|
format!("tests/{}/entity_variable_eval.{}", $script, $extension).to_string(),
|
||||||
|
call_script_on_update_from_rust::<$runtime>,
|
||||||
|
);
|
||||||
|
|
||||||
|
assert_eq!(
|
||||||
|
app.world().get_resource::<State>().unwrap().index,
|
||||||
|
entity.index()
|
||||||
|
);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue