Skip to content

Remove resources from Access#22910

Merged
alice-i-cecile merged 18 commits intobevyengine:mainfrom
Trashtalk217:remove-resources-from-access
Mar 3, 2026
Merged

Remove resources from Access#22910
alice-i-cecile merged 18 commits intobevyengine:mainfrom
Trashtalk217:remove-resources-from-access

Conversation

@Trashtalk217
Copy link
Copy Markdown
Contributor

@Trashtalk217 Trashtalk217 commented Feb 11, 2026

Objective

There's a lot of code duplication in access.rs. The same logic is duplicated between components and resources. This also takes up unnecessary memory in Access, as it relies on bitsets spanning the entire ComponentId range.

Solution

Since resources are now a special kind of component, this can be removed.

Limitations

Since !Send data queries used Access resources, !Send data queries now conflict with broad queries.

// 0.18
fn system(q1_: Query<EntityMut>, q2_: NonSend<R>) {} // valid, does not conflict

// 0.19
fn system(q1_: Query<EntityMut>, q2_: NonSend<R>) {} // invalid, does conflict

Given how rarely non-send data is used, I recommend using

// 0.19
fn system(q1_: Query<EntityMut, Without<R>>, q2_: NonSend<R>) {} // works again

If this is also unacceptable, this PR is blocked on the !Send data removal from the ECS (or some hacky workaround).

Extra Attention

@chescock brought AssetChanged to my attention. It has a weird access pattern. See the following example:

fn system(c: Query<&mut AssetChanges<Mesh>>, r: Query<(), AssetChanged<Mesh>>) {}

System c registers access with add_write for AssetChanges<Mesh>, while r registers access with add_read for both Mesh and AssetChanges<Mesh>. This system is invalid, and I've added a test to reflect that. However, since this stuff is tricky, I would like some extra eyes on it. Currently, it looks fine.

@Trashtalk217 Trashtalk217 added A-ECS Entities, components, systems, and events C-Code-Quality A section of code that is hard to understand or change labels Feb 11, 2026
@alice-i-cecile alice-i-cecile added S-Needs-Review Needs reviewer attention (from anyone!) to move forward S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Feb 11, 2026
@cart cart added this to ECS Feb 12, 2026
@github-project-automation github-project-automation bot moved this to Needs SME Triage in ECS Feb 12, 2026
@alice-i-cecile alice-i-cecile added this to the 0.19 milestone Feb 12, 2026
@alice-i-cecile alice-i-cecile moved this from Needs SME Triage to SME Triaged in ECS Feb 12, 2026
@Trashtalk217 Trashtalk217 marked this pull request as ready for review February 17, 2026 15:58
@Trashtalk217 Trashtalk217 added M-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide S-Needs-Review Needs reviewer attention (from anyone!) to move forward and removed S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged labels Feb 17, 2026
@github-actions
Copy link
Copy Markdown
Contributor

It looks like your PR is a breaking change, but you didn't provide a migration guide.

Please review the instructions for writing migration guides, then expand or revise the content in the migration guides directory to reflect your changes.

@hymm hymm self-requested a review February 18, 2026 01:05
@Trashtalk217 Trashtalk217 added the D-Unsafe Touches with unsafe code in some way label Feb 18, 2026
@Trashtalk217 Trashtalk217 added S-Blocked This cannot move forward until something else changes and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Feb 19, 2026
@Trashtalk217
Copy link
Copy Markdown
Contributor Author

Alright, since #23138, this PR is unblocked. Which leaves me with one question for reviewers. Is the following code acceptable?

// 0.18
fn system(q1_: Query<EntityMut>, q2_: NonSend<R>) {} // works

// 0.19
fn system(q1_: Query<EntityMut, Without<R>>, q2_: NonSend<R>) {} // works again

One possible other solution is to add a fake IsNonSend component to the world. This component will only ever be registered, never spawned, and each NonSend<R> accesses (&R, With<IsNonSend>) under the hood (much like how resources work). In that case you can do:

// 0.18
fn system(q1_: Query<EntityMut>, q2_: NonSend<R>) {} // works

// 0.19
fn system(q1_: Query<EntityMut, Without<IsNonSend>>, q2_: NonSend<R>) {} // works again

This scales slightly better over multiple non-send data, but it's so specific that I (personally) don't think it's worth bothering with.

@Trashtalk217 Trashtalk217 added S-Needs-Review Needs reviewer attention (from anyone!) to move forward and removed S-Blocked This cannot move forward until something else changes labels Mar 1, 2026
Copy link
Copy Markdown
Member

@alice-i-cecile alice-i-cecile left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good renames, great use of deprecations, solid and clear migration guide, and a much welcome cleanup.

Only blocking feedback is "we should add a test to verify that Query<EntityMut, Without<IsResource> + Res<Foo> is a valid system". I've also left a couple of small suggestions for improvements, but those are non-blocking.

@alice-i-cecile
Copy link
Copy Markdown
Member

This scales slightly better over multiple non-send data, but it's so specific that I (personally) don't think it's worth bothering with.

I agree: I think this is so niche that it's not worth the maintenance or compile time cost. EntityMut + multiple NonSend accesses in a single component is... very unusual.

Copy link
Copy Markdown
Contributor

@chescock chescock left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good! And even with the migration guide and #[deprecated] methods being added, it's still removing a few hundred lines of code!

I think we should fix the typos in the deprecation notes before merging, but the rest of my comments are just style nits.

}

/// Adds a read access to a component to the set.
pub fn add_unfiltered_component_read(&mut self, index: ComponentId) {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we actually need this method? It was a common pattern for resources, but I wouldn't expect it to be all that useful for other components.

... Oh, I see, it's used by NonSend and in some tests. I don't want to ask you to refactor those, but I might be inclined to leave this non-pub so that users don't think it's common and so that we can remove it in the future as a non-breaking change. It's not all that many lines of code if they really do need this behavior.

if !accesses.is_empty() {
accesses.push(' ');
}
panic!("error[B0002]: Res<{}> in system {} conflicts with a previous system parameter. Consider using `Without<IsResource>` to create disjoint Queries or merging conflicting Queries into a `ParamSet`. See: https://bevy.org/learn/errors/b0002", DebugName::type_name::<T>(), system_meta.name);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we keep the "Consider removing the duplicate access" part? We used to raise this error mostly for things like fn system(_: ResMut<R>, _: Res<R>), and that case may still be common even if we now also raise it for fn system(_: Query<EntityMut>, _: Res<R>).

Do we need to update the text at https://bevy.org/learn/errors/b0002 at all?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Probably, but that's a seperate PR.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nvm did it

Comment on lines +253 to +256
let mut filter = FilteredAccess::default();
filter.add_read(state.resource_id);
filter.and_with(IS_RESOURCE);
component_access_set.add(filter);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are a few places with this block of code that you can replace with FilteredAccessSet::add_resource_read now that we have it

Suggested change
let mut filter = FilteredAccess::default();
filter.add_read(state.resource_id);
filter.and_with(IS_RESOURCE);
component_access_set.add(filter);
component_access_set.add_resource_read(state.resource_id);

The others are in Res, ResMut, and AssetChanged, but GitHub won't let me make suggestions there because the diff crosses added and removed lines.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The others can't quite be replaced because of the way we immediately check for conflicts, but this one can be subbed out.

@chescock
Copy link
Copy Markdown
Contributor

chescock commented Mar 2, 2026

we should add a test to verify that Query<EntityMut, Without<IsResource> + Res<Foo> is a valid system

It looks like we have an existing test that verifies that systems with those parameters don't conflict. That should be roughly equivalent, although it's a little more complex to read:

fn resource_and_entity_mut() {

@alice-i-cecile alice-i-cecile added S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Mar 2, 2026
@alice-i-cecile alice-i-cecile added S-Needs-Review Needs reviewer attention (from anyone!) to move forward and removed S-Waiting-on-Author The author needs to make changes or address concerns before this can be merged labels Mar 2, 2026
@alice-i-cecile alice-i-cecile added S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it and removed S-Needs-Review Needs reviewer attention (from anyone!) to move forward labels Mar 2, 2026
@alice-i-cecile alice-i-cecile added this pull request to the merge queue Mar 2, 2026
Merged via the queue into bevyengine:main with commit c89541a Mar 3, 2026
42 checks passed
@github-project-automation github-project-automation bot moved this from SME Triaged to Done in ECS Mar 3, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

A-ECS Entities, components, systems, and events C-Code-Quality A section of code that is hard to understand or change D-Unsafe Touches with unsafe code in some way M-Migration-Guide A breaking change to Bevy's public API that needs to be noted in a migration guide S-Ready-For-Final-Review This PR has been approved by the community. It's ready for a maintainer to consider merging it

Projects

Status: Done

Development

Successfully merging this pull request may close these issues.

5 participants