diff --git a/src/lib.rs b/src/lib.rs index 3ae0518..2e86af5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -294,8 +294,8 @@ const ENTITY_VAR_NAME: &str = "entity"; /// An error that can occur when internal [ScriptingPlugin] systems are being executed #[derive(Error, Debug)] pub enum ScriptingError { - #[error("script runtime error: {0}")] - RuntimeError(Box), + #[error("script runtime error: {0}\nscript backtrace:\n{1}")] + RuntimeError(String, String), #[error("script compilation error: {0}")] CompileError(Box), #[error("no runtime resource present")] diff --git a/src/runtimes/ruby.rs b/src/runtimes/ruby.rs index 0aa1be1..168d66a 100644 --- a/src/runtimes/ruby.rs +++ b/src/runtimes/ruby.rs @@ -1,3 +1,4 @@ +// TODO: use funcall_public? use std::{ collections::HashMap, ffi::CString, @@ -5,7 +6,7 @@ use std::{ thread::{self, JoinHandle}, }; -use ::magnus::value::Opaque; +use ::magnus::{error::IntoError, typed_data::Inspect, value::Opaque}; use anyhow::anyhow; use bevy::{ asset::Asset, @@ -20,7 +21,7 @@ use magnus::{ value::{Lazy, ReprValue}, }; use magnus::{method, prelude::*}; -use rb_sys::{VALUE, ruby_init_stack}; +use rb_sys::{VALUE, rb_backtrace, rb_make_backtrace, ruby_init_stack}; use serde::Deserialize; use crate::{ @@ -223,7 +224,19 @@ impl TryConvert for BevyVec3 { impl From for ScriptingError { fn from(value: magnus::Error) -> Self { - ScriptingError::RuntimeError(anyhow!(value.to_string()).into()) + // TODO: DRY + ScriptingError::RuntimeError( + value.inspect(), + value + .value() + .unwrap() + .funcall::<_, _, magnus::RArray>("backtrace", ()) // TODO: is there an API for this + // somehwere + .unwrap() + .to_vec::() + .unwrap() + .join("\n"), + ) } } @@ -374,8 +387,20 @@ impl Runtime for RubyRuntime { var.ivar_set("_current", BevyEntity(entity)) .expect("Failed to set current entity handle"); - ruby.eval::(&script) - .map_err(|e| ScriptingError::RuntimeError(anyhow!(e.to_string()).into()))?; + unsafe { + ruby.eval::(&script).map_err(|e| { + ScriptingError::RuntimeError( + e.inspect(), + e.value() + .unwrap() + .funcall::<_, _, magnus::RArray>("backtrace", ()) + .unwrap() + .to_vec::() + .unwrap() + .join("\n"), + ) + })?; + } var.ivar_set("_current", ruby.qnil().as_value()) .expect("Failed to unset current entity handle"); diff --git a/src/systems.rs b/src/systems.rs index a891720..b48931b 100644 --- a/src/systems.rs +++ b/src/systems.rs @@ -52,7 +52,7 @@ pub(crate) fn process_new_scripts( let path = asset_server .get_path(&script_component.script) .unwrap_or_default(); - tracing::error!("error running script {} {:?}", path, e); + tracing::error!("error running script {} {}", path, e); } } }