Tracked one-shot systems - #24165
Conversation
chescock
left a comment
There was a problem hiding this comment.
Looks good! I left some comments, but they're just style nits.
| I: SystemInput + 'static, | ||
| O: 'static, | ||
| { | ||
| let id = id.into(); |
There was a problem hiding this comment.
Do we need to worry about this monomorphizing two versions of this function?
There was a problem hiding this comment.
Maybe! Would be good to check how much of a difference the codegen is
Co-authored-by: Chris Russell <8494645+chescock@users.noreply.github.com>
Co-authored-by: Chris Russell <8494645+chescock@users.noreply.github.com>
| } | ||
|
|
||
| // A manual impl is used because the trait bounds should ignore the `I` and `O` phantom parameters, | ||
| // and so that the handle can be hashed based on its entity not its handle type. |
There was a problem hiding this comment.
Is there a typo? (maybe there is not, english is my second language)
// and so that the handle can be hashed based on its entity {instead of, and not} its handle type
There was a problem hiding this comment.
it would work with a "," before "not"
| } | ||
|
|
||
| /// Registers a system and returns a tracked [`SystemHandle`] so it can later | ||
| /// be called by [`World::run_system`]. The system entity will be automatically |
There was a problem hiding this comment.
I didn't see a conversion defined for from SystemHandle into SystemId. Maybe From<&SystemHandle> is needed, too.
And I think Command::run_system* should also accept a SystemHandle.
# Objective - The `SystemHandle` was introduced in bevyengine#24165. But it didn't come with full `run_system` support. ## Solution - Implement `From<SystemHandle<I, O>>` and `From<&SystemHandle<I, O>>` for `SystemId<I, O>` to make it available for `run_system`. Using `SystemHandle::entity()` and `SystemId::from_entity()`. - Let `Commands::run_system*` and `commands::command::run_system*` to accept `impl Into<SystemId>` ## Testing - Add a test `system::system_registry::tests::run_system_with_owned_system_handle`, to run a `SystemHandle`. --- ## Showcase ```rust world.run_system(handle) // or borrowing from a reference world.run_system(&handle) ```
# Objective #24087 introduces scene templating for `SystemId`s, however it can result in a memory leak if a scene is re-constructed multiple times: #24087 (comment) > This was proposed basically 1:1 in #24026 (this was later changed though). The issue is that it's unclear who owns these systems, that is who is responsible for unregistering them once they are no longer needed. Given that recreating the template will spawn the system again this basically becomes a memory leak. #24087 (comment) > > Hm, are you sure this is the case even tho in `build_template` it only registers the system the first time its called, switching over to storing the SystemId after the first call? > > If you recreate the template (e.g. you call `my_scene()` again) then you will create a new instance of the system. And since the system is not scoped to the scene once the scene is despawned the system entity will be leaked. Essentially, we need a way to connect the lifetime of the registered system to the lifetime of the scene. ## Solution This is a purely additive / opt-in / backwards-compatible version of #24114 Introducing: `SystemHandle`s ```rust pub enum SystemHandle<I: SystemInput = (), O = ()> { /// A strong handle keeps the system entity alive as long as the handle /// (and any clones of it) exist. Strong(Arc<StrongSystemHandle>), /// A weak handle does not keep the system entity alive. Weak(SystemId<I, O>), } pub struct StrongSystemHandle { entity: Entity, drop_queue: Arc<ConcurrentQueue<<Entity>>, } ``` Similar to `bevy_asset::Handle`s,`SystemHandle`'s custom `Drop` implementation enqueues the registered system entity into a concurrent queue. The system `despawn_unused_registered_systems` pulls from the other end of this queue and despawns the registered system entities. `World::register_tracked_system` and `World::register_tracked_boxed_system` are the only functions that return `SystemHandle`s. ## Testing - Added a test to ensure that `despawn_unused_registered_systems` does its job - Added a test to ensure that the default app will automatically call `despawn_unused_registered_systems` ## Future work - #24087 will use this PR as a base --------- Co-authored-by: Chris Russell <8494645+chescock@users.noreply.github.com> Co-authored-by: François Mockers <francois.mockers@vleue.com>
# Objective - The `SystemHandle` was introduced in #24165. But it didn't come with full `run_system` support. ## Solution - Implement `From<SystemHandle<I, O>>` and `From<&SystemHandle<I, O>>` for `SystemId<I, O>` to make it available for `run_system`. Using `SystemHandle::entity()` and `SystemId::from_entity()`. - Let `Commands::run_system*` and `commands::command::run_system*` to accept `impl Into<SystemId>` ## Testing - Add a test `system::system_registry::tests::run_system_with_owned_system_handle`, to run a `SystemHandle`. --- ## Showcase ```rust world.run_system(handle) // or borrowing from a reference world.run_system(&handle) ```
Objective
#24087 introduces scene templating for
SystemIds, however it can result in a memory leak if a scene is re-constructed multiple times:#24087 (comment)
#24087 (comment)
Essentially, we need a way to connect the lifetime of the registered system to the lifetime of the scene.
Solution
This is a purely additive / opt-in / backwards-compatible version of #24114
Introducing:
SystemHandlesSimilar to
bevy_asset::Handles,SystemHandle's customDropimplementation enqueues the registered system entity into a concurrent queue. The systemdespawn_unused_registered_systemspulls from the other end of this queue and despawns the registered system entities.World::register_tracked_systemandWorld::register_tracked_boxed_systemare the only functions that returnSystemHandles.Testing
despawn_unused_registered_systemsdoes its jobdespawn_unused_registered_systemsFuture work
SystemIdscene templating #24087 will use this PR as a base