Skip to content

Support systems with In parameters in schedules #21658

@eira-fransham

Description

@eira-fransham

Motivation

Recently I’ve been working on scene loading with bevy_trenchbroom, and something that’s come up is the way a user can customise how scenes are loaded. Often, a game may want to have some domain-specific metadata that can customise (for example) properties of materials, the components that get applied to newly-created entities, etc. The current solution is using "hooks" - basically a set of domain-specific linked lists of function pointers, inserted at specific points in the loading process with specific responsibilities. A design we came up with is to have all user code be handled by systems that run in the scene's inner World. For this, we’d like to be able to define phases, to allow users to ensure the order their code runs in comparison to the processing done in bevy_trenchbroom by default. However, in an ideal world we would be able to pass the LoadContext in to the systems, to allow customising loading external dependencies etc. Anything accessible to systems needs to either be added as a resource (in which case it needs to be 'static, which LoadContext isn’t), or passed in via run_system_with. Since the schedule graph uses Systems, which bounds systems to use In = (), this means we can’t use schedules to handle this.

Proposed solution

My proposal would simply be to have SystemWithAccess, Systems, and Schedule have type parameters for input and output, which would both default to (). These would not change the implementation at all (users are considered responsible for handling order w.r.t to inputs/outputs), the new method for relevant types would only be for the <(), ()> instantiation, so users would need to use Default::default() to instantiate other versions, and Schedule::run(..) would only be available for Schedule<(), ()>. For simplicity, instead of introducing Schedule::run_with, the way to actually run these systems would probably be to just use topsort_graph and run the systems in sequence. On the topic of simplicity, I also think it’s fine to require all systems in Systems/Schedule to have the same inputs and outputs, rather than letting them store dynamic system IDs. This is a very minimal change but would be a nice quality-of-life feature for anyone who uses schedules outside of the context of an App and/or wants to run a one-shot schedule.

For the purposes of scene loading, I do feel that loading scenes that include entities with behaviour has unique-enough requirements that something more dedicated built in to Bevy could be useful, but this would, at least, give us primitives that we can experiment with.

Alternatives

The standard way to handle the original motivation is, as far as I know, to load all the assets in some basic form, wait for them to be loaded, then process them in the main loop to create the relevant entities. This works, but has a few issues:

  • The systems operate on the main world instead of in a completely separate world in a completely separate thread (potentially causing frame drops if significant processing is needed).
  • It doesn’t have easy access to assets before handles have been created from them, for example if you want to edit an image before applying it to a material you need to mark it as being CPU-accessible
  • Loading is a one-shot process, and you should ideally not have these systems in the main loop

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-AssetsLoad files from disk to use for things like images, models, and soundsA-ECSEntities, components, systems, and eventsC-FeatureA new feature, making something new possibleS-Needs-Design-DocThis issue or PR is particularly complex, and needs an approved design doc before it can be mergedX-ControversialThere is active debate or serious implications around merging this PR

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions