@@ -43,6 +43,8 @@ pub mod private {
43
43
#[ allow( non_camel_case_types) ]
44
44
pub trait You_forgot_the_attribute__godot_api { }
45
45
46
+ use std:: sync:: { Arc , Mutex } ;
47
+
46
48
pub use crate :: gen:: classes:: class_macros;
47
49
pub use crate :: registry:: { callbacks, ClassPlugin , ErasedRegisterFn , PluginComponent } ;
48
50
pub use crate :: storage:: as_storage;
@@ -68,6 +70,11 @@ pub mod private {
68
70
}
69
71
}
70
72
73
+ struct GodotPanicInfo {
74
+ line : u32 ,
75
+ file : String ,
76
+ }
77
+
71
78
/// Executes `code`. If a panic is thrown, it is caught and an error message is printed to Godot.
72
79
///
73
80
/// Returns `None` if a panic occurred, and `Some(result)` with the result of `code` otherwise.
@@ -77,14 +84,43 @@ pub mod private {
77
84
F : FnOnce ( ) -> R + std:: panic:: UnwindSafe ,
78
85
S : std:: fmt:: Display ,
79
86
{
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 {
81
110
Ok ( result) => Some ( result) ,
82
111
Err ( err) => {
83
112
// Flush, to make sure previous Rust output (e.g. test announcement, or debug prints during app) have been printed
84
113
// TODO write custom panic handler and move this there, before panic backtrace printing
85
114
flush_stdout ( ) ;
86
115
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
+ ) ;
88
124
print_panic ( err) ;
89
125
None
90
126
}
0 commit comments