@@ -43,6 +43,8 @@ pub mod private {
4343 #[ allow( non_camel_case_types) ]
4444 pub trait You_forgot_the_attribute__godot_api { }
4545
46+ use std:: sync:: { Arc , Mutex } ;
47+
4648 pub use crate :: gen:: classes:: class_macros;
4749 pub use crate :: registry:: { callbacks, ClassPlugin , ErasedRegisterFn , PluginComponent } ;
4850 pub use crate :: storage:: as_storage;
@@ -68,6 +70,11 @@ pub mod private {
6870 }
6971 }
7072
73+ struct GodotPanicInfo {
74+ line : u32 ,
75+ file : String ,
76+ }
77+
7178 /// Executes `code`. If a panic is thrown, it is caught and an error message is printed to Godot.
7279 ///
7380 /// Returns `None` if a panic occurred, and `Some(result)` with the result of `code` otherwise.
@@ -77,14 +84,43 @@ pub mod private {
7784 F : FnOnce ( ) -> R + std:: panic:: UnwindSafe ,
7885 S : std:: fmt:: Display ,
7986 {
80- match std:: panic:: catch_unwind ( code) {
87+ let info: Arc < Mutex < Option < GodotPanicInfo > > > = Arc :: new ( Mutex :: new ( None ) ) ;
88+
89+ // Back up previous hook, set new one
90+ let prev_hook = std:: panic:: take_hook ( ) ;
91+ {
92+ let info = info. clone ( ) ;
93+ std:: panic:: set_hook ( Box :: new ( move |panic_info| {
94+ if let Some ( location) = panic_info. location ( ) {
95+ * info. lock ( ) . unwrap ( ) = Some ( GodotPanicInfo {
96+ file : location. file ( ) . to_string ( ) ,
97+ line : location. line ( ) ,
98+ } ) ;
99+ } else {
100+ println ! ( "panic occurred but can't get location information..." ) ;
101+ }
102+ } ) ) ;
103+ }
104+
105+ // Run code that should panic, restore hook
106+ let panic = std:: panic:: catch_unwind ( code) ;
107+ std:: panic:: set_hook ( prev_hook) ;
108+
109+ match panic {
81110 Ok ( result) => Some ( result) ,
82111 Err ( err) => {
83112 // Flush, to make sure previous Rust output (e.g. test announcement, or debug prints during app) have been printed
84113 // TODO write custom panic handler and move this there, before panic backtrace printing
85114 flush_stdout ( ) ;
86115
87- log:: godot_error!( "Rust function panicked. Context: {}" , error_context( ) ) ;
116+ let guard = info. lock ( ) . unwrap ( ) ;
117+ let info = guard. as_ref ( ) . expect ( "no panic info available" ) ;
118+ log:: godot_error!(
119+ "Rust function panicked in file {} at line {}. Context: {}" ,
120+ info. file,
121+ info. line,
122+ error_context( )
123+ ) ;
88124 print_panic ( err) ;
89125 None
90126 }
0 commit comments