Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions _release-content/migration-guides/one-shot-systems.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
---
title: "One-shot systems are now registered as `SystemArc`s rather than `BoxedSystem`s"
pull_requests: [24072]
---

In order to support `bsn!` templating of `SystemId`s, one-shot systems are now
stored as `SystemArc`s rather than `BoxedSystem`s.

- `World::register_boxed_system` was replaced with `World::register_system_arc`.
- Rather than storing `Box<dyn System>`s and passing them to `register_boxed_system`,
store `SystemArc<dyn System>`s and pass them to `register_system_arc`.

```rust
struct Foo;
struct Bar;

// 0.18
let my_boxed_system: Box<dyn System<In = In<Foo>, Out = Bar>> =
Box::new(IntoSystem::into_system(
|foo| { Bar }
));

world.register_boxed_system(my_boxed_system);

// 0.19
let my_system_arc: SystemArc<dyn System<In = In<Foo>, Out = Bar>> =
SystemArc::new_dyn(|foo| { Bar });

world.register_system_arc(my_system_arc);
```
45 changes: 26 additions & 19 deletions crates/bevy_app/src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,14 +19,18 @@ use bevy_ecs::{
InternedSystemSet, ScheduleBuildSettings, ScheduleCleanupPolicy, ScheduleError,
ScheduleLabel,
},
system::{ScheduleSystem, SystemId, SystemInput},
system::ScheduleSystem,
};
use bevy_platform::collections::HashMap;
#[cfg(feature = "bevy_reflect")]
use bevy_reflect::{FromType, Reflect, TypeData, TypePath};
use core::{fmt::Debug, num::NonZero, panic::AssertUnwindSafe};
use log::debug;

bevy_platform::cfg::arc! {
use bevy_ecs::system::{SystemId, SystemInput};
}

#[cfg(feature = "trace")]
use tracing::info_span;

Expand Down Expand Up @@ -362,24 +366,27 @@ impl App {
self.main_mut().remove_systems_in_set(schedule, set, policy)
}

/// Registers a system and returns a [`SystemId`] so it can later be called by [`World::run_system`].
///
/// It's possible to register the same systems more than once, they'll be stored separately.
///
/// This is different from adding systems to a [`Schedule`] with [`App::add_systems`],
/// because the [`SystemId`] that is returned can be used anywhere in the [`World`] to run the associated system.
/// This allows for running systems in a push-based fashion.
/// Using a [`Schedule`] is still preferred for most cases
/// due to its better performance and ability to run non-conflicting systems simultaneously.
pub fn register_system<I, O, M>(
&mut self,
system: impl IntoSystem<I, O, M> + 'static,
) -> SystemId<I, O>
where
I: SystemInput + 'static,
O: 'static,
{
self.main_mut().register_system(system)
// Check bevy_ecs::system::SystemArc file for why this is gated on `arc`.
bevy_platform::cfg::arc! {
/// Registers a system and returns a [`SystemId`] so it can later be called by [`World::run_system`].
///
/// It's possible to register the same systems more than once, they'll be stored separately.
///
/// This is different from adding systems to a [`Schedule`] with [`App::add_systems`],
/// because the [`SystemId`] that is returned can be used anywhere in the [`World`] to run the associated system.
/// This allows for running systems in a push-based fashion.
/// Using a [`Schedule`] is still preferred for most cases
/// due to its better performance and ability to run non-conflicting systems simultaneously.
pub fn register_system<I, O, M>(
&mut self,
system: impl IntoSystem<I, O, M> + 'static,
) -> SystemId<I, O>
where
I: SystemInput + 'static,
O: 'static,
{
self.main_mut().register_system(system)
}
}

/// Configures a collection of system sets in the provided schedule, adding any sets that do not exist.
Expand Down
29 changes: 18 additions & 11 deletions crates/bevy_app/src/sub_app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,15 @@ use bevy_ecs::{
InternedScheduleLabel, InternedSystemSet, ScheduleBuildSettings, ScheduleCleanupPolicy,
ScheduleError, ScheduleLabel,
},
system::{ScheduleSystem, SystemId, SystemInput},
system::ScheduleSystem,
};
use bevy_platform::collections::{HashMap, HashSet};
use core::fmt::Debug;

bevy_platform::cfg::arc! {
use bevy_ecs::system::{SystemId, SystemInput};
}

#[cfg(feature = "trace")]
use tracing::{info_span, warn};

Expand Down Expand Up @@ -235,16 +239,19 @@ impl SubApp {
})
}

/// See [`App::register_system`].
pub fn register_system<I, O, M>(
&mut self,
system: impl IntoSystem<I, O, M> + 'static,
) -> SystemId<I, O>
where
I: SystemInput + 'static,
O: 'static,
{
self.world.register_system(system)
// Check bevy_ecs::system::SystemArc file for why this is gated on `arc`.
bevy_platform::cfg::arc! {
/// See [`App::register_system`].
pub fn register_system<I, O, M>(
&mut self,
system: impl IntoSystem<I, O, M> + 'static,
) -> SystemId<I, O>
where
I: SystemInput + 'static,
O: 'static,
{
self.world.register_system(system)
}
}

/// See [`App::configure_sets`].
Expand Down
140 changes: 72 additions & 68 deletions crates/bevy_ecs/src/system/commands/command.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ use crate::{
message::{Message, Messages},
resource::Resource,
schedule::ScheduleLabel,
system::{IntoSystem, SystemId, SystemInput},
world::{FromWorld, SpawnBatchIter, World},
};

Expand Down Expand Up @@ -181,83 +180,88 @@ pub fn remove_resource<R: Resource>() -> impl Command {
}
}

/// A [`Command`] that runs the system corresponding to the given [`SystemId`].
pub fn run_system<O: 'static>(id: SystemId<(), O>) -> impl Command {
move |world: &mut World| -> Result {
world.run_system(id)?;
Ok(())
// Check bevy_ecs::system::SystemArc file for why this is gated on `arc`.
bevy_platform::cfg::arc! {
use crate::system::{IntoSystem, SystemInput, SystemId};

/// A [`Command`] that runs the system corresponding to the given [`SystemId`].
pub fn run_system<O: 'static>(id: SystemId<(), O>) -> impl Command {
move |world: &mut World| -> Result {
world.run_system(id)?;
Ok(())
}
}
}

/// A [`Command`] that runs the system corresponding to the given [`SystemId`]
/// and provides the given input value.
pub fn run_system_with<I>(id: SystemId<I>, input: I::Inner<'static>) -> impl Command
where
I: SystemInput<Inner<'static>: Send> + 'static,
{
move |world: &mut World| -> Result {
world.run_system_with(id, input)?;
Ok(())
/// A [`Command`] that runs the system corresponding to the given [`SystemId`]
/// and provides the given input value.
pub fn run_system_with<I>(id: SystemId<I>, input: I::Inner<'static>) -> impl Command
where
I: SystemInput<Inner<'static>: Send> + 'static,
{
move |world: &mut World| -> Result {
world.run_system_with(id, input)?;
Ok(())
}
}
}

/// A [`Command`] that runs the given system,
/// caching its [`SystemId`] in a [`CachedSystemId`](crate::system::CachedSystemId) resource.
pub fn run_system_cached<M, S>(system: S) -> impl Command
where
M: 'static,
S: IntoSystem<(), (), M> + Send + 'static,
{
move |world: &mut World| -> Result {
world.run_system_cached(system)?;
Ok(())
/// A [`Command`] that runs the given system,
/// caching its [`SystemId`] in a [`CachedSystemId`](crate::system::CachedSystemId) resource.
pub fn run_system_cached<M, S>(system: S) -> impl Command
where
M: 'static,
S: IntoSystem<(), (), M> + Send + 'static,
{
move |world: &mut World| -> Result {
world.run_system_cached(system)?;
Ok(())
}
}
}

/// A [`Command`] that runs the given system with the given input value,
/// caching its [`SystemId`] in a [`CachedSystemId`](crate::system::CachedSystemId) resource.
///
/// To use the supplied input, the system should have a [`SystemInput`] as the first parameter.
pub fn run_system_cached_with<I, M, S>(system: S, input: I::Inner<'static>) -> impl Command
where
I: SystemInput<Inner<'static>: Send> + Send + 'static,
M: 'static,
S: IntoSystem<I, (), M> + Send + 'static,
{
move |world: &mut World| -> Result {
world.run_system_cached_with(system, input)?;
Ok(())
/// A [`Command`] that runs the given system with the given input value,
/// caching its [`SystemId`] in a [`CachedSystemId`](crate::system::CachedSystemId) resource.
///
/// To use the supplied input, the system should have a [`SystemInput`] as the first parameter.
pub fn run_system_cached_with<I, M, S>(system: S, input: I::Inner<'static>) -> impl Command
where
I: SystemInput<Inner<'static>: Send> + Send + 'static,
M: 'static,
S: IntoSystem<I, (), M> + Send + 'static,
{
move |world: &mut World| -> Result {
world.run_system_cached_with(system, input)?;
Ok(())
}
}
}

/// A [`Command`] that removes a system previously registered with
/// [`Commands::register_system`](crate::system::Commands::register_system) or
/// [`World::register_system`].
pub fn unregister_system<I, O>(system_id: SystemId<I, O>) -> impl Command
where
I: SystemInput + Send + 'static,
O: Send + 'static,
{
move |world: &mut World| -> Result {
world.unregister_system(system_id)?;
Ok(())
/// A [`Command`] that removes a system previously registered with
/// [`Commands::register_system`](crate::system::Commands::register_system) or
/// [`World::register_system`].
pub fn unregister_system<I, O>(system_id: SystemId<I, O>) -> impl Command
where
I: SystemInput + Send + 'static,
O: Send + 'static,
{
move |world: &mut World| -> Result {
world.unregister_system(system_id)?;
Ok(())
}
}
}

/// A [`Command`] that removes a system previously registered with one of the following:
/// - [`Commands::run_system_cached`](crate::system::Commands::run_system_cached)
/// - [`World::run_system_cached`]
/// - [`World::register_system_cached`]
pub fn unregister_system_cached<I, O, M, S>(system: S) -> impl Command
where
I: SystemInput + Send + 'static,
O: 'static,
M: 'static,
S: IntoSystem<I, O, M> + Send + 'static,
{
move |world: &mut World| -> Result {
world.unregister_system_cached(system)?;
Ok(())
/// A [`Command`] that removes a system previously registered with one of the following:
/// - [`Commands::run_system_cached`](crate::system::Commands::run_system_cached)
/// - [`World::run_system_cached`]
/// - [`World::register_system_cached`]
pub fn unregister_system_cached<I, O, M, S>(system: S) -> impl Command
where
I: SystemInput + Send + 'static,
O: 'static,
M: 'static,
S: IntoSystem<I, O, M> + Send + 'static,
{
move |world: &mut World| -> Result {
world.unregister_system_cached(system)?;
Ok(())
}
}
}

Expand Down
Loading