Compare commits
5 commits
1ea7e30c63
...
783183975a
| Author | SHA1 | Date | |
|---|---|---|---|
| 783183975a | |||
| 10985ca777 | |||
| da759a7e0b | |||
| 80e753812a | |||
| 9e29b803b6 |
1 changed files with 61 additions and 71 deletions
|
|
@ -1,4 +1,3 @@
|
||||||
// TODO: use funcall_public?
|
|
||||||
use std::{
|
use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
ffi::CString,
|
ffi::CString,
|
||||||
|
|
@ -6,8 +5,7 @@ use std::{
|
||||||
thread::{self, JoinHandle},
|
thread::{self, JoinHandle},
|
||||||
};
|
};
|
||||||
|
|
||||||
use ::magnus::{error::IntoError, typed_data::Inspect, value::Opaque};
|
use ::magnus::{typed_data::Inspect, value::Opaque};
|
||||||
use anyhow::anyhow;
|
|
||||||
use bevy::{
|
use bevy::{
|
||||||
asset::Asset,
|
asset::Asset,
|
||||||
ecs::{component::Component, entity::Entity, resource::Resource, schedule::ScheduleLabel},
|
ecs::{component::Component, entity::Entity, resource::Resource, schedule::ScheduleLabel},
|
||||||
|
|
@ -21,7 +19,7 @@ use magnus::{
|
||||||
value::{Lazy, ReprValue},
|
value::{Lazy, ReprValue},
|
||||||
};
|
};
|
||||||
use magnus::{method, prelude::*};
|
use magnus::{method, prelude::*};
|
||||||
use rb_sys::{VALUE, rb_backtrace, rb_make_backtrace, ruby_init_stack};
|
use rb_sys::{VALUE, ruby_init_stack};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|
@ -224,17 +222,15 @@ impl TryConvert for BevyVec3 {
|
||||||
|
|
||||||
impl From<magnus::Error> for ScriptingError {
|
impl From<magnus::Error> for ScriptingError {
|
||||||
fn from(value: magnus::Error) -> Self {
|
fn from(value: magnus::Error) -> Self {
|
||||||
// TODO: DRY
|
|
||||||
ScriptingError::RuntimeError(
|
ScriptingError::RuntimeError(
|
||||||
value.inspect(),
|
value.inspect(),
|
||||||
value
|
value
|
||||||
.value()
|
.value()
|
||||||
.unwrap()
|
.expect("No error value")
|
||||||
.funcall::<_, _, magnus::RArray>("backtrace", ()) // TODO: is there an API for this
|
.funcall::<_, _, magnus::RArray>("backtrace", ())
|
||||||
// somehwere
|
.expect("Failed to get backtrace")
|
||||||
.unwrap()
|
|
||||||
.to_vec::<String>()
|
.to_vec::<String>()
|
||||||
.unwrap()
|
.expect("Failed to convert backtrace to vec of strings")
|
||||||
.join("\n"),
|
.join("\n"),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -328,6 +324,25 @@ impl RubyRuntime {
|
||||||
.expect("No Ruby thread")
|
.expect("No Ruby thread")
|
||||||
.execute(Box::new(move |mut ruby| f(&mut ruby)))
|
.execute(Box::new(move |mut ruby| f(&mut ruby)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn with_current_entity<T>(ruby: &Ruby, entity: Entity, f: impl FnOnce() -> T) -> T {
|
||||||
|
let var = ruby
|
||||||
|
.class_object()
|
||||||
|
.const_get::<_, RModule>("Bevy")
|
||||||
|
.expect("Failed to get Bevy module")
|
||||||
|
.const_get::<_, RClass>("Entity")
|
||||||
|
.expect("Failed to get Entity class");
|
||||||
|
|
||||||
|
var.ivar_set("_current", BevyEntity(entity))
|
||||||
|
.expect("Failed to set current entity handle");
|
||||||
|
|
||||||
|
let result = f();
|
||||||
|
|
||||||
|
var.ivar_set("_current", ruby.qnil().as_value())
|
||||||
|
.expect("Failed to unset current entity handle");
|
||||||
|
|
||||||
|
result
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Runtime for RubyRuntime {
|
impl Runtime for RubyRuntime {
|
||||||
|
|
@ -376,33 +391,10 @@ impl Runtime for RubyRuntime {
|
||||||
) -> Result<Self::ScriptData, crate::ScriptingError> {
|
) -> Result<Self::ScriptData, crate::ScriptingError> {
|
||||||
let script = script.0.clone();
|
let script = script.0.clone();
|
||||||
self.execute_in_thread(Box::new(move |ruby: &Ruby| {
|
self.execute_in_thread(Box::new(move |ruby: &Ruby| {
|
||||||
// TODO: refactor
|
Self::with_current_entity(ruby, entity, || {
|
||||||
let var = ruby
|
ruby.eval::<magnus::value::Value>(&script)
|
||||||
.class_object()
|
.map_err(|e| <magnus::Error as Into<ScriptingError>>::into(e))
|
||||||
.const_get::<_, RModule>("Bevy")
|
|
||||||
.expect("Failed to get Bevy module")
|
|
||||||
.const_get::<_, RClass>("Entity")
|
|
||||||
.expect("Failed to get Entity class");
|
|
||||||
|
|
||||||
var.ivar_set("_current", BevyEntity(entity))
|
|
||||||
.expect("Failed to set current entity handle");
|
|
||||||
|
|
||||||
ruby.eval::<magnus::value::Value>(&script).map_err(|e| {
|
|
||||||
ScriptingError::RuntimeError(
|
|
||||||
e.inspect(),
|
|
||||||
e.value()
|
|
||||||
.unwrap()
|
|
||||||
.funcall::<_, _, magnus::RArray>("backtrace", ())
|
|
||||||
.unwrap()
|
|
||||||
.to_vec::<String>()
|
|
||||||
.unwrap()
|
|
||||||
.join("\n"),
|
|
||||||
)
|
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
var.ivar_set("_current", ruby.qnil().as_value())
|
|
||||||
.expect("Failed to unset current entity handle");
|
|
||||||
|
|
||||||
Ok::<Self::ScriptData, ScriptingError>(RubyScriptData)
|
Ok::<Self::ScriptData, ScriptingError>(RubyScriptData)
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|
@ -439,11 +431,19 @@ impl Runtime for RubyRuntime {
|
||||||
fn callback(args: &[magnus::Value]) -> magnus::Value {
|
fn callback(args: &[magnus::Value]) -> magnus::Value {
|
||||||
let ruby = magnus::Ruby::get()
|
let ruby = magnus::Ruby::get()
|
||||||
.expect("Failed to get a handle to Ruby API while processing callback");
|
.expect("Failed to get a handle to Ruby API while processing callback");
|
||||||
let method_name: magnus::value::StaticSymbol =
|
let method_name: magnus::value::StaticSymbol = ruby
|
||||||
ruby.class_object().funcall("__method__", ()).unwrap();
|
.class_object()
|
||||||
let method_name = method_name.name().unwrap();
|
.funcall("__method__", ())
|
||||||
let callbacks = RUBY_CALLBACKS.lock().unwrap();
|
.expect("Failed to get currently called method name symbol from Ruby");
|
||||||
let f = callbacks.get(method_name).unwrap();
|
let method_name = method_name
|
||||||
|
.name()
|
||||||
|
.expect("Failed to convert method symbol to string");
|
||||||
|
let callbacks = RUBY_CALLBACKS
|
||||||
|
.lock()
|
||||||
|
.expect("Failed to lock callbacks when executing a script callback");
|
||||||
|
let f = callbacks
|
||||||
|
.get(method_name)
|
||||||
|
.expect("No callback found to execute with specified name");
|
||||||
let result = f(
|
let result = f(
|
||||||
(),
|
(),
|
||||||
args.iter()
|
args.iter()
|
||||||
|
|
@ -471,23 +471,15 @@ impl Runtime for RubyRuntime {
|
||||||
) -> Result<Self::Value, crate::ScriptingError> {
|
) -> Result<Self::Value, crate::ScriptingError> {
|
||||||
let name = name.to_string();
|
let name = name.to_string();
|
||||||
self.execute_in_thread(Box::new(move |ruby: &Ruby| {
|
self.execute_in_thread(Box::new(move |ruby: &Ruby| {
|
||||||
// TOOD: refactor
|
let return_value = Self::with_current_entity(ruby, entity, || {
|
||||||
let var = ruby
|
let args: Vec<_> = args
|
||||||
.class_object()
|
.parse(ruby)
|
||||||
.const_get::<_, RModule>("Bevy")
|
.into_iter()
|
||||||
.unwrap()
|
.map(|a| ruby.get_inner(a.0))
|
||||||
.const_get::<_, RClass>("Entity")
|
.collect();
|
||||||
.unwrap();
|
|
||||||
var.ivar_set("_current", BevyEntity(entity)).unwrap();
|
|
||||||
|
|
||||||
let args: Vec<_> = args
|
ruby.class_object().funcall(name, args.as_slice())
|
||||||
.parse(ruby)
|
})?;
|
||||||
.into_iter()
|
|
||||||
.map(|a| ruby.get_inner(a.0))
|
|
||||||
.collect();
|
|
||||||
let return_value: magnus::Value = ruby.class_object().funcall(name, args.as_slice())?;
|
|
||||||
|
|
||||||
var.ivar_set("_current", ruby.qnil().as_value()).unwrap();
|
|
||||||
|
|
||||||
Ok(RubyValue::new(return_value))
|
Ok(RubyValue::new(return_value))
|
||||||
}))
|
}))
|
||||||
|
|
@ -501,19 +493,16 @@ impl Runtime for RubyRuntime {
|
||||||
) -> Result<Self::Value, crate::ScriptingError> {
|
) -> Result<Self::Value, crate::ScriptingError> {
|
||||||
let value = value.clone();
|
let value = value.clone();
|
||||||
|
|
||||||
self.ruby_thread
|
self.execute_in_thread(move |ruby| {
|
||||||
.as_ref()
|
let f: Proc = TryConvert::try_convert(ruby.get_inner(value.0))?;
|
||||||
.unwrap()
|
|
||||||
.execute(Box::new(move |ruby| {
|
|
||||||
let f: Proc = TryConvert::try_convert(ruby.get_inner(value.0)).unwrap();
|
|
||||||
|
|
||||||
let args: Vec<_> = args
|
let args: Vec<_> = args
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|x| ruby.get_inner(x.0).as_value())
|
.map(|x| ruby.get_inner(x.0).as_value())
|
||||||
.collect();
|
.collect();
|
||||||
let result: magnus::Value = f.funcall("call", args.as_slice())?;
|
let result: magnus::Value = f.funcall("call", args.as_slice())?;
|
||||||
Ok(RubyValue::new(result))
|
Ok(RubyValue::new(result))
|
||||||
}))
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn needs_own_thread() -> bool {
|
fn needs_own_thread() -> bool {
|
||||||
|
|
@ -532,7 +521,7 @@ pub mod prelude {
|
||||||
impl<T: TryConvert> FromRuntimeValueWithEngine<'_, RubyRuntime> for T {
|
impl<T: TryConvert> FromRuntimeValueWithEngine<'_, RubyRuntime> for T {
|
||||||
fn from_runtime_value_with_engine(value: RubyValue, engine: &magnus::Ruby) -> Self {
|
fn from_runtime_value_with_engine(value: RubyValue, engine: &magnus::Ruby) -> Self {
|
||||||
let inner = engine.get_inner(value.0);
|
let inner = engine.get_inner(value.0);
|
||||||
T::try_convert(inner).unwrap()
|
T::try_convert(inner).expect("Failed to convert from Ruby value to native type")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -561,7 +550,8 @@ pub struct RArray(pub Opaque<magnus::RArray>);
|
||||||
impl FromRuntimeValueWithEngine<'_, RubyRuntime> for RArray {
|
impl FromRuntimeValueWithEngine<'_, RubyRuntime> for RArray {
|
||||||
fn from_runtime_value_with_engine(value: RubyValue, engine: &magnus::Ruby) -> Self {
|
fn from_runtime_value_with_engine(value: RubyValue, engine: &magnus::Ruby) -> Self {
|
||||||
let inner = engine.get_inner(value.0);
|
let inner = engine.get_inner(value.0);
|
||||||
let array = magnus::RArray::try_convert(inner).unwrap();
|
let array =
|
||||||
|
magnus::RArray::try_convert(inner).expect("Failed to convert Ruby value to RArray");
|
||||||
RArray(Opaque::from(array))
|
RArray(Opaque::from(array))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue