Decouple *what* plugins do from *when* they do it #14412
Labels
A-App
Bevy apps and plugins
C-Feature
A new feature, making something new possible
S-Needs-Design
This issue requires design work to think about how it would best be accomplished
Background
I've been developing a deterministic lockstep multiplayer game which requires multiple non-standard game loops:
What problem does this solve or what need does it fill?
On the one hand, there are tons of amazing plugins to use! On the other hand,
Plugin
strongly couples systems (what is done) to specific schedule (when it's done) through thebuild()
API. Unfortunately, for anyone using non-standard game loops, this almost immediately makes most plugins useless out of the box.Take for example something as core as the bevy provided
InputPlugin
:Here, we see that
InputPlugin
adds event maintenance to theFirst
schedule, which is part of the render loop. In this case, the coupling extends all the way down intoapp.rs
. If I wanted to reuse this logic for my own input polling loop, I can't useInputPlugin
. I can't even useadd_event
. At best, I must copy/paste large chunks of code from across bevy into my project using my schedules instead. This is less than idea because it's otherwise unnecessary work, but more so because I now have to keep that code in sync with upstream changes and improvements to bevy's. This process then repeats for each useful plugin I would like to leverage.My personal feeling is the progress being made on
FixedUpdate
isn't actually all that valuable so far primarily because of this coupling issue. Improvements keep coming, but we can't quite manage to close issues like, Inputs can be missed (or duplicated) when using a fixed time step. Plugins are tightly coupled specifically to the bevy versions of theUpdate
orFixedUpdate
loops, making anything even slightly different immediately very tricky and/or painful.What solution would you like?
I would love to somehow decouple what plugins do from when they do it. This doesn't inherently require any breaking changes, but I'm not set on a specific solution. Ultimately, those two aspects just need to be exposed in an (ideally easily) consumable way.
One potential solution I've been playing around with is to simply expose system sets for each logical chuck of systems, plus an "init". For example, this the the interface to my copy/pasted version of bevy's
InputPlugin
:Consumers are then free to add the exposed system sets to whatever schedules that meet their needs. One could even theoretically use the same logic on multiple schedules at the same time this way (e.g. local UI input vs deterministic player input). Granted, you would need to work around resources being
World
global.Plugin
could trivially be implemented on top of this for the same, nice out-of-the-box experience provided today.Also notice how I don't have to guess how long to keep events around for anymore, because the consumer specifies that information. Additionally, if
systems_tick_input_collect
is never used, no memory leak occurs.Summary
Anyway, like I said, I'm not particularly attached to a specific implementation. I would love to hear other ideas. Mostly, I hope to get people thinking about ways "mechanism" can be decoupled in bevy, because I think it will make bevy all the better.
Thanks for reading, and thanks for working on bevy!
Edit: fixed logic error in schedule example
The text was updated successfully, but these errors were encountered: