1
- use std:: any:: type_name;
2
-
3
1
use crate :: {
4
2
bindings:: {
5
3
pretty_print:: DisplayWithWorld , script_value:: ScriptValue , WorldAccessGuard , WorldGuard ,
6
4
} ,
7
- context:: { ContextLoadingSettings , ContextPreHandlingInitializer , ScriptContexts } ,
5
+ context:: ContextPreHandlingInitializer ,
8
6
error:: ScriptError ,
9
7
event:: { CallbackLabel , IntoCallbackLabel , ScriptCallbackEvent , ScriptErrorEvent } ,
10
- runtime :: RuntimeContainer ,
11
- script:: { ScriptComponent , ScriptId , Scripts } ,
8
+ extractors :: { extract_handler_context , yield_handler_context , HandlerContext } ,
9
+ script:: { ScriptComponent , ScriptId } ,
12
10
IntoScriptPluginParams ,
13
11
} ;
14
12
use bevy:: {
@@ -18,7 +16,7 @@ use bevy::{
18
16
world:: World ,
19
17
} ,
20
18
log:: { debug, trace} ,
21
- prelude:: { EventReader , Events , Query , Ref , Res } ,
19
+ prelude:: { EventReader , Events , Query , Ref } ,
22
20
} ;
23
21
24
22
pub trait Args : Clone + Send + Sync + ' static { }
@@ -53,36 +51,17 @@ macro_rules! push_err_and_continue {
53
51
} ;
54
52
}
55
53
56
- /// Passes events with the specified label to the script callback with the same name and runs the callback
57
- pub fn event_handler < L : IntoCallbackLabel , P : IntoScriptPluginParams > (
54
+ /// A utility to separate the event handling logic from the retrieval of the handler context
55
+ pub ( crate ) fn event_handler_internal < L : IntoCallbackLabel , P : IntoScriptPluginParams > (
58
56
world : & mut World ,
57
+ res_ctxt : & mut HandlerContext < P > ,
59
58
params : & mut SystemState < (
60
59
EventReader < ScriptCallbackEvent > ,
61
- Res < CallbackSettings < P > > ,
62
- Res < ContextLoadingSettings < P > > ,
63
- Res < Scripts > ,
64
60
Query < ( Entity , Ref < ScriptComponent > ) > ,
65
61
) > ,
66
62
) {
67
- let mut runtime_container = world
68
- . remove_non_send_resource :: < RuntimeContainer < P > > ( )
69
- . unwrap_or_else ( || {
70
- panic ! (
71
- "No runtime container for runtime {} found. Was the scripting plugin initialized correctly?" ,
72
- type_name:: <P :: R >( )
73
- )
74
- } ) ;
75
- let runtime = & mut runtime_container. runtime ;
76
- let mut script_contexts = world
77
- . remove_non_send_resource :: < ScriptContexts < P > > ( )
78
- . unwrap_or_else ( || panic ! ( "No script contexts found for context {}" , type_name:: <P >( ) ) ) ;
63
+ let ( mut script_events, entities) = params. get_mut ( world) ;
79
64
80
- let ( mut script_events, callback_settings, context_settings, scripts, entities) =
81
- params. get_mut ( world) ;
82
-
83
- let handler = callback_settings. callback_handler ;
84
- let pre_handling_initializers = context_settings. context_pre_handling_initializers . clone ( ) ;
85
- let scripts = scripts. clone ( ) ;
86
65
let mut errors = Vec :: default ( ) ;
87
66
88
67
let events = script_events. read ( ) . cloned ( ) . collect :: < Vec < _ > > ( ) ;
@@ -112,7 +91,7 @@ pub fn event_handler<L: IntoCallbackLabel, P: IntoScriptPluginParams>(
112
91
"Handling event for script {} on entity {:?}" ,
113
92
script_id, entity
114
93
) ;
115
- let script = match scripts. scripts . get ( script_id) {
94
+ let script = match res_ctxt . scripts . scripts . get ( script_id) {
116
95
Some ( s) => s,
117
96
None => {
118
97
trace ! (
@@ -123,7 +102,11 @@ pub fn event_handler<L: IntoCallbackLabel, P: IntoScriptPluginParams>(
123
102
}
124
103
} ;
125
104
126
- let ctxt = match script_contexts. contexts . get_mut ( & script. context_id ) {
105
+ let ctxt = match res_ctxt
106
+ . script_contexts
107
+ . contexts
108
+ . get_mut ( & script. context_id )
109
+ {
127
110
Some ( ctxt) => ctxt,
128
111
None => {
129
112
// if we don't have a context for the script, it's either:
@@ -133,14 +116,16 @@ pub fn event_handler<L: IntoCallbackLabel, P: IntoScriptPluginParams>(
133
116
}
134
117
} ;
135
118
136
- let handler_result = ( handler ) (
119
+ let handler_result = ( res_ctxt . callback_settings . callback_handler ) (
137
120
event. args . clone ( ) ,
138
121
* entity,
139
122
& script. id ,
140
123
& L :: into_callback_label ( ) ,
141
124
ctxt,
142
- & pre_handling_initializers,
143
- runtime,
125
+ & res_ctxt
126
+ . context_loading_settings
127
+ . context_pre_handling_initializers ,
128
+ & mut res_ctxt. runtime_container . runtime ,
144
129
world,
145
130
)
146
131
. map_err ( |e| {
@@ -153,20 +138,43 @@ pub fn event_handler<L: IntoCallbackLabel, P: IntoScriptPluginParams>(
153
138
}
154
139
}
155
140
156
- world. insert_non_send_resource ( runtime_container) ;
157
- world. insert_non_send_resource ( script_contexts) ;
158
-
159
141
handle_script_errors ( world, errors. into_iter ( ) ) ;
160
142
}
161
143
144
+ /// Passes events with the specified label to the script callback with the same name and runs the callback.
145
+ ///
146
+ /// If any of the resources required for the handler are missing, the system will log this issue and do nothing.
147
+ pub fn event_handler < L : IntoCallbackLabel , P : IntoScriptPluginParams > (
148
+ world : & mut World ,
149
+ params : & mut SystemState < (
150
+ EventReader < ScriptCallbackEvent > ,
151
+ Query < ( Entity , Ref < ScriptComponent > ) > ,
152
+ ) > ,
153
+ ) {
154
+ let mut res_ctxt = match extract_handler_context :: < P > ( world) {
155
+ Ok ( handler_context) => handler_context,
156
+ Err ( e) => {
157
+ bevy:: log:: error_once!(
158
+ "Event handler for language `{}` will not run due to missing resource: {}" ,
159
+ P :: LANGUAGE ,
160
+ e
161
+ ) ;
162
+ return ;
163
+ }
164
+ } ;
165
+
166
+ // this ensures the internal handler cannot early return without yielding the context
167
+ event_handler_internal :: < L , P > ( world, & mut res_ctxt, params) ;
168
+
169
+ yield_handler_context ( world, res_ctxt) ;
170
+ }
171
+
162
172
/// Handles errors caused by script execution and sends them to the error event channel
163
173
pub ( crate ) fn handle_script_errors < I : Iterator < Item = ScriptError > + Clone > (
164
174
world : & mut World ,
165
175
errors : I ,
166
176
) {
167
- let mut error_events = world
168
- . get_resource_mut :: < Events < ScriptErrorEvent > > ( )
169
- . expect ( "Missing events resource" ) ;
177
+ let mut error_events = world. get_resource_or_init :: < Events < ScriptErrorEvent > > ( ) ;
170
178
171
179
for error in errors. clone ( ) {
172
180
error_events. send ( ScriptErrorEvent { error } ) ;
0 commit comments