Skip to content

Commit 3461ecf

Browse files
committed
initial work 🚧
1 parent 4a4c039 commit 3461ecf

File tree

4 files changed

+467
-206
lines changed

4 files changed

+467
-206
lines changed

crates/bevy_mod_scripting_core/src/bindings/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ pub mod pretty_print;
88
pub mod query;
99
pub mod reference;
1010
pub mod schedule;
11+
pub mod script_system;
1112
pub mod script_value;
1213
pub mod world;
1314

crates/bevy_mod_scripting_core/src/bindings/schedule.rs

Lines changed: 10 additions & 206 deletions
Original file line numberDiff line numberDiff line change
@@ -1,58 +1,33 @@
11
//! Dynamic scheduling from scripts
22
3-
use std::{
4-
any::TypeId,
5-
borrow::Cow,
6-
collections::HashMap,
7-
hash::Hash,
8-
ops::Deref,
9-
sync::{
10-
atomic::{AtomicUsize, Ordering},
11-
Arc,
12-
},
13-
};
14-
3+
use super::{script_system::ScriptSystemBuilder, WorldAccessGuard};
4+
use crate::{error::InteropError, IntoScriptPluginParams};
155
use bevy::{
166
app::{
177
First, FixedFirst, FixedLast, FixedMain, FixedPostUpdate, FixedPreUpdate, FixedUpdate,
188
Last, PostStartup, PostUpdate, PreStartup, PreUpdate, RunFixedMainLoop, Startup, Update,
199
},
2010
ecs::{
21-
entity::Entity,
22-
intern::Interned,
23-
schedule::{
24-
InternedScheduleLabel, IntoSystemConfigs, NodeId, Schedule, ScheduleLabel, Schedules,
25-
SystemSet,
26-
},
27-
system::{IntoSystem, Resource, System, SystemInput, SystemState},
11+
schedule::{InternedScheduleLabel, NodeId, Schedule, ScheduleLabel, Schedules},
12+
system::{Resource, System, SystemInput},
2813
world::World,
2914
},
3015
reflect::Reflect,
3116
};
3217
use parking_lot::RwLock;
33-
34-
use crate::{
35-
error::InteropError,
36-
event::CallbackLabel,
37-
extractors::{HandlerContext, WithWorldGuard},
38-
handler::handle_script_errors,
39-
script::ScriptId,
40-
IntoScriptPluginParams,
41-
};
42-
43-
use super::{WorldAccessGuard, WorldGuard};
18+
use std::{any::TypeId, borrow::Cow, collections::HashMap, ops::Deref, sync::Arc};
4419

4520
#[derive(Reflect, Debug, Clone)]
4621
/// A reflectable system.
4722
pub struct ReflectSystem {
48-
name: Cow<'static, str>,
49-
type_id: TypeId,
50-
node_id: ReflectNodeId,
23+
pub(crate) name: Cow<'static, str>,
24+
pub(crate) type_id: TypeId,
25+
pub(crate) node_id: ReflectNodeId,
5126
}
5227

5328
#[derive(Reflect, Clone, Debug)]
5429
#[reflect(opaque)]
55-
pub(crate) struct ReflectNodeId(pub(crate) NodeId);
30+
pub(crate) struct ReflectNodeId(pub NodeId);
5631

5732
impl ReflectSystem {
5833
/// Creates a reflect system from a system specification
@@ -230,177 +205,6 @@ impl ScheduleRegistry {
230205
}
231206
}
232207

233-
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)]
234-
/// a system set for script systems.
235-
pub struct ScriptSystemSet(usize);
236-
237-
impl ScriptSystemSet {
238-
/// Creates a new script system set with a unique id
239-
pub fn next() -> Self {
240-
static CURRENT_ID: AtomicUsize = AtomicUsize::new(0);
241-
Self(CURRENT_ID.fetch_add(1, Ordering::Relaxed))
242-
}
243-
}
244-
245-
impl SystemSet for ScriptSystemSet {
246-
fn dyn_clone(&self) -> bevy::ecs::label::Box<dyn SystemSet> {
247-
Box::new(*self)
248-
}
249-
250-
fn as_dyn_eq(&self) -> &dyn bevy::ecs::label::DynEq {
251-
self
252-
}
253-
254-
fn dyn_hash(&self, mut state: &mut dyn ::core::hash::Hasher) {
255-
self.hash(&mut state);
256-
}
257-
}
258-
259-
/// A builder for systems living in scripts
260-
#[derive(Reflect)]
261-
pub struct ScriptSystemBuilder {
262-
name: CallbackLabel,
263-
script_id: ScriptId,
264-
before: Vec<ReflectSystem>,
265-
after: Vec<ReflectSystem>,
266-
}
267-
268-
impl ScriptSystemBuilder {
269-
/// Creates a new script system builder
270-
pub fn new(name: CallbackLabel, script_id: ScriptId) -> Self {
271-
Self {
272-
before: vec![],
273-
after: vec![],
274-
name,
275-
script_id,
276-
}
277-
}
278-
279-
/// Adds a system to run before the script system
280-
pub fn before(&mut self, system: ReflectSystem) -> &mut Self {
281-
self.before.push(system);
282-
self
283-
}
284-
285-
/// Adds a system to run after the script system
286-
pub fn after(&mut self, system: ReflectSystem) -> &mut Self {
287-
self.after.push(system);
288-
self
289-
}
290-
291-
/// Selects the most granual system set it can for the given system node id or None
292-
fn get_individual_system_system_set(
293-
node_id: NodeId,
294-
schedule: &Schedule,
295-
) -> Option<Interned<dyn SystemSet>> {
296-
// if let Some(system) = schedule.graph().get_system_at(node_id) {
297-
// // this only works for normal bevy rust systems
298-
// if let Some(system_set) = system.default_system_sets().first() {
299-
// return Some(system_set.dyn_clone());
300-
// }
301-
// }
302-
if let Ok(systems) = schedule.systems() {
303-
for (system_id, system) in systems {
304-
if system_id == node_id {
305-
return system.default_system_sets().first().cloned();
306-
}
307-
}
308-
}
309-
310-
None
311-
}
312-
313-
/// Builds the system and inserts it into the given schedule
314-
#[allow(deprecated)]
315-
pub fn build<P: IntoScriptPluginParams>(
316-
self,
317-
world: WorldGuard,
318-
schedule: &ReflectSchedule,
319-
) -> Result<ReflectSystem, InteropError> {
320-
world.scope_schedule(schedule, |world, schedule| {
321-
// this is different to a normal event handler
322-
// the system doesn't listen to events
323-
// it immediately calls a singular script with a predefined payload
324-
let system_name = format!("script_system_{}", &self.name);
325-
let _system = move |world: &mut World,
326-
system_state: &mut SystemState<
327-
WithWorldGuard<HandlerContext<P>>,
328-
>| {
329-
let mut with_guard = system_state.get_mut(world);
330-
331-
{
332-
let (guard, handler_ctxt) = with_guard.get_mut();
333-
let name = self.name.clone();
334-
bevy::log::debug_once!("First call to script system {}", name);
335-
match handler_ctxt.call_dynamic_label(
336-
&name,
337-
&self.script_id,
338-
Entity::from_raw(0),
339-
vec![],
340-
guard.clone(),
341-
) {
342-
Ok(_) => {}
343-
Err(err) => {
344-
handle_script_errors(
345-
guard,
346-
vec![err.with_script(self.script_id.clone())].into_iter(),
347-
);
348-
}
349-
};
350-
}
351-
352-
system_state.apply(world);
353-
};
354-
355-
let function_system = IntoSystem::into_system(_system.clone()).with_name(system_name);
356-
357-
// dummy node id for now
358-
let mut reflect_system =
359-
ReflectSystem::from_system(&function_system, NodeId::System(0));
360-
361-
// this is quite important, by default systems are placed in a set defined by their TYPE, i.e. in this case
362-
// all script systems would be the same
363-
let set = ScriptSystemSet::next();
364-
let mut config = IntoSystemConfigs::into_configs(function_system.in_set(set));
365-
366-
// apply ordering
367-
for (other, is_before) in self
368-
.before
369-
.iter()
370-
.map(|b| (b, true))
371-
.chain(self.after.iter().map(|a| (a, false)))
372-
{
373-
match Self::get_individual_system_system_set(other.node_id.0, schedule) {
374-
Some(set) => {
375-
if is_before {
376-
config = config.before(set);
377-
} else {
378-
config = config.after(set);
379-
}
380-
}
381-
None => {
382-
bevy::log::warn!(
383-
"Could not find system set for system {:?}",
384-
other.identifier()
385-
);
386-
}
387-
}
388-
}
389-
390-
schedule.configure_sets(set);
391-
schedule.add_systems(config);
392-
393-
schedule.initialize(world)?;
394-
395-
let node_id = NodeId::System(schedule.systems_len());
396-
397-
reflect_system.node_id = ReflectNodeId(node_id);
398-
399-
Ok(reflect_system)
400-
})?
401-
}
402-
}
403-
404208
#[profiling::all_functions]
405209
/// Impls to do with dynamically querying systems and schedules
406210
impl WorldAccessGuard<'_> {
@@ -487,7 +291,7 @@ mod tests {
487291

488292
use bevy::{
489293
app::{App, Update},
490-
ecs::system::IntoSystem,
294+
ecs::{schedule::Schedules, system::IntoSystem},
491295
};
492296
use test_utils::make_test_plugin;
493297

0 commit comments

Comments
 (0)