bevyengine / bevy

A refreshingly simple data-driven game engine built in Rust
https://bevyengine.org
Apache License 2.0
34.78k stars 3.4k forks source link

Abstraction of bevy_dev_tools #12368

Open matiqo15 opened 5 months ago

matiqo15 commented 5 months ago

What problem does this solve or what need does it fill?

Allow for configuration of dev tools

What solution would you like?

Ideally, we're looking for something that:

Additional context

see https://github.com/bevyengine/bevy/pull/12354#discussion_r1516637590

pablo-lua commented 5 months ago

Ideally, we would Fix #11083 and follow with some type of API from that.

But while we don't have it, one challenge of doing this now is the fact that we need to use something other than a plugin for it or similar. A problem that I can see is the fact that the major part of the tools need to add systems and so in the App building for working, something that I can't imagine doing without plugins, the only API that I can imagine working somehow is One Shot systems.

matiqo15 commented 5 months ago

I don't think #11083 will be fixed anytime soon though, we could just drop configuration during runtime for now but keep it in mind for the future. We need some abstraction before merging more than few tools.

alice-i-cecile commented 5 months ago

Yeah, I would like to avoid coupling this too tightly to the current Plugin trait.

The other key requirements I have are:

  1. It's easy to toggle one on and off independently.
  2. It's easy to toggle all of them on and off independently.
  3. There's a simple standard way to add third-party or user-created dev tools to this group, which can then be toggled on and off.
BD103 commented 5 months ago

3. There's a simple standard way to add third-party or user-created dev tools to this group, which can then be toggled on and off.

What if dev tools were stored in a Resource, which could be registered with a trait on App?

fn main() {
    App::new()
        .register_dev_tool(MyEpicEditorDoodad)
        .run();
}

#[derive(Resource)]
struct DevTools(Vec<Box<dyn DevTool>>);

trait DevTool {
    // TODO: What methods are needed here?
}

trait DevToolsExt: Sealed {
    fn register_dev_tool(&mut self, tool: impl DevTool) -> &mut Self;
}

impl DevToolsExt for App {
    fn register_dev_tool(&mut self, tool: impl DevTool) -> &mut Self {
        self.world.get_resource_or_something::<DevTools>().0.push(Box::new(tool));
        self
    }
}
pablo-lua commented 5 months ago

What if dev tools were stored in a Resource

That was what I was thinking. But first, we would probably need a TypeIdMap. I'm thinking in something like the Multiple gizmos config (see #10342).

matiqo15 commented 5 months ago

I was thinking of something similar to diagnostics:

#[derive(Hash, Eq, PartialEq)
pub struct DevToolId(pub Uuid);

pub struct DevTool {
    pub id: DevToolId,
    pub is_enabled: bool,
    // ...
}

#[derive(Resource, Default)]
pub struct DevToolsStore {
    pub dev_tools: HashMap<DevtoolId, DevTool>,
}

This should meet all of our requirements. Though with the configuration during runtime it would require something like:

fn tool_system(dev_tools_store: Res<DevToolsStore>) {
    let Some(tool) = dev_tools_store.dev_tools.get(&uuid);
    if !tool.is_enabled {
        return;
    }
    // rest of the system
}
alice-i-cecile commented 5 months ago

I wrote an RFC to better explore this space: https://github.com/bevyengine/rfcs/pull/77