Bevy Tool #6026
Replies: 7 comments 6 replies
-
For cross-linking: previously discussed in #436. |
Beta Was this translation helpful? Give feedback.
-
Another idea: [config]
theme = "Dark"
undo_limit = 128
[plugins]
something = {
version = "0.3",
config = { # just to show the relationship
key = "value"
}
} This also means that plugins could have default configs instead of just options that evaluate to a default value when |
Beta Was this translation helpful? Give feedback.
-
In regards to codegen, I've made a small poc on this with bevy_cursed_editor which is similar to what you explained in some ways, though it generates the entire codebase from scratch. Might be useful for testing stuff out :) |
Beta Was this translation helpful? Give feedback.
-
Codegen will be a problem in the future. Right now, the scheduling of a plugin is completely self-contained. This however creates a problem that reduce plugin composability (See #2160). The issue will be solved by the upcoming stageless schedule, but as a result, the plugin is not scheduled by itself, but by user code. And that user code may vary depending on what other plugins are present. |
Beta Was this translation helpful? Give feedback.
-
Fleshing out the [editor]
profile = "basic" # set the current editor used
release = true # runs the editor in release mode (see my previous reply about config evaluation time)
[alias] # creates aliases for other bevy commands
node = "editor --name node" # bevy node => bevy editor --name node
[codegen]
jobs = 0 # number of parallel jobs (0 evaluates to number of CPUs)
incremental = true # Writes the output of each installer to separate files before combining
[term]
quiet = false # whether bevy output is quiet
verbose = false # whether bevy provides verbose output
color = 'auto' # whether bevy colorizes output Instead of the tool's source code allowing short versions of commands, there could be default aliases instead (this is the new default file): [editor]
profile = "default"
release = true
[alias]
n = "new"
e = "editor"
a = "add"
r = "remove"
[codegen]
jobs = 0
incremental = true
[term]
quiet = false
verbose = false
color = 'auto' Incremental codegen could work by generating files that have a hash of the config and the corresponding output: b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9
@add_plugin(bevy_thing::ThingPlugin); |
Beta Was this translation helpful? Give feedback.
-
I hadn't read this issue yet, I found the idea very interesting Yes, it's true that a lot of things related to Bevy have to be done manually. Just to make a functional and optimized piece of code, you need to spend a few minutes editing Cargo.toml, adding features and then editing the main rust file. I made bevyinit, which is to minimize all this work in just a few seconds with some available templates and options: https://github.com/nigrodev/bevyinit Currently, the use of cargo-binstall is very helpful for distributing the binary and making it easier to use |
Beta Was this translation helpful? Give feedback.
-
I've written up some initial work scoping for this at https://hackmd.io/@bevy/rk2Qnf5i0/edit |
Beta Was this translation helpful? Give feedback.
-
Summary
The Bevy tool (from here on referred to as "tool") is a CLI/GUI utility for managing projects and editors and their dependencies. This isn't anything official; it's just an idea.
This discussion is meant to explore the pros and cons, possible features and use cases of the tool, and ultimately help decide whether or not to create it. Depending on the feedback, this discussion may be transformed into an RFC. This document is also to help convince the community that a beginner-friendly experience can be created without a traditional editor.
Table of Contents
Motivation
There has been much discussion of an editor and how it would be created (#5043). There are two general visions: an editor library and an editor binary. They have the following general characteristics:
Library Solution
Binary Solution
Personally, I believe that a library solution is the better of the two (after being convinced after having it explained to me by @bjorn3), as it offers a "Rusty" experience, where extensions are just crates, and allows for dogfooding (the editor can just be another Bevy app, extensions are just plugins, etc.). Compare that to a traditional experience, where there is a distinction between extensions and plugins, since extensions have to be loaded in at runtime, and so there will be more work required to set the foundation for such an editor.
But it can't be ignored that a binary solution opens the door to beginners and non-programmers, who could use extensions to work with node editors. By strictly following a library solution, it requires more of users than a binary solution.
Instead of just creating a library, I propose also creating a tool to simplify the creation of editors and projects. It could also be used for quickly adding plugins by generating code from a plugin-provided installer program to be used with the library.
In order to get a better idea of the use-cases for such a tool, how about we explore it's usage by some hypothetical users:
User Experiences
John is an absolute beginner to game development. He has written little to no code and barely touched the command line, and needs something to ease him into it. Unity and Unreal offer a solution for him: GUI installers and node programming editors allow him to start creating a game without knowing how to write code.
What Bevy can do is provide scripts (bat/ps1/sh) or simple binaries to install Rust and install the tool and open it up in its GUI mode. From there, the tool can be used to create desktop shortcuts, create an editor, install a few extensions (including a node editor), and create a new project with some basic plugins. John was able to do this, without writing a single line of code, or typing any commands.
Sally has experience with game development, but not with Rust. She can install Rust, and even write a bit in it, but struggles with the usual stuff, like the borrow checker and lifetimes. She has ideas that she really wants to explore in Bevy, but is held back by her lack of experience in Rust.
However, the Bevy community has graciously provided plugins and extensions that she can install via the tool. Among these is a plethora of scripting plugins for all sorts of languages. Sally didn't really need the tool to do it for her (it's already easy to add plugins in Bevy, so she could have figured it out), but she appreciated the convenience of being able to quickly switch out plugins until she found the ones she likes.
Grant has experience with Rust and Bevy. He may be on a small team of developers making small games. He can do everything the tool does himself, but he still uses the tool for efficiency and organization.
Because the tool organizes his editors, he can start work on new projects without creating a new editor or changing his path to point to a specific editor. The tool also allows him to add plugins really quickly. What this means is that Grant can prototype new ideas in Bevy without writing the boilerplate himself.
May is part of a large team that is in the middle of developing a large game. Her team already has a system created for using Bevy and the editor, which is a workspace member of the project (so as to be included in the project's VCS) and is called via a cargo alias. Her team has no need for the tool, since they are managing their own editor and have all the plugins they need.
From these experiences, we can conclude that the tool makes Bevy more accessible and also makes Bevy users more efficient. It is also optional; the users weren't forced to use it but chose freely. In the case they don't need it or it gets in their way, they can still use Bevy as usual, just like Unity and Unreal. The tool also loses usability as development progresses.
User-facing explanation
The tool is installed via
cargo install bevy
. It can also be installed via a script/binary that can be downloaded from Bevy's website, which also installs Rust if necessary and also opens the tool afterward.The tool's GUI can be opened by calling
bevy
without any arguments. On the first run, the tool will set up the necessary file structure, and if it is the first run in the GUI, it will display options for changing settings and creating desktop and/or start menu shortcuts.The tool also has commands that can be called via CLI (each can be shortened to their first letter):
bevy [n]ew <name> (--editor/-e)
: Creates a new project (or editor)bevy [e]ditor (<name>)
: Opens the current editor (or a named editor)bevy [a]dd <plugin>(@<version>) (--editor/-e <name>)
: Adds a plugin (at latest or given version) to a project (or editor)bevy [r]emove <plugin> (--editor/-e <name>)
: Remove a plugin from a project (or editor)When you create a new project, it creates the following structure in the current directory:
It's like
cargo new --bin
but addsBevy.toml
and modifiesCargo.toml
andsrc/main.rs
. TheBevy.toml
file is where project settings (like plugins) for the tool can be modified. It has the following format:Code generation works by plugins providing installer scripts (See Implementation strategy). These scripts are used to write to a generated file.
src/main.rs
now looks like:include_plugins
calls a macro that includes and parses the generated file. In the case of a new editor,DefaultPlugins
is replaced withEditorPlugins
.In
Cargo.toml
, Bevy is a dependency by default. The version of Bevy used is the one associated with the version of the tool, unless changed in the tools config files.metabuild
is also set to Bevy's metabuild, so the codegen runs whencargo run
orcargo build
is called.include
is also set to includeBevy.toml
, so published crates don't forget it.The config files are
.bevy/config.toml
files. By default, this file is created at~/.bevy/config.toml
, but can be used elsewhere to configure the tool's behavior. The default structure of~/.bevy
looks like:As you can see, the tool automatically creates an editor named "default". By default,
.bevy/config.toml
looks like:By creating your own
.bevy/config.toml
files (or editing this one), you can change the current editor for your path.The need for separate
.bevy/config.toml
andBevy.toml
files arises from how.bevy/config.toml
settings propagate top-down, while only the lowestBevy.toml
are effective.Implementation strategy
This tool can be created later, after an editor library has been implemented. However, it is important that this is an official part of Bevy, rather than as a separate project, since it will work better if plugin creators feel an obligation to provide installer scripts out of a sense of correctness. It would also help to discourage the creation of other codegen tools and their standards if there is something official, which will prevent a possible fracturing of the community (very low risk and not an issue now, but if someone makes such a tool, then it might encourage others).
Installers
An installer script is just a binary target that is part of a crate. It is specified in
Bevy.toml
like so:When the installer runs, it communicates back to the tool via stdin/stdout/stderr IPC. An installer program looks like:
These macros allow plugin creators to define powerful configuration options for users. This installer would then output the following to the generated file:
Then, from the user's program,
App::include_plugins
would call theinclude_plugins!
macro (users could also use the macro directly). So,App::include_plugins
looks like:and evaluates to:
Tool Design
The tool would be another Bevy app, since it can dogfood the UI for the GUI mode. As for the CLI, I believe a system should be upstreamed to Bevy, as the editor could also support a CLI, as well as many Bevy apps and games. I have some ideas for an
Action
system, which could expose commands to CLIs and GUIs. It would also support a history of actions, allowing for undoing/redoing actions, making commands likebevy [u]ndo
possible for quick fixes (as well asbevy e undo
andbevy e redo
for the editor).Code Generation Metabuild
When
cargo run
is called, a metabuild script executes that runs the code generation. The metabuild doesn't actually generate code itself, instead, it calls a command (maybebevy build
?) that can get settings from.bevy/config.toml
andBevy.toml
files in the path. (This is a pretty simple metabuild, so maybebevy new
can just generate a simple build script?)Plugins are downloaded from Crates.io (or some other specified source, like a git repo or a path). Each one is verified to have a correct
Bevy.toml
file. They are then put with the other dependencies (the feasibility of this would need investigating, and maybe the source code can be cached in.bevy/plugins
?). Their installers then run, and the output is written to some file to be referenced by theinclude_plugins!
macro. Any failures cause the entire build to fail.Drawbacks
Any changes require rebuilding the project or editor.
It puts a responsibility on plugin creators to include an installer and document it. However, if an installer doesn't exist for a given plugin, the user can still use it normally:
Rationale and alternatives
The other option that provides a smooth experience for beginners is the traditional editor design with IPC extensions. However, I don't like the idea of extensions being different from plugins; I would rather keep things homogeneous. I don't mind DLLs for that reason (you would just load extensions at startup and add them to the app) but the Rust ABI is unstable, so it isn't feasible. That all being said, IPC extensions can be hot reloaded, so there are benefits, but is that really necessary? It seems that other engines support IPC or DLL extensions so they can run an add-on store (and hide their source code).
Prior Art
Some people might find the idea of code generation foreign and perhaps dangerous. I don't think there is an issue: macros are a huge part of Rust and build systems are common (though some are pretty bad, so it isn't surprising that some might have developed an aversion to all).
Unresolved questions
I still think the code generation could be more hygienic. Maybe the macro could check if the
App
identifier conflicts with any identifiers in the installer and alias it if so? Like:Beta Was this translation helpful? Give feedback.
All reactions