From a6574786757c0a0a7ddffb99fdc40ce90980fc82 Mon Sep 17 00:00:00 2001 From: Jakob Hellermann Date: Tue, 9 Jan 2024 20:08:15 +0100 Subject: [PATCH] resolve all internal ambiguities (#10411) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - ignore all ambiguities that are not a problem - remove `.before(Assets::::track_assets),` that points into a different schedule (-> should this be caught?) - add some explicit orderings: - run `poll_receivers` and `update_accessibility_nodes` after `window_closed` in `bevy_winit::accessibility` - run `bevy_ui::accessibility::calc_bounds` after `CameraUpdateSystem` - run ` bevy_text::update_text2d_layout` and `bevy_ui::text_system` after `font_atlas_set::remove_dropped_font_atlas_sets` - add `app.ignore_ambiguity(a, b)` function for cases where you want to ignore an ambiguity between two independent plugins `A` and `B` - add `IgnoreAmbiguitiesPlugin` in `DefaultPlugins` that allows cross-crate ambiguities like `bevy_animation`/`bevy_ui` - Fixes https://github.com/bevyengine/bevy/issues/9511 ## Before **Render** ![render_schedule_Render dot](https://github.com/bevyengine/bevy/assets/22177966/1c677968-7873-40cc-848c-91fca4c8e383) **PostUpdate** ![schedule_PostUpdate dot](https://github.com/bevyengine/bevy/assets/22177966/8fc61304-08d4-4533-8110-c04113a7367a) ## After **Render** ![render_schedule_Render dot](https://github.com/bevyengine/bevy/assets/22177966/462f3b28-cef7-4833-8619-1f5175983485) **PostUpdate** ![schedule_PostUpdate dot](https://github.com/bevyengine/bevy/assets/22177966/8cfb3d83-7842-4a84-9082-46177e1a6c70) --------- Co-authored-by: Alice Cecile Co-authored-by: Alice Cecile Co-authored-by: François --- crates/bevy_a11y/src/lib.rs | 3 +- crates/bevy_app/src/app.rs | 32 +++++++++++++++ crates/bevy_audio/src/audio_output.rs | 2 +- crates/bevy_core_pipeline/src/blit/mod.rs | 4 ++ crates/bevy_ecs/src/schedule/schedule.rs | 31 +++++++++++++++ crates/bevy_gizmos/src/lib.rs | 13 +++++- crates/bevy_gizmos/src/pipeline_2d.rs | 10 +++-- crates/bevy_gizmos/src/pipeline_3d.rs | 10 +++-- crates/bevy_internal/src/default_plugins.rs | 44 ++++++++++++++++++++- crates/bevy_pbr/src/lib.rs | 9 +++++ crates/bevy_pbr/src/material.rs | 4 +- crates/bevy_pbr/src/prepass/mod.rs | 5 ++- crates/bevy_pbr/src/render/mesh.rs | 1 + crates/bevy_render/src/view/mod.rs | 3 +- crates/bevy_text/src/lib.rs | 1 + crates/bevy_ui/src/accessibility.rs | 9 ++++- crates/bevy_ui/src/lib.rs | 32 +++++++++++---- crates/bevy_ui/src/render/mod.rs | 1 + crates/bevy_winit/src/accessibility.rs | 13 +++--- 19 files changed, 199 insertions(+), 28 deletions(-) diff --git a/crates/bevy_a11y/src/lib.rs b/crates/bevy_a11y/src/lib.rs index 4a1948c065ec7..44e4f5cb9031a 100644 --- a/crates/bevy_a11y/src/lib.rs +++ b/crates/bevy_a11y/src/lib.rs @@ -105,6 +105,7 @@ impl Plugin for AccessibilityPlugin { fn build(&self, app: &mut bevy_app::App) { app.init_resource::() .init_resource::() - .init_resource::(); + .init_resource::() + .allow_ambiguous_component::(); } } diff --git a/crates/bevy_app/src/app.rs b/crates/bevy_app/src/app.rs index 8a884038987f5..f117db2e77e40 100644 --- a/crates/bevy_app/src/app.rs +++ b/crates/bevy_app/src/app.rs @@ -1000,6 +1000,38 @@ impl App { self.world.allow_ambiguous_resource::(); self } + + /// Suppress warnings and errors that would result from systems in these sets having ambiguities + /// (conflicting access but indeterminate order) with systems in `set`. + /// + /// When possible, do this directly in the `.add_systems(Update, a.ambiguous_with(b))` call. + /// However, sometimes two independant plugins `A` and `B` are reported as ambiguous, which you + /// can only supress as the consumer of both. + #[track_caller] + pub fn ignore_ambiguity( + &mut self, + schedule: impl ScheduleLabel, + a: S1, + b: S2, + ) -> &mut Self + where + S1: IntoSystemSet, + S2: IntoSystemSet, + { + let schedule = schedule.intern(); + let mut schedules = self.world.resource_mut::(); + + if let Some(schedule) = schedules.get_mut(schedule) { + let schedule: &mut Schedule = schedule; + schedule.ignore_ambiguity(a, b); + } else { + let mut new_schedule = Schedule::new(schedule); + new_schedule.ignore_ambiguity(a, b); + schedules.insert(new_schedule); + } + + self + } } fn run_once(mut app: App) { diff --git a/crates/bevy_audio/src/audio_output.rs b/crates/bevy_audio/src/audio_output.rs index b799c1a9f5ceb..2e6faf266e793 100644 --- a/crates/bevy_audio/src/audio_output.rs +++ b/crates/bevy_audio/src/audio_output.rs @@ -291,7 +291,7 @@ pub(crate) fn audio_output_available(audio_output: Res) -> bool { /// Updates spatial audio sinks when emitter positions change. pub(crate) fn update_emitter_positions( - mut emitters: Query<(&mut GlobalTransform, &SpatialAudioSink), Changed>, + mut emitters: Query<(&GlobalTransform, &SpatialAudioSink), Changed>, spatial_scale: Res, ) { for (transform, sink) in emitters.iter_mut() { diff --git a/crates/bevy_core_pipeline/src/blit/mod.rs b/crates/bevy_core_pipeline/src/blit/mod.rs index 9a9777a43f212..91258c034de59 100644 --- a/crates/bevy_core_pipeline/src/blit/mod.rs +++ b/crates/bevy_core_pipeline/src/blit/mod.rs @@ -20,6 +20,10 @@ pub struct BlitPlugin; impl Plugin for BlitPlugin { fn build(&self, app: &mut App) { load_internal_asset!(app, BLIT_SHADER_HANDLE, "blit.wgsl", Shader::from_wgsl); + + if let Ok(render_app) = app.get_sub_app_mut(RenderApp) { + render_app.allow_ambiguous_resource::>(); + } } fn finish(&self, app: &mut App) { diff --git a/crates/bevy_ecs/src/schedule/schedule.rs b/crates/bevy_ecs/src/schedule/schedule.rs index 31a4c6f9cdab4..0cf8fec0ee7eb 100644 --- a/crates/bevy_ecs/src/schedule/schedule.rs +++ b/crates/bevy_ecs/src/schedule/schedule.rs @@ -244,6 +244,37 @@ impl Schedule { self } + /// Suppress warnings and errors that would result from systems in these sets having ambiguities + /// (conflicting access but indeterminate order) with systems in `set`. + #[track_caller] + pub fn ignore_ambiguity(&mut self, a: S1, b: S2) -> &mut Self + where + S1: IntoSystemSet, + S2: IntoSystemSet, + { + let a = a.into_system_set(); + let b = b.into_system_set(); + + let Some(&a_id) = self.graph.system_set_ids.get(&a.intern()) else { + panic!( + "Could not mark system as ambiguous, `{:?}` was not found in the schedule. + Did you try to call `ambiguous_with` before adding the system to the world?", + a + ); + }; + let Some(&b_id) = self.graph.system_set_ids.get(&b.intern()) else { + panic!( + "Could not mark system as ambiguous, `{:?}` was not found in the schedule. + Did you try to call `ambiguous_with` before adding the system to the world?", + b + ); + }; + + self.graph.ambiguous_with.add_edge(a_id, b_id, ()); + + self + } + /// Configures a collection of system sets in this schedule, adding them if they does not exist. #[track_caller] pub fn configure_sets(&mut self, sets: impl IntoSystemSetConfigs) -> &mut Self { diff --git a/crates/bevy_gizmos/src/lib.rs b/crates/bevy_gizmos/src/lib.rs index 862b008e8c74e..470ae26650d6b 100644 --- a/crates/bevy_gizmos/src/lib.rs +++ b/crates/bevy_gizmos/src/lib.rs @@ -15,6 +15,17 @@ //! //! See the documentation on [`Gizmos`] for more examples. +/// Label for the the render systems handling the +#[derive(SystemSet, Clone, Debug, Hash, PartialEq, Eq)] +pub enum GizmoRenderSystem { + /// Adds gizmos to the [`Transparent2d`](bevy_core_pipeline::core_2d::Transparent2d) render phase + #[cfg(feature = "bevy_sprite")] + QueueLineGizmos2d, + /// Adds gizmos to the [`Transparent3d`](bevy_core_pipeline::core_3d::Transparent3d) render phase + #[cfg(feature = "bevy_pbr")] + QueueLineGizmos3d, +} + pub mod arcs; pub mod arrows; pub mod circles; @@ -40,7 +51,7 @@ use bevy_ecs::{ entity::Entity, query::{ROQueryItem, Without}, reflect::{ReflectComponent, ReflectResource}, - schedule::IntoSystemConfigs, + schedule::{IntoSystemConfigs, SystemSet}, system::{ lifetimeless::{Read, SRes}, Commands, Query, Res, ResMut, Resource, SystemParamItem, diff --git a/crates/bevy_gizmos/src/pipeline_2d.rs b/crates/bevy_gizmos/src/pipeline_2d.rs index 5b64598eb403f..dd53a40e5fc9e 100644 --- a/crates/bevy_gizmos/src/pipeline_2d.rs +++ b/crates/bevy_gizmos/src/pipeline_2d.rs @@ -1,5 +1,5 @@ use crate::{ - line_gizmo_vertex_buffer_layouts, DrawLineGizmo, GizmoConfig, LineGizmo, + line_gizmo_vertex_buffer_layouts, DrawLineGizmo, GizmoConfig, GizmoRenderSystem, LineGizmo, LineGizmoUniformBindgroupLayout, SetLineGizmoBindGroup, LINE_SHADER_HANDLE, }; use bevy_app::{App, Plugin}; @@ -8,7 +8,7 @@ use bevy_core_pipeline::core_2d::Transparent2d; use bevy_ecs::{ prelude::Entity, - schedule::IntoSystemConfigs, + schedule::{IntoSystemConfigs, IntoSystemSetConfigs}, system::{Query, Res, ResMut, Resource}, world::{FromWorld, World}, }; @@ -34,10 +34,14 @@ impl Plugin for LineGizmo2dPlugin { render_app .add_render_command::() .init_resource::>() + .configure_sets( + Render, + GizmoRenderSystem::QueueLineGizmos2d.in_set(RenderSet::Queue), + ) .add_systems( Render, queue_line_gizmos_2d - .in_set(RenderSet::Queue) + .in_set(GizmoRenderSystem::QueueLineGizmos2d) .after(prepare_assets::), ); } diff --git a/crates/bevy_gizmos/src/pipeline_3d.rs b/crates/bevy_gizmos/src/pipeline_3d.rs index 2cb016753513b..9ea991e4753a2 100644 --- a/crates/bevy_gizmos/src/pipeline_3d.rs +++ b/crates/bevy_gizmos/src/pipeline_3d.rs @@ -1,5 +1,5 @@ use crate::{ - line_gizmo_vertex_buffer_layouts, DrawLineGizmo, GizmoConfig, LineGizmo, + line_gizmo_vertex_buffer_layouts, DrawLineGizmo, GizmoConfig, GizmoRenderSystem, LineGizmo, LineGizmoUniformBindgroupLayout, SetLineGizmoBindGroup, LINE_SHADER_HANDLE, }; use bevy_app::{App, Plugin}; @@ -12,7 +12,7 @@ use bevy_core_pipeline::{ use bevy_ecs::{ prelude::Entity, query::Has, - schedule::IntoSystemConfigs, + schedule::{IntoSystemConfigs, IntoSystemSetConfigs}, system::{Query, Res, ResMut, Resource}, world::{FromWorld, World}, }; @@ -36,10 +36,14 @@ impl Plugin for LineGizmo3dPlugin { render_app .add_render_command::() .init_resource::>() + .configure_sets( + Render, + GizmoRenderSystem::QueueLineGizmos3d.in_set(RenderSet::Queue), + ) .add_systems( Render, queue_line_gizmos_3d - .in_set(RenderSet::Queue) + .in_set(GizmoRenderSystem::QueueLineGizmos3d) .after(prepare_assets::), ); } diff --git a/crates/bevy_internal/src/default_plugins.rs b/crates/bevy_internal/src/default_plugins.rs index d95957ab43dbf..0b87248f86a93 100644 --- a/crates/bevy_internal/src/default_plugins.rs +++ b/crates/bevy_internal/src/default_plugins.rs @@ -1,4 +1,4 @@ -use bevy_app::{PluginGroup, PluginGroupBuilder}; +use bevy_app::{Plugin, PluginGroup, PluginGroupBuilder}; /// This plugin group will add all the default plugins for a *Bevy* application: /// * [`LogPlugin`](crate::log::LogPlugin) @@ -133,10 +133,52 @@ impl PluginGroup for DefaultPlugins { group = group.add(bevy_gizmos::GizmoPlugin); } + group = group.add(IgnoreAmbiguitiesPlugin); + group } } +struct IgnoreAmbiguitiesPlugin; + +impl Plugin for IgnoreAmbiguitiesPlugin { + #[allow(unused_variables)] // Variables are used depending on enabled features + fn build(&self, app: &mut bevy_app::App) { + // bevy_ui owns the Transform and cannot be animated + #[cfg(all(feature = "bevy_animation", feature = "bevy_ui"))] + app.ignore_ambiguity( + bevy_app::PostUpdate, + bevy_animation::animation_player, + bevy_ui::ui_layout_system, + ); + + #[cfg(feature = "bevy_render")] + if let Ok(render_app) = app.get_sub_app_mut(bevy_render::RenderApp) { + #[cfg(all(feature = "bevy_gizmos", feature = "bevy_sprite"))] + { + render_app.ignore_ambiguity( + bevy_render::Render, + bevy_gizmos::GizmoRenderSystem::QueueLineGizmos2d, + bevy_sprite::queue_sprites, + ); + render_app.ignore_ambiguity( + bevy_render::Render, + bevy_gizmos::GizmoRenderSystem::QueueLineGizmos2d, + bevy_sprite::queue_material2d_meshes::, + ); + } + #[cfg(all(feature = "bevy_gizmos", feature = "bevy_pbr"))] + { + render_app.ignore_ambiguity( + bevy_render::Render, + bevy_gizmos::GizmoRenderSystem::QueueLineGizmos3d, + bevy_pbr::queue_material_meshes::, + ); + } + } + } +} + /// This plugin group will add the minimal plugins for a *Bevy* application: /// * [`TaskPoolPlugin`](crate::core::TaskPoolPlugin) /// * [`TypeRegistrationPlugin`](crate::core::TypeRegistrationPlugin) diff --git a/crates/bevy_pbr/src/lib.rs b/crates/bevy_pbr/src/lib.rs index ba29ccce3fc91..97fd0a0ecc5bd 100644 --- a/crates/bevy_pbr/src/lib.rs +++ b/crates/bevy_pbr/src/lib.rs @@ -361,6 +361,15 @@ impl Plugin for PbrPlugin { draw_3d_graph::node::SHADOW_PASS, bevy_core_pipeline::core_3d::graph::node::START_MAIN_PASS, ); + + render_app.ignore_ambiguity( + bevy_render::Render, + bevy_core_pipeline::core_3d::prepare_core_3d_transmission_textures, + bevy_render::batching::batch_and_prepare_render_phase::< + bevy_core_pipeline::core_3d::Transmissive3d, + MeshPipeline, + >, + ); } fn finish(&self, app: &mut App) { diff --git a/crates/bevy_pbr/src/material.rs b/crates/bevy_pbr/src/material.rs index e8f9601cb18ab..3af43aeda69d5 100644 --- a/crates/bevy_pbr/src/material.rs +++ b/crates/bevy_pbr/src/material.rs @@ -234,7 +234,9 @@ where .after(prepare_materials::), queue_material_meshes:: .in_set(RenderSet::QueueMeshes) - .after(prepare_materials::), + .after(prepare_materials::) + // queue_material_meshes only writes to `material_bind_group_id`, which `queue_shadows` doesn't read + .ambiguous_with(render::queue_shadows::), ), ); } diff --git a/crates/bevy_pbr/src/prepass/mod.rs b/crates/bevy_pbr/src/prepass/mod.rs index 9d557327f08da..6b05982f8942e 100644 --- a/crates/bevy_pbr/src/prepass/mod.rs +++ b/crates/bevy_pbr/src/prepass/mod.rs @@ -98,6 +98,7 @@ where ) .init_resource::() .init_resource::>>() + .allow_ambiguous_resource::>>() .init_resource::(); } @@ -168,7 +169,9 @@ where Render, queue_prepass_material_meshes:: .in_set(RenderSet::QueueMeshes) - .after(prepare_materials::), + .after(prepare_materials::) + // queue_material_meshes only writes to `material_bind_group_id`, which `queue_prepass_material_meshes` doesn't read + .ambiguous_with(queue_material_meshes::), ); } } diff --git a/crates/bevy_pbr/src/render/mesh.rs b/crates/bevy_pbr/src/render/mesh.rs index 23820a2761443..03bec26da9873 100644 --- a/crates/bevy_pbr/src/render/mesh.rs +++ b/crates/bevy_pbr/src/render/mesh.rs @@ -130,6 +130,7 @@ impl Plugin for MeshRenderPlugin { .init_resource::() .init_resource::() .init_resource::() + .allow_ambiguous_resource::>() .add_systems( ExtractSchedule, (extract_meshes, extract_skins, extract_morphs), diff --git a/crates/bevy_render/src/view/mod.rs b/crates/bevy_render/src/view/mod.rs index af91222152886..62b20c206ff8f 100644 --- a/crates/bevy_render/src/view/mod.rs +++ b/crates/bevy_render/src/view/mod.rs @@ -61,7 +61,8 @@ impl Plugin for ViewPlugin { prepare_view_targets .in_set(RenderSet::ManageViews) .after(prepare_windows) - .after(crate::render_asset::prepare_assets::), + .after(crate::render_asset::prepare_assets::) + .ambiguous_with(crate::camera::sort_cameras), // doesn't use `sorted_camera_index_for_target` prepare_view_uniforms.in_set(RenderSet::PrepareResources), ), ); diff --git a/crates/bevy_text/src/lib.rs b/crates/bevy_text/src/lib.rs index 06783e12242fb..d0b5752266f55 100644 --- a/crates/bevy_text/src/lib.rs +++ b/crates/bevy_text/src/lib.rs @@ -94,6 +94,7 @@ impl Plugin for TextPlugin { PostUpdate, ( update_text2d_layout + .after(font_atlas_set::remove_dropped_font_atlas_sets) // Potential conflict: `Assets` // In practice, they run independently since `bevy_render::camera_update_system` // will only ever observe its own render target, and `update_text2d_layout` diff --git a/crates/bevy_ui/src/accessibility.rs b/crates/bevy_ui/src/accessibility.rs index 50e883695524a..7620c18519208 100644 --- a/crates/bevy_ui/src/accessibility.rs +++ b/crates/bevy_ui/src/accessibility.rs @@ -15,7 +15,7 @@ use bevy_ecs::{ world::Ref, }; use bevy_hierarchy::Children; -use bevy_render::prelude::Camera; +use bevy_render::{camera::CameraUpdateSystem, prelude::Camera}; use bevy_text::Text; use bevy_transform::prelude::GlobalTransform; @@ -150,7 +150,12 @@ impl Plugin for AccessibilityPlugin { app.add_systems( PostUpdate, ( - calc_bounds.after(bevy_transform::TransformSystem::TransformPropagate), + calc_bounds + .after(bevy_transform::TransformSystem::TransformPropagate) + .after(CameraUpdateSystem) + // the listed systems do not affect calculated size + .ambiguous_with(crate::resolve_outlines_system) + .ambiguous_with(crate::ui_stack_system), button_changed, image_changed, label_changed, diff --git a/crates/bevy_ui/src/lib.rs b/crates/bevy_ui/src/lib.rs index ee9b34ff32343..54322d1573363 100644 --- a/crates/bevy_ui/src/lib.rs +++ b/crates/bevy_ui/src/lib.rs @@ -45,10 +45,9 @@ use crate::prelude::UiCameraConfig; #[cfg(feature = "bevy_text")] use crate::widget::TextFlags; use bevy_app::prelude::*; -use bevy_asset::Assets; use bevy_ecs::prelude::*; use bevy_input::InputSystem; -use bevy_render::{extract_component::ExtractComponentPlugin, texture::Image, RenderApp}; +use bevy_render::{extract_component::ExtractComponentPlugin, RenderApp}; use bevy_transform::TransformSystem; use stack::ui_stack_system; pub use stack::UiStack; @@ -152,16 +151,26 @@ impl Plugin for UiPlugin { // Potential conflict: `Assets` // Since both systems will only ever insert new [`Image`] assets, // they will never observe each other's effects. - .ambiguous_with(bevy_text::update_text2d_layout), + .ambiguous_with(bevy_text::update_text2d_layout) + // We assume Text is on disjoint UI entities to UiImage and UiTextureAtlasImage + // FIXME: Add an archetype invariant for this https://github.com/bevyengine/bevy/issues/1481. + .ambiguous_with(widget::update_image_content_size_system) + .ambiguous_with(widget::update_atlas_content_size_system), widget::text_system .after(UiSystem::Layout) - .before(Assets::::track_assets), + .after(bevy_text::remove_dropped_font_atlas_sets) + // Text2d and bevy_ui text are entirely on separate entities + .ambiguous_with(bevy_text::update_text2d_layout), ), ); #[cfg(feature = "bevy_text")] app.add_plugins(accessibility::AccessibilityPlugin); app.add_systems(PostUpdate, { - let system = widget::update_image_content_size_system.before(UiSystem::Layout); + let system = widget::update_image_content_size_system + .before(UiSystem::Layout) + // We assume UiImage, UiTextureAtlasImage are disjoint UI entities + // FIXME: Add an archetype invariant for this https://github.com/bevyengine/bevy/issues/1481. + .ambiguous_with(widget::update_atlas_content_size_system); // Potential conflicts: `Assets` // They run independently since `widget::image_node_system` will only ever observe // its own UiImage, and `widget::text_system` & `bevy_text::update_text2d_layout` @@ -185,8 +194,17 @@ impl Plugin for UiPlugin { .before(TransformSystem::TransformPropagate), resolve_outlines_system .in_set(UiSystem::Outlines) - .after(UiSystem::Layout), - ui_stack_system.in_set(UiSystem::Stack), + .after(UiSystem::Layout) + // clipping doesn't care about outlines + .ambiguous_with(update_clipping_system) + .ambiguous_with(widget::text_system), + ui_stack_system + .in_set(UiSystem::Stack) + // the systems don't care about stack index + .ambiguous_with(update_clipping_system) + .ambiguous_with(resolve_outlines_system) + .ambiguous_with(ui_layout_system) + .ambiguous_with(widget::text_system), update_clipping_system.after(TransformSystem::TransformPropagate), ), ); diff --git a/crates/bevy_ui/src/render/mod.rs b/crates/bevy_ui/src/render/mod.rs index c1c4a9f370bb7..60dfd1fab65e7 100644 --- a/crates/bevy_ui/src/render/mod.rs +++ b/crates/bevy_ui/src/render/mod.rs @@ -74,6 +74,7 @@ pub fn build_ui_render(app: &mut App) { .init_resource::() .init_resource::() .init_resource::() + .allow_ambiguous_resource::() .init_resource::>() .add_render_command::() .add_systems( diff --git a/crates/bevy_winit/src/accessibility.rs b/crates/bevy_winit/src/accessibility.rs index 50d5b0bdc134b..e1ea386af535e 100644 --- a/crates/bevy_winit/src/accessibility.rs +++ b/crates/bevy_winit/src/accessibility.rs @@ -187,12 +187,13 @@ impl Plugin for AccessKitPlugin { .add_event::() .add_systems( PostUpdate, - (window_closed, poll_receivers).in_set(AccessibilitySystem::Update), - ) - .add_systems( - PostUpdate, - update_accessibility_nodes - .run_if(should_update_accessibility_nodes) + ( + poll_receivers, + update_accessibility_nodes.run_if(should_update_accessibility_nodes), + window_closed + .before(poll_receivers) + .before(update_accessibility_nodes), + ) .in_set(AccessibilitySystem::Update), ); }