Crates.io | bevy_simple_subsecond_system_macros |
lib.rs | bevy_simple_subsecond_system_macros |
version | 0.1.9 |
created_at | 2025-05-20 00:30:20.315559+00 |
updated_at | 2025-05-25 02:05:09.514457+00 |
description | Macros for bevy_simple_subsecond_system |
homepage | |
repository | https://github.com/janhohenheim/bevy_simple_subsecond_system |
max_upload_size | |
id | 1680587 |
size | 25,930 |
Hotpatch your Bevy systems, allowing you to change their code while the app is running and directly see the results! This is an intermediate solution you can use until Bevy implements this feature upstream.
Powered by Dioxus' subsecond
Please report all hotpatch-related problems to them :)
https://github.com/user-attachments/assets/a44e446b-b2bb-4e10-81c3-3f20cccadea0
First, we need to install a specific version of the Dioxus CLI.
cargo install dioxus-cli --git https://github.com/DioxusLabs/dioxus --rev b2bd1f
Depending on your OS, you'll have to set up your environment a bit more:
If you're lucky, you don't need to change anything.
However, some users may experience issues with their path length.
If that happens, move your crate closer to your drive, e.g. C:\my_crate
.
If that is not enough, set the following in your ~\.cargo\config.toml
:
[profile.dev]
codegen-units = 1
Note that this may increase compile times significantly if your crate is very large.
When changing this number, always run cargo clean
before rebuilding.
If you can verify that this solved your issue,
try increasing this number until you find a happy middle ground. For reference, the default number
for incremental builds is 256
, and for non-incremental builds 16
.
You also cannot set linker = "rust-lld.exe"
, as subsecond currently crashes when linker
is set.
You're in luck! Everything should work out of the box if you use the default system linker.
Execute the following:
readlink -f "$(which cc)"
If this points to clang
, you're good. Otherwise, we'll need to symlink it.
Read the path returned by the following command:
which cc
and cd
into it. For example,
$ which cc
/usr/bin/cc
$ cd /usr/bin
Assuming you have clang
installed, run the following commands:
mv cc cc-real
ln -s "$(which clang)" cc
Note that the above commands may require sudo
.
Now everything should work. If not, install lld
on your system and add the following to your ~/.cargo/config.toml
:
[target.x86_64-unknown-linux-gnu]
rustflags = [
"-Clink-arg=-fuse-ld=lld",
]
If you prefer to use mold
, you can set it up like this:
[target.x86_64-unknown-linux-gnu]
#linker = clang
rustflags = [
"-Clink-arg=-fuse-ld=mold",
]
Note that the linker
key needs to be commented out.
You will also need to replace your system ld
with mold
.
cd /usr/bin
sudo mv ld ld-real
sudo ln -s mold ld
On NixOS you can do this in a shell by replacing:
pkgs.mkShell {
# ..
}
with:
pkgs.mkShell.override {
stdenv = pkgs.stdenvAdapters.useMoldLinker pkgs.clangStdenv;
} {
# ..
}
Add the crate to your dependencies:
cargo add bevy_simple_subsecond_system
Then add the plugin to your app and annotate any system you want with #[hot]
:
use bevy::prelude::*;
use bevy_simple_subsecond_system::prelude::*;
fn main() -> AppExit {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(SimpleSubsecondPlugin::default())
.add_systems(Update, greet)
.run()
}
#[hot]
fn greet(time: Res<Time>) {
info_once!(
"Hello from a hotpatched system! Try changing this string while the app is running! Patched at t = {} s",
time.elapsed_secs()
);
}
Now run your app with
dx serve --hot-patch
Now try changing that string at runtime and then check your logs!
Note that changing the greet
function's signature at runtime by e.g. adding a new parameter will still require a restart.
In general, you can only change the code inside the function at runtime. See the Advanced Usage section for more.
Run the examples with
dx serve --hot-patch --example name_of_the_example
e.g.
dx serve --hot-patch --example patch_on_update
In general, rust analyzer for VS Code will play nice with the #[hot]
attribute.
If you're running into issues, you can add the following to your VS Code settings:
"rust-analyzer.procMacro.ignored": {
"bevy_simple_subsecond_system_macros": [
"hot"
]
},
"rust-analyzer.diagnostics.disabled": [
"proc-macro-disabled"
]
lspconfig.rust_analyzer.setup({
capabilities = capabilities,
settings = {
["rust-analyzer"] = {
procMacro = {
ignored = {
bevy_simple_subsecond_system_macros = { "hot" },
},
},
diagnostics = {
disabled = { "proc-macro-disabled" },
},
},
},
})
There are some more things you can hot-patch, but they come with extra caveats right now
#[hot(rerun_on_hot_patch)]
or #[hot(hot_patch_signature)]
on a system that uses any of the following:
EventReader
Local
Added
, Changed
, or Spawned
#[hot(rerun_on_hot_patch)]
or #[hot(hot_patch_signature)]
commented out to indicate thisHotPatchMigrate
), changing definitions of the types used as fields of the components isn't supported. It might work in some cases but most probably will be an undefined behaviourUI is often spawned in Startup
or OnEnter
schedules. Hot-patching such setup systems would be fairly useless, as they wouldn't run again.
For this reason, the plugin supports automatically rerunning systems that have been hot-patched. To opt-in, replace #[hot]
with #[hot(rerun_on_hot_patch = true)]
.
See the rerun_setup
example for detailed instructions.
Replace #[hot]
with #[hot(hot_patch_signature = true)]
to allow changing a system's signature at runtime.
This allows you to e.g. add additional Query
or Res
parameters or modify existing ones.
#[hot]
attribute#[hot]
attribute does simply nothing on such builds.World
yet.
Resource
s and Component
s of your system at runtimelib.rs
or a workspace setup.bevy_mod_debugdump
still work? Maybe. Let me know!A
that calls a function B
,
changing B
will only work at runtime if that function existed already when the app was launched.bevy | bevy_simple_subsecond_system |
---|---|
0.16 | 0.2 |