# Dexterous Developer
![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/lee-orr/dexterous_developer/.github%2Fworkflows%2Ftests.yml?label=Tests)
![GitHub Workflow Status (with event)](https://img.shields.io/github/actions/workflow/status/lee-orr/dexterous_developer/.github%2Fworkflows%2Fstatic-analysis.yml?label=Static%20Analysis)
![crates.io](https://img.shields.io/crates/v/dexterous_developer?label=dexterous_developer) ![cli](https://img.shields.io/crates/v/dexterous_developer_cli?label=dexterous_developer_cli)
A modular hot-reload system for Rust.
Docs for the latest release are available at:
You can also find [docs for the latest pre-release](https://lee-orr.github.io/dexterous_developer/pre) and [docs for the main branch](https://lee-orr.github.io/dexterous_developer/main)
## Features
- A CLI for building & running reloadable rust projects, including over the network (cross-device)
- Works directly with Binary crates!
- The ability to serialize/deserialize elements, allowing the evolution of schemas over time
- Only includes any hot reload capacity in your build when you explicitly enable it - such as by using the CLI launcher
- The capacity to create adapters for additional frameworks, allowing you to use Dexterous Developer tooling with other tools.
- Includes a first-party Bevy adapter
- Works on Windows, Linux, and MacOS
- On Linux, can be used to develop within a dev container while running on the main OS, enabling use of dev containers for games & other GUI apps.
### Bevy Specific
- Define the reloadable areas of your game explicitly - which can include systems, components, events and resources (w/ some limitations)
- Reset resources to a default or pre-determined value upon reload
- Serialize/deserialize your reloadable resources & components, allowing you to evolve their schemas so long as they are compatible with the de-serializer (using rmp_serde)
- Mark entities to get removed on hot reload
- Run systems after hot-reload
- Create functions to set up & tear down upon either entering/exiting a state or on hot reload
### Future Work
- Cross-platform hot reload - run a "hot reload server" on a development environment, and execute the application on a different OS
- Mobile support
- Browser-based WASM support
- WASI support
- Patching running libraries with intermediate compilation results
- Supporting the use of inter-process communication in addition to the current dynamic-library approach
- GUI-based launchers should be added, especially for mobile
- Supporting ECS hooks and observers in bevy
## Installation
Install the CLI by running: ```cargo install dexterous_developer_cli```. This installs 2 command line utilities:
- `dexterous_developer_cli` - used to build the project, potentially running it at the same time
- `dexterous_developer_runner` - used to run the project on another device
## Setup
You'll also need to add the appropriate dexterous developer adapter to your library's dependencies, and set up the "hot" feature. For example, if you are using bevy:
```toml
[features]
hot = ["dexterous_developer/hot"]
[dependencies]
bevy = "0.14"
dexterous_developer = { version = "0.4.0-pre.0", features = ["bevy"] }
serde = "1" # If you want the serialization capacities
```
Finally, you'll need to set up a `Dexterous.toml` file, that helps define some of the necessary elements - such as which folders should be watched for changes, and what features should be enabled. See the [example file in this repository](./Dexterous.toml) or the [book](https://lee-orr.github.io/dexterous_developer/) for more info.
### Bevy Setup
In your `main.rs`, your main function should become:
```rust
reloadable_main!((initial_plugins) {
App::new()
.add_plugins(initial_plugins.initialize::()) // You can use either DefaultPlugins or MinimnalPlugins here, and use "set" on this as you would with them
// Here you can do what you'd normally do with app
// ... and so on
});
```
If you have a plugin where you want to add reloadable elements, add the following in the file defining the plugin:
```rust
impl Plugin for MyPlugin {
fn build(&self, app: &mut App) {
app
.setup_reloadable_elements::();
}
}
reloadable_scope!(reloadable(app) {
app
.add_systems(Update, this_system_will_reload);
})
```
The [Simple Visual](./adapters/bevy_dexterous_developer/examples/simple_visual.rs) example shows the basic use of the library, and the [book](https://lee-orr.github.io/dexterous_developer/) has more info as well.
## Running with Hot Reload
To run a hot-reloaded app locally, cargo install and run `dexterous_developer_cli` (optionally passing in a specific package or example).
To run the app on a different machine (with the same platform), cargo install `dexterous_developer_cli` on both machines, and then:
- run the `dexterous_developer_cli --serve-only` on the development machine
- run the `dexterous_developer_runner --server http://*.*.*.*:4321` command, ideally in a dedicated directory, on the target machine
## Running or Building Without Hot Reload
To build or run the non-hot-reloadable version of your app, just remember to avoid including the `hot` feature, since it's designed to work only inside a reloadable library!.
## Inspiration
Initial inspiration came from [DGriffin91's Ridiculous bevy hot reloading](https://github.com/DGriffin91/ridiculous_bevy_hot_reloading)
## Bevy Version Support
| Bevy | Dexterous Developer |
| --- |--------------------|
| 0.14 | >= 0.3 |
| 0.13 | = 0.2 |
| 0.12 | 0.0.12, 0.1 |
| 0.11 | <= 0.0.11 |