Skip to content

Component features for resources#23168

Draft
Trashtalk217 wants to merge 3 commits intobevyengine:mainfrom
Trashtalk217:component-features-for-resources
Draft

Component features for resources#23168
Trashtalk217 wants to merge 3 commits intobevyengine:mainfrom
Trashtalk217:component-features-for-resources

Conversation

@Trashtalk217
Copy link
Contributor

Objective

Now that resources are components, any component feature can become a resource feature. We know we can, now we just need to figure out whether or not we should.

Solution

We're going through a list of features we can enable for resources, in the order of most reasonable to least reasonable. I invite everyone to add to this discussion and list reasons for or against adding a feature. This includes weird edge cases, confusing semantics, or novel use cases. In order to learn more about the features I'm referencing in a Component context, the documentation is a good start.

Configurable Storage

#[derive(Resource)]
#[resource(storage = "SparseSet")]
struct MyResource;

Pretty much a no-brainer: 0 downsides.

Custom Entity Mapping

#[derive(Resource)]
#[resource(map_entities)]
struct MyResource {
    items: HashMap<Entity, usize>,
}

impl MapEntities for MyResource {
    fn map_entities<M: EntityMapper>(&mut self, entity_mapper: &mut M) {
        self.items = self
            .items
            .drain()
            .map(|(id, count)| (entity_mapper.get_mapped(id), count))
            .collect();
    }
}

I'd have to do some testing to see that this actually does work in the contexts of entity cloning and scenes, but this should also be a pretty clear win without any downside.

Clone Behaviour

#[derive(Resource)]
#[resource(clone_behaviour = Ignore)]
struct MyResource;

Used in very similar contexts to custom entity mapping. I should write tests for this, but otherwise a pretty clear win.

Immutable Resources

#[derive(Resource)]
#[resource(immutable)]
struct MyResource {};

Why would you want an immutable resource? Not sure, but from now, you can. The only downside is that methods operating on mutable resources need to be annotated with Component<Mutability = Mutable>. Take for example try_resource_scope:

pub fn try_resource_scope<T: Resource + Component<Mutability = Mutable>, U>(&mut self) -> ...

So there's a bit of extra boilerplate there.

Resource Hooks

fn resource_hook(_world: DeferredWorld, _context: Hookcontext) {
    println!("Hello");
}

#[derive(Resource)]
#[resource(on_add = resource_hook)]
struct MyResource;

The original PR #20934 added support for observers. Component (resource) hooks, are slightly different. One potential problem with adding support for this is that resource_hook might read an invalid world state.

The 'resource-ness' of MyResource is determined by two things: the presence of an IsResource marker component on the same entity and there being an entry in the ResourceEntities hashmap (stored on World). IsResource is a required component and is added alongside MyResource in the same insertion.

Afterwards, the ResourceEntities hashmap is updated in the on_insert hook for IsResource. I'm uncertain whether or not this runs before or after any on_insert / on_add hooks for MyResource, so the MyResource hooks might perceive an invalid world state. The same goes for the on_discard / on_remove hooks.

This might not be such a big problem, because hooks are intended to maintain invariants. Only after all hooks are ran, can a user expect that everything is in order, but not before. If this is documented correctly, I think we can allow this.

Required Components

#[derive(Resource)]
#[require(Foo)]
struct MyResource;

Required components are really useful. Replicon uses them for networking components and it would be good to use the same code for resources. However there is a number of problems:

  • Additional components added to resource entities are not saved to scenes Remove resources from scenes #22968.
  • We need a way to prevent #[require(MyResource)] on a component or resource.
  • What about #[require(IsResource)]? Doubly requiring IsResource on a resource probably shouldn't be possible.

Relations

I don't know what this would even mean in the context of resources.

@Trashtalk217 Trashtalk217 added A-ECS Entities, components, systems, and events S-Needs-Design This issue requires design work to think about how it would best be accomplished labels Feb 27, 2026
@github-project-automation github-project-automation bot moved this to Needs SME Triage in ECS Feb 27, 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 S-Needs-Design This issue requires design work to think about how it would best be accomplished

Projects

Status: Needs SME Triage

Development

Successfully merging this pull request may close these issues.

1 participant