Skip to content

Commit c7799a6

Browse files
committed
parameterize scripts by the plugin type
1 parent 86f2be8 commit c7799a6

File tree

6 files changed

+49
-92
lines changed

6 files changed

+49
-92
lines changed

crates/bevy_mod_scripting_core/src/commands.rs

Lines changed: 10 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
use crate::{
44
asset::ScriptAsset,
55
bindings::WorldGuard,
6-
context::{ContextBuilder, DowncastContext},
6+
context::ContextBuilder,
77
error::{InteropError, ScriptError},
88
event::{IntoCallbackLabel, OnScriptLoaded, OnScriptUnloaded},
99
extractors::{with_handler_system_state, HandlerContext},
@@ -41,25 +41,14 @@ impl<P: IntoScriptPluginParams> Command for DeleteScript<P> {
4141

4242
// first let the script uninstall itself
4343
let mut context = script.context.lock();
44-
let downcast_context = match context.downcast_mut::<P::C>() {
45-
Some(downcast_context) => downcast_context,
46-
None => {
47-
bevy::log::error!(
48-
"{}: Tried to delete script context for id: {}, but the context is of the wrong type for this script plugin.",
49-
P::LANGUAGE,
50-
self.id
51-
);
52-
return;
53-
}
54-
};
5544

5645
match (CallbackSettings::<P>::call)(
5746
handler_ctxt.callback_settings.callback_handler,
5847
vec![],
5948
bevy::ecs::entity::Entity::from_raw(0),
6049
&self.id,
6150
&OnScriptUnloaded::into_callback_label(),
62-
downcast_context,
51+
&mut context,
6352
&handler_ctxt
6453
.context_loading_settings
6554
.context_pre_handling_initializers,
@@ -132,20 +121,12 @@ impl<P: IntoScriptPluginParams> CreateOrUpdateScript<P> {
132121

133122
// reload context
134123
let mut context = existing_script.context.lock();
135-
let downcast_context = match context.downcast_mut::<P::C>() {
136-
Some(downcast_context) => downcast_context,
137-
None => {
138-
return Err(InteropError::unsupported_operation(None,None,
139-
"Tried to reload script but the context loaded on it is of the wrong type for this script plugin."
140-
).into());
141-
}
142-
};
143124

144125
(ContextBuilder::<P>::reload)(
145126
handler_ctxt.context_loading_settings.loader.reload,
146127
&self.id,
147128
&self.content,
148-
downcast_context,
129+
&mut context,
149130
&handler_ctxt.context_loading_settings.context_initializers,
150131
&handler_ctxt
151132
.context_loading_settings
@@ -381,7 +362,7 @@ mod test {
381362
Ok(ScriptValue::Unit)
382363
},
383364
})
384-
.insert_resource(Scripts {
365+
.insert_resource(Scripts::<DummyPlugin> {
385366
scripts: Default::default(),
386367
});
387368

@@ -401,7 +382,7 @@ mod test {
401382
}
402383

403384
fn assert_context_and_script(world: &World, id: &str, context: &str, message: &str) {
404-
let scripts = world.get_resource::<Scripts>().unwrap();
385+
let scripts = world.get_resource::<Scripts<DummyPlugin>>().unwrap();
405386

406387
let script = scripts
407388
.scripts
@@ -410,9 +391,8 @@ mod test {
410391

411392
assert_eq!(id, script.id);
412393
let found_context = script.context.lock();
413-
let found_context = &found_context.downcast_ref::<String>().unwrap().to_string();
414394

415-
assert_eq!(&context, &found_context, "{}", message);
395+
assert_eq!(*context, *found_context, "{}", message);
416396
}
417397

418398
#[test]
@@ -467,7 +447,7 @@ mod test {
467447
command.apply(world);
468448

469449
// check that the scripts are gone
470-
let scripts = world.get_resource::<Scripts>().unwrap();
450+
let scripts = world.get_resource::<Scripts<DummyPlugin>>().unwrap();
471451
assert!(scripts.scripts.is_empty());
472452
}
473453

@@ -535,7 +515,7 @@ mod test {
535515
"First script context was not updated on second script insert",
536516
);
537517

538-
let scripts = app.world().get_resource::<Scripts>().unwrap();
518+
let scripts = app.world().get_resource::<Scripts<DummyPlugin>>().unwrap();
539519
assert!(scripts.scripts.len() == 2);
540520

541521
// delete first script
@@ -559,10 +539,10 @@ mod test {
559539

560540
// check that the scripts are gone, and so is the context
561541

562-
let scripts = app.world().get_resource::<Scripts>().unwrap();
542+
let scripts = app.world().get_resource::<Scripts<DummyPlugin>>().unwrap();
563543
assert!(scripts.scripts.is_empty());
564544

565-
let scripts = app.world().get_resource::<Scripts>().unwrap();
545+
let scripts = app.world().get_resource::<Scripts<DummyPlugin>>().unwrap();
566546

567547
assert_eq!(scripts.scripts.len(), 0, "scripts weren't removed");
568548
}

crates/bevy_mod_scripting_core/src/context.rs

Lines changed: 2 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
//! Traits and types for managing script contexts.
22
3-
use std::any::Any;
4-
53
use crate::{
64
bindings::{ThreadWorldContainer, WorldContainer, WorldGuard},
75
error::{InteropError, ScriptError},
@@ -14,39 +12,8 @@ use bevy::ecs::{entity::Entity, system::Resource};
1412
///
1513
/// Contexts are not required to be `Sync` as they are internally stored behind a `Mutex` but they must satisfy `Send` so they can be
1614
/// freely sent between threads.
17-
pub trait Context: 'static + Send {
18-
/// Downcast the context to a reference of the given type if it is of that type.
19-
fn as_any(&self) -> &dyn Any;
20-
/// Downcast the context to a mutable reference of the given type if it is of that type.
21-
fn as_any_mut(&mut self) -> &mut dyn Any;
22-
}
23-
24-
impl<T: 'static + Send> Context for T {
25-
fn as_any(&self) -> &dyn Any {
26-
self
27-
}
28-
29-
fn as_any_mut(&mut self) -> &mut dyn Any {
30-
self
31-
}
32-
}
33-
/// A helper trait for downcasting a context to a reference of a specific type.
34-
pub trait DowncastContext {
35-
/// Downcast the context to a reference of the given type if it is of that type.
36-
fn downcast_ref<T: 'static>(&self) -> Option<&T>;
37-
/// Downcast the context to a mutable reference of the given type if it is of that type.
38-
fn downcast_mut<T: 'static>(&mut self) -> Option<&mut T>;
39-
}
40-
41-
impl DowncastContext for dyn Context {
42-
fn downcast_ref<T: 'static>(&self) -> Option<&T> {
43-
self.as_any().downcast_ref()
44-
}
45-
46-
fn downcast_mut<T: 'static>(&mut self) -> Option<&mut T> {
47-
self.as_any_mut().downcast_mut()
48-
}
49-
}
15+
pub trait Context: 'static + Send {}
16+
impl<T: 'static + Send> Context for T {}
5017

5118
/// Initializer run once after creating a context but before executing it for the first time as well as after re-loading the script
5219
pub type ContextInitializer<P> =

crates/bevy_mod_scripting_core/src/extractors.rs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ use crate::{
2020
access_map::ReflectAccessId, pretty_print::DisplayWithWorld, script_value::ScriptValue,
2121
WorldAccessGuard, WorldGuard,
2222
},
23-
context::{ContextLoadingSettings, DowncastContext},
23+
context::ContextLoadingSettings,
2424
error::{InteropError, ScriptError},
2525
event::{CallbackLabel, IntoCallbackLabel},
2626
handler::CallbackSettings,
@@ -141,7 +141,7 @@ pub struct HandlerContext<'s, P: IntoScriptPluginParams> {
141141
/// Settings for loading contexts
142142
pub(crate) context_loading_settings: ResScope<'s, ContextLoadingSettings<P>>,
143143
/// Scripts
144-
pub(crate) scripts: ResScope<'s, Scripts>,
144+
pub(crate) scripts: ResScope<'s, Scripts<P>>,
145145
/// The runtime container
146146
pub(crate) runtime_container: ResScope<'s, RuntimeContainer<P>>,
147147
/// List of static scripts
@@ -158,7 +158,7 @@ impl<P: IntoScriptPluginParams> HandlerContext<'_, P> {
158158
) -> (
159159
&mut CallbackSettings<P>,
160160
&mut ContextLoadingSettings<P>,
161-
&mut Scripts,
161+
&mut Scripts<P>,
162162
&mut RuntimeContainer<P>,
163163
&mut StaticScripts,
164164
) {
@@ -182,7 +182,7 @@ impl<P: IntoScriptPluginParams> HandlerContext<'_, P> {
182182
}
183183

184184
/// Get the scripts
185-
pub fn scripts(&mut self) -> &mut Scripts {
185+
pub fn scripts(&mut self) -> &mut Scripts<P> {
186186
&mut self.scripts
187187
}
188188

@@ -224,17 +224,14 @@ impl<P: IntoScriptPluginParams> HandlerContext<'_, P> {
224224
let runtime = &self.runtime_container.runtime;
225225

226226
let mut context = script.context.lock();
227-
let donwcast_context = context.downcast_mut::<P::C>().ok_or_else(|| {
228-
InteropError::unsupported_operation(None, None, "Context is not the correct type")
229-
})?;
230227

231228
CallbackSettings::<P>::call(
232229
handler,
233230
payload,
234231
entity,
235232
script_id,
236233
label,
237-
donwcast_context,
234+
&mut context,
238235
pre_handling_initializers,
239236
runtime,
240237
guard,

crates/bevy_mod_scripting_core/src/handler.rs

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -269,7 +269,7 @@ mod test {
269269

270270
use crate::{
271271
bindings::script_value::ScriptValue,
272-
context::{ContextBuilder, ContextLoadingSettings, DowncastContext},
272+
context::{ContextBuilder, ContextLoadingSettings},
273273
event::{CallbackLabel, IntoCallbackLabel, ScriptCallbackEvent, ScriptErrorEvent},
274274
runtime::RuntimeContainer,
275275
script::{Script, ScriptComponent, ScriptId, Scripts, StaticScripts},
@@ -288,7 +288,7 @@ mod test {
288288

289289
fn setup_app<L: IntoCallbackLabel + 'static>(
290290
runtime: TestRuntime,
291-
scripts: HashMap<ScriptId, Script>,
291+
scripts: HashMap<ScriptId, Script<TestPlugin>>,
292292
) -> App {
293293
let mut app = App::new();
294294

@@ -303,7 +303,7 @@ mod test {
303303
},
304304
});
305305
app.add_systems(Update, event_handler::<L, TestPlugin>);
306-
app.insert_resource::<Scripts>(Scripts { scripts });
306+
app.insert_resource::<Scripts<TestPlugin>>(Scripts { scripts });
307307
app.insert_resource(RuntimeContainer::<TestPlugin> { runtime });
308308
app.init_resource::<StaticScripts>();
309309
app.insert_resource(ContextLoadingSettings::<TestPlugin> {
@@ -346,14 +346,13 @@ mod test {
346346

347347
let test_script = app
348348
.world()
349-
.get_resource::<Scripts>()
349+
.get_resource::<Scripts<TestPlugin>>()
350350
.unwrap()
351351
.scripts
352352
.get(&test_script_id)
353353
.unwrap();
354354

355355
let test_context = test_script.context.lock();
356-
let test_context = test_context.downcast_ref::<TestContext>().unwrap();
357356

358357
let test_runtime = app
359358
.world()
@@ -418,15 +417,14 @@ mod test {
418417

419418
app.update();
420419

421-
let test_scripts = app.world().get_resource::<Scripts>().unwrap();
420+
let test_scripts = app.world().get_resource::<Scripts<TestPlugin>>().unwrap();
422421
let test_runtime = app
423422
.world()
424423
.get_resource::<RuntimeContainer<TestPlugin>>()
425424
.unwrap();
426425
let test_runtime = test_runtime.runtime.invocations.lock();
427426
let script_after = test_scripts.scripts.get(&test_script_id).unwrap();
428427
let context_after = script_after.context.lock();
429-
let context_after = context_after.downcast_ref::<TestContext>().unwrap();
430428
assert_eq!(
431429
context_after.invocations,
432430
vec![
@@ -482,16 +480,14 @@ mod test {
482480

483481
app.update();
484482

485-
let test_scripts = app.world().get_resource::<Scripts>().unwrap();
483+
let test_scripts = app.world().get_resource::<Scripts<TestPlugin>>().unwrap();
486484
let test_context = test_scripts
487485
.scripts
488486
.get(&test_script_id)
489487
.unwrap()
490488
.context
491489
.lock();
492490

493-
let test_context = test_context.downcast_ref::<TestContext>().unwrap();
494-
495491
assert_eq!(
496492
test_context.invocations,
497493
vec![

crates/bevy_mod_scripting_core/src/lib.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,8 @@ impl<P: IntoScriptPluginParams> Plugin for ScriptingPlugin<P> {
128128
assignment_strategy: self.context_assignment_strategy,
129129
context_initializers: self.context_initializers.clone(),
130130
context_pre_handling_initializers: self.context_pre_handling_initializers.clone(),
131-
});
131+
})
132+
.init_resource::<Scripts<P>>();
132133

133134
register_script_plugin_systems::<P>(app);
134135

@@ -289,7 +290,6 @@ fn once_per_app_init(app: &mut App) {
289290
app.add_event::<ScriptErrorEvent>()
290291
.add_event::<ScriptCallbackEvent>()
291292
.init_resource::<AppReflectAllocator>()
292-
.init_resource::<Scripts>()
293293
.init_resource::<StaticScripts>()
294294
.init_asset::<ScriptAsset>()
295295
.init_resource::<AppScriptFunctionRegistry>()

crates/bevy_mod_scripting_core/src/script.rs

Lines changed: 24 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
//! Script related types, functions and components
22
3-
use crate::{asset::ScriptAsset, context::Context};
3+
use crate::{asset::ScriptAsset, IntoScriptPluginParams};
44
use bevy::{asset::Handle, ecs::system::Resource, reflect::Reflect, utils::HashSet};
55
use parking_lot::Mutex;
66
use std::{borrow::Cow, collections::HashMap, ops::Deref, sync::Arc};
@@ -33,20 +33,37 @@ impl ScriptComponent {
3333
}
3434

3535
/// All the scripts which are currently loaded or loading and their mapping to contexts
36-
#[derive(Resource, Default, Clone)]
37-
pub struct Scripts {
38-
pub(crate) scripts: HashMap<ScriptId, Script>,
36+
#[derive(Resource)]
37+
pub struct Scripts<P: IntoScriptPluginParams> {
38+
pub(crate) scripts: HashMap<ScriptId, Script<P>>,
39+
}
40+
41+
impl<P: IntoScriptPluginParams> Default for Scripts<P> {
42+
fn default() -> Self {
43+
Self {
44+
scripts: Default::default(),
45+
}
46+
}
3947
}
4048

4149
/// A script
42-
#[derive(Clone)]
43-
pub struct Script {
50+
pub struct Script<P: IntoScriptPluginParams> {
4451
/// The id of the script
4552
pub id: ScriptId,
4653
/// the asset holding the content of the script if it comes from an asset
4754
pub asset: Option<Handle<ScriptAsset>>,
4855
/// The context of the script, possibly shared with other scripts
49-
pub context: Arc<Mutex<dyn Context>>,
56+
pub context: Arc<Mutex<P::C>>,
57+
}
58+
59+
impl<P: IntoScriptPluginParams> Clone for Script<P> {
60+
fn clone(&self) -> Self {
61+
Self {
62+
id: self.id.clone(),
63+
asset: self.asset.clone(),
64+
context: self.context.clone(),
65+
}
66+
}
5067
}
5168

5269
/// A collection of scripts, not associated with any entity.

0 commit comments

Comments
 (0)