#Hotpatching Rust code π₯
1 messages Β· Page 2 of 1
i didn't test that all of these signatures actually worked in 0.1.3, but they did compile (potentially with _x: Local<()> added)
i'll lyk if i hit a use case that isn't called from a system
Ideally they all should work, I'll try to wrestle the macro
(Time to hit chat GPT
)
Could I get a minimal definition for these types?
- ConfigRef
- CurrentRef
- Progress
- ScheduleConfigs
- ScheduleSystem
ScheduleConfigs and ScheduleSystem are from bevy, Progress is from iyes_progress and used with my_fn.track_progress() which returns a system, CurrentRef is from pyri_state and it's a newtype holding an Option<Res>, and ConfigRef is from my template and it's a struct containing an Option<Res> and a Res<Assets>
btw how do i get the latest version of dioxus CLI to test DX_LINKER? cargo install --rev?
cargo install --git should already get you main, I believe
Uff, generic params are proving to be quite hard to fix
@worldly ether so, by adding this to my build.rs I get the first build working, adding it to my path does not help, and any further edits when it tries to hot reload run into the same error!
Oh actually we dont need the /Include one
Are you piping the last two?
the second to last i'm calling .track_progress() which pipes internally, the last i'm calling directly wait_in_screen(0.5) which returns a system
OOOh so the last is not a system, but creates a system?
yep
understandable if it's not supported π
maybe a macro on the closure itself?
yeah i could do that and try putting #[hot] on that
That would work, if I knew how to parse macros π
But I can show you how to hotpatch it manually
ah in this particular case it's a closure that returns Progress and i call .track_progress() on that internally lol
so double whammy
fn create_system(input: f32) -> ScheduleConfigs<ScheduleSystem> {
|a, b, c| {
let inner = |some_inputs| { todo!() };
bevy_simple_subsecond_system::dioxus_devtools::subsecond::HotFn::current(inner).call((a, b, c));
}
}
something like that could work
Fixed the generic system btw π
Now return values
the tricky thing there is that I have early returns in the macro
can you do something like Result<ActualReturnValue, ReturnedEarlyFromMacro>?
Not sure how that would work with things like Progress tbh
Hmmm
ofc that could just be an Option
ic
Not sure if I can fix this from a third-party crate 
I'll need to think a bit
For context, the early return is needed when using something like Single, that is supposed to be skipped when not matching
Usually, the scheduler does this for you, but when manually calling it from World::run_system, it just panics by default
So I have to bail out of the system if a fallible param requires skipping the system
interesting. sounds like an upstream bevy issue
Setting rustflags directly has the same behavior
run_system already returns a Result, i'd expect "system skipped due to fallible system param" to be in the error case
I cant figure out how to get the linker to look at my damn paths the second time π
Yeah fair point
But that wouldn't fix our issue either, I believe
I think piped systems are just not supported for the moment :/
This could potentially look better upstream though
@lone token I think both piped systems and fallible systems should already work with your PR, right?
It's just an issue when wrapping them that we get that unfortunate interaction where we have to choose to support either one or the other
i updated to dioxus-cli main (ab76) and moved my /usr/bin/ld-real back to /usr/bin/ld, and then:
dx serve --hot-patchran but failed to hot patch- all of
DX_LINKER=mold,DX_LINKER=/usr/bin/mold,DX_HOST_LINKER=mold, andDX_HOST_LINKER=/usr/bin/moldas prefix failed to run with error:Failed to generate fat binary: mold: fatal: unknown -m argument: 64 DX_LINKER=lldas prefix failed to run with error:Failed to generate fat binary: lld is a generic driver. Invoke ld.lld (Unix), ld64.lld (macOS), lld-link (Windows), wasm-ld (WebAssembly) instead
i previously had my ld binary symlinked to mold and it was working
π€
I think i got it working on windows by forking dioxus and directly overriding the linker flags lmao
Yes!
Though the linking takes 3 seconds instead of 300 ms lmao
Good enough for me to be able to try to add the ability to add new systems though!
Okay wait wait giga brained idea
Can we have rebuilds happen with cfgs? But the original build not have the cfg flag?
I didn't read francois pr earlier in depth I didn't realize it actually directly handled hotpatches
also @mellow flint hot patching worked for modifying the code of an observer that was added to an entity inside a system marked #[hot] :)
the observer function is external to the system function
What we can do is ever better if we can rely on cfgs. We can just cfg app so that way when its rebuilt its actually an entirely different app struct for our rebuild, and then we can read when the main function gets hotpatched and then rerun the main function inside. No need for a macro, no need for these global variables, we can even insert schedule directly and then take it out
Ah heck :/ Could you create a bug report for that?
@worldly ether you'll be interested in this
Yessss! That's lovely! 
i commented on this issue, should i spin that into a separate bug report?
yeah, it's not quite the same bug
thanks π
note that i do have to get the entity to respawn after the hotpatch to pick up the change, just checked
fair enough
I guess you'd have to hotpatch a function from inside the observer to not have to do that
Gonna see if i can add system adding to your crate jan
Because my linker fuckery isn't liked by bevy 0.17 lmao
heck ye
@idle stone I got exclusive systems running when using a single world param π
Not sure how to handle the case where World and Locals are mixed
So I left it for now
I also removed DespawnOnHotPatch in favor of leaving the user to do it manually, because the automatic variant would despawn entities that were outside the hotpatched system, which would be very surprising
@idle stone I just pushed a new release with the new signature support
confirmed working:
- generics
&mut Worldas the only param
confirmed still not working:
- generic plus
&mut Worldas the only param &mut Worldplus more params- return values
i'm down to only 5 //#[hot] commented out now though π
-> Result, where Result is the bevy result, should at least work π
oh, I didn't consider exclusive + generics
let me see if that's easy to fix
Would making T: 'static work for the "World + generics" case?
I mean, it won't compile
But the solution I'm working on has lifetime issues otherwise
Does T: 'static work for you when you remove #[hot], is what I'm asking
Oh wait, if T: Component or something like that, it works
only fn foo<T>(world: &World) where T is completely unbound does not work
That's alright I'd say
Published another update for the generics + exclusive π
probably because trait Component: Send + Sync + 'static
aaah got it
in my case C: Config where Config: Asset where Asset: 'static so i already have the bound
incidentally
hehe
can confirm that my fn foo<C: Config>(world: &mut World) now compiles with #[hot] and triggers a hotpatch when i edit it
yay!
can't confirm that it actually worked because it's a Startup system, but it's probably good
#[hot(rerun_on_hot_patch = true)]
ok let me try that
(will spawn stuff again if you spawn in there though)
can confirm that it reran it. also i'm seeing logs now, is that new?
Hot-patched system ...
not that new π
I yoinked that logging trick from Francois' PR
it seems to be logging for systems that i didn't directly edit, is that expected?
π€·ββοΈ not entirely, but I'm fairly sure my jumptable-keeping is not that clean
i wonder if it should be moved to DEBUG logging
That's fair
well i only say that because it's noisy with the false positives
yeah I think you're right
Oh btw, the logs also tell you if your system reran
yeah i saw that as well. could put it earlier in the message so it's more visible though
Hot-patching and re-running system ...
lovely, thank you. this is already enormous for productivity even with the limitations
especially while working on a real game, it can be painful to edit the code, close and recompile the game, and get back to where you were in the game to see the changes
that can take like 2 minutes per change depending on what you're doing, now down to 5 seconds
I'm happy that it's in a state where you can use it π
Yeah absolutely, and I don't have the time to add fancy live-editing UIs or fiddle around with bevy_inspector_egui to try and get things right
This is also the first time that I've really been able to productively work with bevy_ui beyond clicking around in bevy_inspector_egui and hoping for the best
i actually think inspectors still have a place here, in particular as actual inspectors instead of ad hoc editors
yep, totally
since hot reloading doesn't give you visibility into your entity hierarchy etc unless you add lines to manually print stuff out
But also, being able to hotpatch a little info! call right into my system made me very happy π
don't forget info_once
also i recommend adding dx serve ... as the default task in .vscode/tasks.json
i kept muscle memorying to my keybinding which runs bevy run
Oh yeah good idea, thanks
i think dioxus-cli is inserting this into my Cargo.toml?
[profile.wasm-dev]
inherits = "dev"
opt-level = 1
[profile.server-dev]
inherits = "dev"
[profile.android-dev]
inherits = "dev"
Yeah I saw that too
Oh, so that's where that came from π
dioxus-cli probably has its reasons for it, so i think an option to disable the behavior would be good enough
Does building the CLI from main work for you now, btw?
Better errors now that I can override the linker with DX_LINKER/DX_HOST_LINKER, but now just other issues similar to Malek with kernel32.lib
are you on windows? on linux i wasn't able to use DX_LINKER / DX_HOST_LINKER
Yeah on Windows, and it does work
but i might be doing it wrong
Don't know about Linux tho
I suspect not, since I think the env variable was added to fix the Windows issues haha
interesting, on linux you still have to set up a global symlink from /usr/bin/ld to /usr/bin/mold, so i thought the variable would help with that too c:
yeah I think it was supposed to be a 2 in 1 fix PR π
There are definitely some rough edges to the CLI-side of this experience (no hate btw, it looks amazing)
We're in this together
ITS NOT because its not working its because its not working consistently
I don't understand some intricacies of this hotpatching and I think its biting me
OKAY
YESH
WHAT TBE FUCK
Im gonna record this

it's my turn in a second
we're installing dx on main now right (is it possible to pin to the main branch with cargo install)
edit yes!
So far it's working for 1/4 Windows users, haha
I've got all 3 ready, I'll try Windows first
heck yeah!
π youtube is taking 15 minutes to upload the video, don't hold your breath l
I've since passed
Passed away from holding your breath?
couldn't help myself
still figuring out how to get cmake to work on windows LOL
chocolatey is NOT helping
BTW @mellow flint you may be able to get access to the system that spawned the entity using the track_locations feature
winget install --id=Kitware.CMake -e
oh that's clever
I've since shied a bit away from the idea of auto-reloading Startup and OnEnter systems
(We support an explicit opt-in for it, right now)
If we went the opt-out route, this would certainly be helpful though, thanks
So it's clear the problem I'm having is (for whatever reason) dx just has absolutely no idea where anything is on my machine, despite rustc and cargo having no trouble at all. Like, dx doesn't know where any of my system libraries like kernel32.lib are. If I specify them using $env:LIB, then it seems to not include the directory of the actual build artifact anymore
did fall for the old "Just delete C:\System32" trick? /j
Could you add that to https://github.com/DioxusLabs/dioxus/issues/4150 ?
Problem Steps To Reproduce Steps to reproduce the behavior: Run subsecond Expected behavior The application runs Screenshots https://cdn.discordapp.com/attachments/1374138469420499107/1374176347609...
https://youtu.be/aTUIwHBMbz8
Okay look at this video and tell me im going crazy
phahahaha I love the truckload of UwU and OwOs in your code
this is how I code
But yeah you see the problem!!!!
The hotpatching doesn't hotpatch after the first time!
This isn't a problem with hot reloading systems
Those hot reload an unlimited amount of times
Oh heck I see
that's super weird yeah
At first I thought it was this: https://github.com/DioxusLabs/dioxus/issues/4165
though maybe
wait, let me test something
Okie
π
Doesn't do it with hotfn either
Will he eventually be able to support workspaces?
Unless I misunderstand how hotfn is supposed to be used
Lemme try using it a different way
I think that's part of the roadmap π€
is your code on GH?
No
How did you get a \n without a \r in there? π
I don't know. wandows
Ima try something else
Maybe i need to persistently store the hot fn
NO
Doing this doesnt work either
ah too bad
Yea
The behavior does seem quite puzzling to me 
ez just compress the code and put it in a QR code π
that would actually work with this little code 
But how does Malek get a QR code creator without Wi-Fi?
If only they had a QR code decoder, we could send them the QR code creator as a QR code
Oh hey @trim quest had that
If I had a nickel...
I think it's cuz i wanted to see what would happen if I didn't install lld
pretty sure that needs to take place
According to Jon it doesn't, but I'm skeptical
Right???
Take a look at https://github.com/DioxusLabs/dioxus/issues/4159
You can since one or two hours ago
Update your branch π
As Malek would say:
OwO
One of the issues is that people create plugins ( like the winit plugin ) on the assumption they will only be built once, so I cant just extract out all the systems they add without running into issues
This really sucks
What do you mean by "extract out"?
And means we need a special spot to put systems / plugins that dont rely on that idea
Yeah, this is doomed unfortunately...same issue, not sure really how to fix after trying to run this at the root dir of D:
I think I have a better solution though it doesnt look like pure bevy
I keep reading that path as a smiley
remove_resource::<Schedules>()
Never have I seen such a wild line in Bevy user code
I think your C: drive is much happier than your D: drive
That might be the issue here /j
Could you add a comment saying that this issue also happens when not using CARGO_TARGET_DIR?
Okay so, new idea
Note:
-
EventLoopBuilder::buildwill now panic when theEventLoopis being created more than once.
https://github.com/rust-windowing/winit/blob/47b938dbe78702d521c2c7a43b6f741a3bb8cb0b/src/event_loop.rs#L62
https://github.com/rust-windowing/winit/blob/47b938dbe78702d521c2c7a43b6f741a3bb8cb0b/src/event_loop.rs#L96
I think i can pull it off with a closure where you add the new systems u wanna be hot reloaded inside
( this is also a perfectly fine place to put systems and plugins normally too )
But it has the side effect of, when you add new systems or plugins to the app within that closure, then they get added to your running app
Driving home rn gonna try to implement it when I get there
plugins just need a rework overall anyways
I'm going to bed in a few minutes, so in case everything works out neatly on Linux, here is my ~/.cargo/config.toml for extra speedups that are compatible with subsecond π https://gist.github.com/janhohenheim/5731c11e91736bab5e9ef58c2a982c36
awesome, thanks
also, don't forget to take a look at the Linux instructions for bevy_simple_subsecond_system. You unfortunately have to symlink your machine's ld to mold for it to work π
If you do end up using these, please let me know how much time a hot-patch and/or an incremental rebuild takes for you before and after π
Wrote up some comments here around trying to get dx serve --hot-patch working on Windows 10. Very strange honestly; feels like I'm missing some set of environment variables that everyone else has, but which don't affect cargo
Griffin's still the only one to get it working on Windows AFAIK, so youβre definitely not alone
That's crazy, I wonder what they did to get it working
They only had to deactivate their build target env var, see their issue on Dioxus
But they also ran into a completely different issue than you
mold: warning: symbol type mismatch: rayon_core::registry::Registry::in_worker_cold::LOCK_LATCH::_$u7b$$u7b$constant$u7d$$u7d$::_$u7b$$u7b$closure$u7d$$u7d$::VAL::h6c1a7cebcbb48869
>>> defined in /home/adamime/repo/red-room3d/target/dx/red-room3d/debug/linux/app/stub.o as STT_FUNC
>>> defined in /home/adamime/repo/red-room3d/target/x86_64-unknown-linux-gnu/debug/deps/red_room3d-30d5ca6d8a32b76b.6qf93jwpagnd6pzcx2nklx9e9.rcgu.o as STT_TLS
mold: warning: symbol type mismatch: std::sync::mpmc::waker::current_thread_id::DUMMY::_$u7b$$u7b$constant$u7d$$u7d$::_$u7b$$u7b$closure$u7d$$u7d$::VAL::h40d6ba24d35890da
>>> defined in /home/adamime/repo/red-room3d/target/dx/red-room3d/debug/linux/app/stub.o as STT_FUNC
>>> defined in /home/adamime/repo/red-room3d/target/x86_64-unknown-linux-gnu/debug/deps/red_room3d-30d5ca6d8a32b76b.c6jiucc0gjo21hfq5zae0jrzw.rcgu.o as STT_TLS
mold: warning: symbol type mismatch: std::sync::mpmc::context::Context::with::CONTEXT::_$u7b$$u7b$constant$u7d$$u7d$::_$u7b$$u7b$closure$u7d$$u7d$::VAL::h34901b78060da703
23:12:30 [dev] Application [linux] exited with error: signal: 8 (SIGFPE) (core dumped)
been trying to figure this one out for a minute. seems like it's still mpmc. noting to myself this is dx@ab76d90 and 0.1.7. May need to reference this issue, but π€. AM me will report
Crap
Realized an issue with what im doing is there will be no way to tell how to remove systems that are removed
Hngggg
Okay
Actually no I can fix this
I'm surprised you haven't run into any thread issues like I have
are you running without default features?
I must be pulling in something that's using channels
Hmm yeah no thread issues
No im just running things as is
elephant in the room here
I feel like @worldly ether should probably think about splitting subsecond into its own repository LOL
i feel its a bit weird to leave all of the subsecond issues on the dixous repo, since they aren't really related to like Rust Web UI
Maybe when they're more stable, but I think it's easier for their team to work on it in a monorepo at the moment
gotcha
does anyone know how I could parse this line?
std::sync::mpmc::waker::current_thread_id::DUMMY::_$u7b$$u7b$constant$u7d$$u7d$::_$u7b$$u7b$closure$u7d$$u7d$::VAL::h40d6ba24d35890da
I can't quite tell what to take away here
I'd like to learn how to fix this
Once you see the $ that indicates you're looking at a mangled name for starters. Looks like a captured value in a closure inside something related to a std channel
I'll see if I can run this without mangling
Mangling will also happen for un-namable things too, like closures
makes sense, and this appears to be an anonymous function
It looks like some code inside a const _:() = { /* ... */ }; block
oh, so this is being spat out from the linker
Is it from the linker?
I believe that's the case
makes sense, I think my knowledge of linking is apparent from that comment π
Oh yeah I just scrolled up to your other messages, yeah it's a linker error
Looks like your code was compiled in two different "ways"
I got it
Lets see if i can make it betterrfr
OwO?
holy fuck
a sick one-liner
that was a bit premature
I have never seen such a horrific error message for what comes after
Ok
I think I've figured it out. it is NOT a one-liner
do not be fooled !
OH MY GOD
I did it
I dont know how a linker works this code is terrible
he's gonna love this
Adding new update systems works
I'll polish it up tomorrow but I think the strategy is good enough to be useful for Jan's crate, it feels too jank for actual integration into bevy, at least not until we make App/World send/sync
for a sec I thought this was wasm
this is nice
keep going and we might get a JIT
It basically is jit bevy with this, we just need the struct migration and then you can develop a whole bevy game without ever leaving hotreload mode π€
You got it working on Windows? A triumph on its own lol
I'm still fighting for my life out here
Ahah I forked the toool
To get it to work
And it doesnt work on francois pr
Lmao
What did you have to change?
Manually added some libs to the linker
Yeah ok, could you send which ones?
I think I added them using the LIB environment variable, but now it can't like the actual build artifacts lol
Not at my PC anymore tonight
But I'll send you in the morning yeah
I just found the ones that were missing and added them until it works lol
Ahh all good, I'm sure I wont have it working by then haha
Haahahaah
Holy hell finally
Turns out ONE of the issues was that link.exe just does not work at all for this, so you need to use rust-lld, but dx doesn't support non-link.exe style calling convention, so for it you need to use lld-link.exe and for rustc you need to use rust-lld.exe and make sure they're the same version otherwise it doesn't work
Also libs need to be added to %LIB%, and you must use cmd, PowerShell just doesn't seem to work at all
congRATs!
Is the hot-patching part also working? π
Still working out exactly what fixed it, but here's some cmd commands that does make a fresh cmd window work:
set DX_LINKER=%USERPROFILE%\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\bin\gcc-ld\lld-link.exe
set DX_HOST_LINKER=%DX_LINKER%
set PATH=%PATH%;%USERPROFILE%\.rustup\toolchains\stable-x86_64-pc-windows-msvc\lib\rustlib\x86_64-pc-windows-msvc\lib
set PATH=%PATH%;%PROGRAMFILES%\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\bin\Hostx64\x64
set LIB=%PROGRAMFILES%\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\ATLMFC\lib\x64
set LIB=%LIB%;%PROGRAMFILES%\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\lib\x64
set LIB=%LIB%;%PROGRAMFILES(x86)%\Windows Kits\NETFXSDK\4.8\lib\um\x64
set LIB=%LIB%;%PROGRAMFILES(x86)%\Windows Kits\10\lib\10.0.26100.0\ucrt\x64
set LIB=%LIB%;%PROGRAMFILES(x86)%\Windows Kits\10\lib\10.0.26100.0\um\x64
Yep! Was able to change the gravity in the n_body_simulation example
Yay!!
If you do, would you consider doing a PR with instructions for the bevy crate?
Hopefully some of these steps can be removed, and others built into dx instead
Woah thatβs crazy!
Does it also work when the system function was not yet written when the program starts? If so, can the new function be hotpatched? What about the functions called by the new function?
Hopefully all steps can be made obsolete upstream π¬
Does that mean it works for you now? π
Itβs on his radar, he wants to move it eventually π
Nice! If you first run the app and then create a new system (as in "write new code in a file") and add it to Update does this new function also get hot-patched? Cos I had some problems with things like that
Super-excited to see all the progress here! At the same time a bit sad I might not be able to use it properly in a while because our project is a big workspace π
What are the current workspace limitations? Is it just being in a workspace, or multiple workspace crates changing at the same time?
Can you try this PR? We are imitating the env the rust sets when doing thin compiles but not during linking, and this PR imitates it for linking as well
I'll give it a try! But I can also help, I've worked out the following batch commands will setup the required environment variables for dx serve --hot-patch to work in a plain cmd window without any other special setup:
set VCToolsVersion=14.44.35207
set WindowsSDKVersion=10.0.26100.0
set VCToolsInstallDir=%PROGRAMFILES%\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\%VCToolsVersion%
set WindowsSdkDir=%PROGRAMFILES(x86)%\Windows Kits\10\
set LIB=%VCToolsInstallDir%\lib\x64
set LIB=%LIB%;%WindowsSdkDir%\lib\%__WIN_SDK_VER%\ucrt\x64
set LIB=%LIB%;%WindowsSdkDir%\lib\%__WIN_SDK_VER%\um\x64
does a regular cargo build work in your prompt?
Note that only LIB needs to be set, but the other variables mirror how x64 native tools works
Yes, I think I have a very typical Windows installation
I seem to remember them saying above that only the top crate hotpatches, but don't quote me on that π
in that case cargo or rustc is setting these variables I believe, unless there's something special with the system link.exe
can you run where link.exe - curious where its coming from for you
So I tried using the MSVC link.exe and it just doesn't work (probably 32bit issues), so I'm using the default linker for both cargo and dx
I had issues with the default windows prompt even running cargo build and I tracked that down to running arm64 windows so I have a weird setup
In the x64 native tools environment:
C:\Program Files\Microsoft Visual Studio\2022\Community\VC\Tools\MSVC\14.44.35207\bin\Hostx64\x64\link.exe
It's otherwise not in my path
sadly emulating x86 windows is just too slow
Ahh that makes sense, I'm on a typical Intel x64 laptop
I need some cloud vms... will probably end up building a little product around it
hmm if it's not in path then rustc is finding it which is good news for the PR I linked
Makes sense. I'll checkout that PR now and see what happens, might take a bit though, dx is a slow build haha
I need to wire up nightly/uploads from branches, then you could dx self-update --branch jk/blah
C'mon, two more dependencies surely
how did you end up with this particular implementation? it doesn't seem like we're actually bridging the tls address. do you have a particular replication case I can try to use to test against?
There are different types of tls in macho
- __thread_vars
- __thread_data
- __thread_bss
And I assume different approaches on lin/win, etc
Seems like your impl just sets the tls values to zero - curious how that doesn't end up segfaulting
also generally (directed towards others) how should we handle TLS in the patched crate?
I updated dsgallups PR to properly reuse the TLS initializer so you can modify this code
thread_local! {
pub static FOO: Cell<f32> = const { Cell::new(1.0) };
}
ball_velocity.x = FOO.get() * 200.0 * ball_velocity.x.signum();
ball_velocity.y = FOO.get() * 200.0 * ball_velocity.y.signum();
and the value of the TLS gets reset on every hotpatch, but I think we dont want TLS to re-run on every patch right, only if it changes?
Ok that PR definitely works a lot better, thanks! I have noticed I need to run cargo clean before dx serve, as it doesn't seem to handle continuing on from existing artifacts. Might be because cargo doesn't actually build or link?
On windows I think the mtime -based hash busting doesn't work if you have the file open. Try adding a blank line to the end of the file and then running again
if you run two cargo builds in succession without changing anything, cargo short circuits and doesn't give us any rustc args the second time. There's a bust_fingerprint method that works on mac/linux but I can't seem to get it working on windows
I have no clue how to solve this properly other than adding some entropy to the env that cargo uses to bust the hash
Actually that might've just been a fluke, it does seem to work as I'd expect now!
yay!
I'll leave a review on the PR
appreciate everyone for testing this thoroughly, it'll be so nice to have this pretty battle tested before releasing
it's scary how many people use windows vs linux/mac, sometimes you forget how big the windows dev community is
Hey thanks for working on it! We're all very excited to have this for the whole Rust ecosystem tbh
I do think it's worth splitting into it's own CLI tool and repo if possible. Probably makes sense to be a cargo-subsecond style of package
Only the tip crate works for now. Notably, this means you're also not allowed to have a lib.rs file in your project
I'm just really happy this wizardry works at all. Even with its current limitations, this is an extreme improvement for iteration π
My phone does not want to play the video, but I assume you've got rendering support working? π
Youβre relying on a patched Bevy, right?
Yep, but I made the patch thinner yesterday, now I am really just adding an event to bevy and updating the runners to call a single method on app after they run
Let me push the patch to my fork
Hmm, if we could somehow get rid of that part, we could use your implementation for people with workspaces π€
Yeah my implementation also supports workspaces
Thought so π
The patch is also not exactly specific to my implementation
It's generic over an idea
I will explain in a second let me push
Huh, I donβt quite understand, sorry π
The diff if you're curious
The basic idea is that plugins can now add a resource to an app that handles reloading and they can emit the event AppReload to ask the runners to reload the app by utilizing that resource
The reload handler has the signature Fn(App) -> App
For a patching system to work in practice it needs to not bring in TLS and global statics like tokio twice, otherwise you get segfaults and panics twice - how does your implementation handle that?
So the runners need to provide the current app and then they will get back a new app that represents the reloaded app
It seems that using Bevy's dynamic linking feature prevents TLS/globals from being recreated, if I understand some of the behavior I encountered correctly
If you add tokio as a direct dependency then itβll be statically linked
That's fair, I can see why a build step to do this via dylibs behind the scenes is appealing
Such a build step isn't really impossible with my implementation
How does subsecond handle that?
Thatβs the patching part of hot-patching. We manually define override symbols using addresses from the running program
Yeah but probably a big ask for users if it doesnβt happen automatically 
Ooh got it π
That's interesting, I might be able to borrow the code for that part from subsecond and handle it within the app's own execution 
So new TODO list for me
- Handle doing something like using
tokio - Deal with
Locals - Give nice error messages when
Resources change
Iβll be honest, after having done the R&D for this for a long time, the only approach that can work in this space with all the complexities is real binary patching
You need to operate in the linker/compiler level to fix the statics and TLS issues
Thanks for the link, looks like a good read π
Take a look at cargo-config2 ! It's maintained by the some person who develops cargo-llvm-cov, cargo-hack, and pin-project, and seems to expose the linker information you want
another good read on patching by liveplusplus - they sell their version of subsecond as a paid product to unreal
https://liveplusplus.tech/downloads/THQ_Nordic_Dev_Summit_2023_Live++_Behind_the_Scenes.pptx
@mellow flint not to nerdsnipe you but I think the patch I linked to earlier can be utilized with subsecond to handle reloading the plugins/detect new systems
But thatβs mostly a guess and I havenβt actually validated it
If that does work then the patch would be useful for either implementations and should have an easier time getting upstreamed
If you wanna work on trying it together feel free to ping me whenever 
Pinging @raven valley, since theyβre doing the system adding stuff π
@raven valley fun demo above^ 
Indeed, on Linux that is
yay!!
oh wow I was super tired when I finished this. I didn't even see that
so I'm not sure...honestly need to audit my project and find out what's pulling in rayon
but I'll see if I can come up with an MRE for some code on the original commit
Thanks for fixing this! (also it makes sense TLS isn't changed every patch imo)
Yes, I dont know but I think so, dunno
Yee
Oo
think I'm gonna start using windows to code for a bit. always been a blindside for me
esp here, definitely want to get this working on this platform
now just to transfer all my keybinds from Zed into VSCode...
My main reason for not working on Windows is that it is about 2-3 times slower at compiling Rust for me
yeah, it's like not even using max cores on my computer either
Same story on GH agents, multi-OS test suites always take ages on the Windows runners :/
keep running into this problem as well...where is my integrated terminal
the heck π
While you're configuring, consider upgrading to PS Core
AKA pwsh.exe
winget install --id Microsoft.PowerShell --source winget
interesting...gonna see if this breaks everything rq
wait how on earth do I differentiate between this and powershell
edit: 7
use pwsh.exe instead of powershell.exe
On my Windows, I personally removed all shortcuts and links to the old preinstalled powershell
nice, yeah it's great. thanks
random dumb idea, but if you run bevy with hotpatching and have an in-engine(future bevy editor?) code editor you could theoretically hot patch from within the app directly. 
huh, that would be quite crazy π You could even hot-patch the code editor you're using to edit code
yep
literally this was the first thing that came to mind. I feel like if this can be pulled off, this could solve a lot of heartache for @opaque mulch
specifically for this work
off-topic: you can improve rust-analyzer's suggestions for hotpatched code by adding
"rust-analyzer.procMacro.ignored": {
"bevy_simple_subsecond_system_macros": [
"hot"
]
}
to your VS Code settings
@idle stone youβll want to use this
I think the way to get RA to work would be to have a fallback, when you can't get the output of the macro to work properly, just output the function as-is
Do you have an example of how to do that?
I imagine it it probably pretty easy
But I'm very much a beginner at proc macros
I'm thinking through how we might want to do things
And I have an idea
Hmm
Not sure
Maybe not actually
Hmm
Okay new idea, yeah, so let's do a StartupReload schedule, which auto-despawns and reruns when hot reloading and edited
For resources we can just have it so when you comment out a resource in the reloadable section it unloads that resource, and when you add it back it loads it again. But if you just edit the resource it doesnt edit it
@mellow flint how far did you get with that entity tracking stuff for systems?
oh interesting π€
What exactly?
Auto-track and despawn entities spawned within startup systems that you reload
Not at all. No clue how to track which systems spawned an entity.
Mkay
I just do the manual version right now:
#[derive(Component)]
struct Setup;
#[hot(rerun_on_hot_patch = true)]
fn setup(previous_setup: Query<Entity, With<Setup>>, mut commands: Commands) {
// Clear all entities that were spawned on `Startup` so that
// hot-patching does not spawn them again
for entity in previous_setup.iter() {
commands.entity(entity).despawn();
}
// Actual UI setup goes here
}
Note that this is not library code, but consumer code
on that topic: There was this merged recently: https://github.com/bevyengine/bevy/pull/19047
Objective
In my own project I was encountering the issue to find out which entities were spawned after applying commands. I began maintaining a vector of all entities with generational information ...
so 0.17/main only, but perhaps useful
Oo
Oh yeah that looks super relevant
Oh, I forgot, Alice also had an idea
track_location could be used right now, maybe
this worked for me, although it does add a tiny white squiggle under the # of the annotation saying hot: proc-macro is explicitly disabled
I think I just managed to implement @quartz whale's suggestion π
Hmm so hot reload messages just give us the line number not the span of the function
Hmm
OH jan
I HAVE AN IDEA

In your macro we could add something at the bottom and the top of the function inside, that we could then map to the top position that the hot reload gives us, and so we could have a mapping from the hot reload line number to a span of the hot reload
GOOD reactions
Then we could despawn anything within that span from the location tracking
( if its in a StartupReload schedule instead of a Startup schedule )
Oh I cant wait till im home im gonna cook so hard my development speed is way faster on Linux with my normal setup
We can do this all without having to mess with bevy internals
And it will still look vaguely like bevy
Oh yeah that could work
MHM!
Pog glad you think so
We could also do the same for when components are added
We can look for where they were added and remove them ( if inside a StartupHotReload instead of Startup scheudle )
Inside my reloadable method from the video
GH action runners are not responding 
I'll just merge, all checks run on my system β’οΈ
We can also do the same thing with resources
Though we might not need to because I also have another idea for resources that covers this
What we do is, because how my reload code works is it makes a new empty App, passes it through, and then u add ur plugins, and systems to it, you could ALSO add your resources to it
( in the plugin build process )
( like how you do)
THEN
We can extract out all the resources from the app, look at their type ids, and store them in a hash set we keep
And we add the resources to the new app, only if they didn't already exist in the hash set
AND
If something is in the hash set that ISNT in the new app
Then we remove it from our actual app and the hash set
So that way you can remove resources from your plugin build in the reloadable section and it works
Alright, version 0.1.8 now should have fully working Rust Analyzer suggestions out of the box without any VS Code settings @idle stone @delicate acorn . Thanks again @quartz whale for the suggestion for how to fix it π
I need to go AFK for half an hour right now, but I'll read through your idea when I come back!
Actually on second thought this is orthogonal to resources added by startup systems so we would need both systems
But yeah!
Okay!
hmm it seems better now but non-trait suggestions seem to still be missing
can you give an example?
transform.tra gives try_apply, try_as_reflect, and try_as_reflect_mut only
where transform: Mut<Transform>
the good suggestions come back when re-adding the rust-analyzer setting (transform_point, translate_around, translation, etc.)
Our solutions might totally be workable together since we have roughly the same signature for how we are handling this
OWO yeah
Did you get a chance to push your code anywhere? 
I did not! I can try to push it somewhere later today
You mean you don't see translation?
cannot reproduce
But I can also just take some pictures lol
yep i only see those 3 suggestions
also i'm doing #[cfg_attr(feature = "native_dev", hot)] if it matters, with rust-analyzer configured to have native_dev enabled
Sweet! Iβm going to work on integration between the two solutions and an initial PR with a few use cases later today
Okie
FYI I've promoted this work for the upcoming jam
@worldly ether do you think you'll do a new alpha release? anything you would want to see in it where we can help?
yes, will be doing a new alpha soon-ish... solved a handful of issues, currently getting the custom linkers wired up. just finished the dynamic linking thing (though that requires updating the subsecond lib, unfortunately, so using it via a new alpha will be best)
would like to get workspace support but will probably need to look at other dioxus-y things first
with bevy dynamic linking my iteration time is 150ms haha
SHEEsh
Thanks a bunch!
workspace support would be π₯ , but yeah from the selfish point of view of Bevy jam it probably can wait, people won't do workspaces for the jam π
Except when @graceful falcon decides to submit a multiplayer game again π
(Still very impressed by that)
well my personal template is a workspace, I'll just change that for this jam π
yeah i changed my lib.rs + src/bin/ to a single main.rs for now
I really hope I can get the hot reloading startup systems + normal systems added to your crate this weekend jan
It will improve the experience EVEN MOAR
Can the Windows people confirm whether the dioxus CLI on main works for them now after https://github.com/DioxusLabs/dioxus/pull/4172 ?
Pinging @raven valley @elder heart
I dont wanna touch my windows setup for it rn im too invested in the aforementioned code
@viral dust did you have to do any setup after this PR to get it working? E.g. setting the linker env var
Understandable, same 
also @lone token I merged your PR so hopefully you can get onto main or a stable commit from main. I had to patch a bunch of stuff in my cargo.toml to get your branch working with my weird PR
[patch.'https://github.com/mockersf/dioxus']
dioxus-cli-config = { path = "../../dioxus/packages/cli-config" }
dioxus-core = { path = "../../dioxus/packages/core" }
dioxus-devtools = { path = "../../dioxus/packages/devtools" }
dioxus-devtools-types = { path = "../../dioxus/packages/devtools-types" }
subsecond = { path = "../../dioxus/packages/subsecond/subsecond" }
subsecond-types = { path = "../../dioxus/packages/subsecond/subsecond-types" }
dioxus-signals = { path = "../../dioxus/packages/signals" }
generational-box = { path = "../../dioxus/packages/generational-box" }
thanks! I'll update my PR to target your main
That would be really really cool
setting linker env isn't enough I imagine since the linker needs to accept the same types of arguments, we need a flavor or we infer the flavor
thanks a bunch π
If anyone can give me a step-by-step of how they got it working on Windows, I can add that to the readme π
For what itβs worth my implementation supports workspaces today and Iβll streamline it before the Jam 
Maybe just make sure to be explicit about TLS and Tokio maybe not working with it
Yeah Iβll be and Iβm already looking into possible workarounds and/or solutions
yup
Hmm I could see it possibly being a path to simplifying the "new component" workflow that the editor will have.
And system ordering.
Smoothing out the code/editor barrier to a nicer experience.
It'd take a lot of work and I'm sure we'd be in UB territory... But I do see the potential.
We got a PR for struct migration: https://github.com/TheBevyFlock/bevy_simple_subsecond_system/pull/11 π
We're on board with merging this, right? Pinging @viral dust and @raven valley who had discussed this before
Thanks for the PR, @amber grotto π
MMM
Lemme look at it
Also I'll have a pr for you not too long that just adds the system adding for update systems
assigned you as the reviewer 
Mmmm actually I wanna get my pr finished before I run out of stram
After I get my thing written I'll look at this pr
Still blocked on https://github.com/DioxusLabs/dioxus/issues/4159
unsure how to work around
need to figure out how to undo some implicit target dir
I re-installed MSVC build tools and the Windows 10 SDK, but I don't think I needed to. Everything else I was able to leave as-is on the newest commit
LMAO WAIT
YOU DONT EVEN NEED TO HOT ANNOTATE THE SYSTEM INSIDE RELOADABLE
Lmaooo
@mellow flint made the pr
Yeye
now I wonder...what if you reload a startup system
it probably does nothing
even if the system is updated...hmm
wait
but state transitions...hmmmmmm
Rn I dont have it do anything, I can add behavior for startup systems
Only 89 loc!
Very happy about that
@worldly ether is it possible for us to get, not only the line number but the span of the reloadable section? Is that possible? If not I think i can do some work arounds but I'm not certain I can get them to work ( compiler intrinsic vs macro shenanigans)
only symbol names, but in theory the dwarf tables give you lots of info
no, that's our macro hot-reload stuff
the subsecond api is just jump table and some addresses of anchors

Nooo my dastardly plans ruined
Okay wait
I have another idea
But thanks jon that was helpful thats all the questions I have for now
@mellow flint https://github.com/DioxusLabs/dioxus/pull/4174
think this should work, worth giving a spin
dynamic linking, custom linkers, global target dir
unsure if mold will work, there's a difference between "compile driver" and "direct linker" and I don't have mold/sold installed to test
I'll try it out in a few mins π
Gave you a preliminary review, need to look at it in detail again.
But the closure API is a really good idea π
@worldly ether does the PR also address this?
ok I figured out how to make my path extremely short...let's see
forgot about this, it did compile finally, now just seeing..
yes!
perfect, it works
with smol path. no linker adjustments or anything. out of the box, on a big project
Okay super big brain I've figured out how to get the span out of the macro
For the hot fn
So we can despawn entities within the startup hot functions
UwU
I haven't done that second part
Okie
Iβm hoping it does
On main or on the linked PR?
As the linked PR is supposed to not require a smol path
but congrats π
mind compiling the CLI once more? π
ok one sec making a few images
Done π
Looks like a solid idea!
I wonder if we could skip the closure by annotating the function that calls app.add_systems as #[hot_plugin] or something
But that does not need to be part of this PR
Like
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(hot_plugin)
.run();
}
#[hot]
fn hot_plugin(app: &mut App) {
app.add_systems(Update, foo);
}
I got this idea since your closure already has nearly exactly the signature of a plugin fn
If we need an AppWrapper instead of an App, the proc macro could just silently give you that type instead of an actual App.
Though that may be very surprising if you do things like fetch resources out of the App. Those would suddenly not be around :/
Eh, just throwing these ideas on the table
@autumn lark could you maybe take a look at this?
It looks right to me, but I'm veeeery untrained in reflection π
This PR breaks it for me :/
With no setup, i.e. no symlinking, no config.toml, I get:
01:39:55 [dev] Failed to generate fat binary: rust-lld: error: /home/hhh/git/bevy_simple_subsecond_system/target/x86_64-unknown-linux-gnu/debug/examples/libfatdependencies-8b8cea20-0c14-54a3-b19a-e2cf23a420d4.a: Archive::chcollect2: error: ld returned 1 exit statusive (terminator characters in archive member "H\215" not the correct "`\n" values for the archive member header for οΏ½Z)
I am on nightly Linux, where I think the default linker is already rust-lld, but I'm not entirely sure
So I edited my ~/.cargo/config.toml to include only this:
[target.x86_64-unknown-linux-gnu]
linker = "clang"
rustflags = ["-C", "link-arg=-fuse-ld=lld"]
Which gives me:
dx serve panicked at packages/cli/src/build/builder.rs:1254:49
called `Result::unwrap()` on an `Err` value: Os { code: 2, kind: NotFound, message: "No such file or directory" }
0: dx::cli::serve::ServeArgs::serve::{{closure}}::{{closure}}
1: std::panicking::rust_panic_with_hook
2: std::panicking::begin_panic_handler::{{closure}}
3: std::sys::backtrace::__rust_end_short_backtrace
4: __rustc::rust_begin_unwind
5: core::panicking::panic_fmt
6: core::result::unwrap_failed
7: dx::build::builder::AppBuilder::open_with_main_exe
8: dx::build::builder::AppBuilder::open::{{closure}}
9: dx::serve::runner::AppServer::open_all::{{closure}}
10: dx::serve::serve_all::{{closure}}
11: dx::main::{{closure}}
12: tokio::runtime::park::CachedParkThread::block_on
13: tokio::runtime::context::runtime::enter_runtime
14: tokio::runtime::runtime::Runtime::block_on
15: dx::main
16: std::sys::backtrace::__rust_begin_short_backtrace
17: std::rt::lang_start::{{closure}}
18: std::rt::lang_start_internal
19: main
20: __libc_start_call_main
21: __libc_start_main_impl
22: _start
___rust_try ___rust_try
same with
[target.x86_64-unknown-linux-gnu]
linker = "rust-lld"
and same with
[target.x86_64-unknown-linux-gnu]
linker = "clang"
rustflags = ["-C", "link-arg=-fuse-ld=mold"]
oh wait, I didn't do cargo clean
let me try again
nvm, same error messages even after a cargo clean
to be fair, I didn't run main before, so these errors might not be new
Let me try that real quick
Yeah the issue is on main. I get this one there as well.
@worldly ether want me to bisect?
Reviewed!
We could also set up a CI step for Linux fairly easily that verifies that dx supports various linker setups
thanks π
is it possible that the #[hot] macro is breaking resource change detection?
I wouldn't think so, since it desugars to a fairly standard exclusive system
But I can check, if you want
@idle stone regarding the Bevy New 2D PR for hot patching
Do you think I should change the plugin to be a noop for Wasm?
At least until we know how to make that work
if it doesn't work on wasm, yes. also for release builds would be nice
like inline_tweak compiles out of release builds
Alright, will do π
then it wouldn't have to be an optional dependency at all and i could just do #[hot] everywhere
(ah yeah, @worldly ether I forgot to ask you: how should one use subsecond for Wasm?)
sounds good!
It is possible for it to break change detection if youβre recreating the systems in any way
I don't think theres a linked PR for the cargo target dir being too long 
@elder heart ^
i guess this would still increase compile times if i compile bevy_simple_subsecond_system and its transitive deps in even if it's internally #[cfg]ing itself out of existence
Yesn't
In theory, yes. In practice, its deps are already all deps of Bevy
what about dioxus-devtools
Oh snap you're right
(why do I always curse like a weird Christian online
)
i think #[cfg]-ing itself out internally is still correct fwiw, better than accidentally breaking builds
Oh shit that's right
so true, first thing I thought, that jan guy's a weird Christian
phahaha
ah I see, I'll have to figure out how to get this branch to compile
compiles out of the box for me 
are you on wandows
Lanux
error[E0425]: cannot find function `dlsym` in crate `libc`
--> packages\subsecond\subsecond\src\lib.rs:699:15
|
699 | libc::dlsym(libc::RTLD_DEFAULT, c"main".as_ptr() as _) as _
| ^^^^^ not found in `libc`
for windows compilation on jk/fix-dyn-link-subsecond
if only bevy_simple_subsecond_system could make all of its deps optional and compile those out of the dep tree in web / release builds as well
but cargo limitations
welp
Yeah I already looked far and wide for a hack for that
Nope, only thing you can do is have a dev or release feature
seems like it's just a windows api diff, could use something else I think. I'll just mention in the pr
i've confirmed that this is the case btw. still not sure what the bug is though :')
To be clear, you've confirmed it's not a hotpatching bug?
i've confirmed this particular instance is not related to hotpatching, because i compiled with hotpatching fully disabled and it still occurs
ok, good to know π
I'll now prepare a release that does not break Wasm
I guess I'll just print a WARNING
It just works. dx serve βplatform web βhotpatch
Well I havenβt tested non Dioxus web setups, if it complains you might have to add Dioxus to your dependency list even if you donβt use it
I think connect does not have the same signature on wasm or something like that
let me confirm
Oh you canβt use connect on web
This our web code for the devtools socket on web
https://github.com/DioxusLabs/dioxus/blob/main/packages/web/src/devtools.rs
Oh I see, so I should call make_ws instead of connect?
Sad I thought windows had libc. Lemme fix real quick
Also, what does dx serve --platform web provide for me? Does it already create an HTML file with a canvas for me, or do I need to create that myself?
Asking because the Bevy CLI prototype is setup so that bevy run web creates all of that for you so that you just "magically" open localhost:4000 and you see your game π
It creates an html file, the js glue, bindgen, wasmopt, etc, and then the index.html runs fn main
Ah nice π
Any canvas?
No canvas, the root is <div id="main></div>
could hack this with something really simple via websys
good idea
like before app run
if you want, you can use dioxus
use dioxus::prelude::*;
fn main() {
dioxus::launch(|| {
rsx! {
canvas { id: "my-canvas" }
}
});
}
omg forgot LOL, yeah!!
Hmm, it would need to run before some specific plugin
then you get the websocket, patching, etc
yeah that sounds way better actually
Oh that's cool!
Really not sure how the plugin would be able to do that though 
one of the few times your fn plugin(&mut App) won't suffice
Correction: not sure how the SimpleSubsecondPlugin would do that
I'm actually so on board with this, I've got an idea. Will experiment
since you can push stuff into the subsecond handler something like
use dioxus::prelude::*;
fn main() {
dioxus::launch(|| {
use_effect(|| async move {
subsecond::register_handler(|| do_bevy_hotpatch_stuff);
// ... bevy code
});
rsx! {
canvas { id: "my-canvas" }
}
});
}
loved leptos but it's time for dioxus
Bevy calls our integration plugin right now, not the other way around
So I don't think that would work
is there no way to customize where bevy renders on the web?
The defining Component for window entities, storing information about how it should appear and behave.
needs to be a canvas AFAIK
we can target ids
wait, doesn't it also have the ability to make one when canvas isn't present per the docs?
oh wait you're right
Absolutely!
yes, just name the canvas something and then in the effect do bevy stuff
but even so, I think we can still target a specific part of a web page through dioxus before build is called on the default plugin
I'm pretty sure WindowPlugin inserts this at the Plugin::build call
That would mean we'd have to sandwich our plugin in-between
well, we just use those other plugin trait methods there is no before build step
ah heck
yeah I'm gonna work on it rn
thx
effects run after the element is mounted
Give me 5 mins so you don't have a merge conflict π
interesting...yeah I've been so giddy about trying dioxus
we could even do some really cool things with signals/events
lots of goodies recently, inline debugger, sending logs from browser to terminal, hotpatching, interactive tui, etc etc
@mellow flint could theoretically readd the AppExit result in the template, too
@idle stone I think the proc_macro crate does not receive the #[cfg]s 
Inline tweak also does not remove their macro expansions on release?
im gonna go make food, on standby
The library file then does the noops I believe: https://github.com/Uriopass/inline_tweak/blob/master/src/lib.rs
enjoy π
meant for ur merge, haven't looked at what's changed
I think I'm actually a bit stumped at how to noop away the #[hot] macro on release and Wasm 
wrap it
with a #[cfg_attr]
something like
// in your hot macro
#[cfg_attr(any(not(profile = "release), not(target = "wasm")), hot_inner)]
or something idk the exact syntax, copy everything in hot to hot_inner
that too
edit: oh I see, didn't understand. back in 30
it should for #[tweak_fn] hm
maybe the readme is wrong: "In release mode, the tweaking code is disabled and compiled away."
yeah it does, the proc macro generates a derive_tweak! call which is selected by #[cfg]: https://github.com/Uriopass/inline_tweak/blob/master/src/lib.rs
ooh I see
I think I got it π Let me quickly verify
@amber grotto review is done π
@idle stone released v0.1.9 that compiles away on Wasm and on release
@elder heart you can work on it now, my stuff is merged π
idk if it matters at all, prepending things with :: like ::std or ::bevy
dont quite remember why people do that
It prevents someone making a module of the same name and breaking macros
As ::foo will only match an external crate named foo
totally
I don't think it's a big deal in practice, but it's not too painful to do so might as well
this is my one update README.md commit
lmao realized that if you alias a crate in Cargo.toml this would break as well, but that seems universal
Yeah there was a crate that attempted to solve that issue, but it balloons out proc-macro execution time since it needs to parse the Cargo.toml and it's stateful and all sorts of other issues
So I think most people just agree to use the derive macro you need to be "normal", otherwise just implement the trait yourself
and so that's why you can alias something like use external_crate_thing as crate; because there's always a way to get ::crate
makes sense
oh dang if your hotpatch has a compilation error it gets logged, nice
i've just been perfect up til now π
I guess this PR really doesnt go the whole way either. this can fail if the user imports individual bevy crates...re-exporting bevy_ecs in bevy_simple_subsecond_system would probably be more correct
Should I wait with merging?
yeah, I was thinking about half-assing this but should probably go the whole length
give me a sec
Little POC of adding systems at runtime on @raven valley's PR.
@languid sable, you may want to see this π
yuk. I think I can do better but want to know what you think
meaning, the reexports module and importing individual bevy crates as opposed to bevy itself
unsure about the latter
Move that to the ugly __macros_internal module
Other than that, looks fine to me π
FYI
Pah, I refuse to believe you until I see a green checkmark there π /j
lmao no way π
fak gonna take a minute
ok should be fixed now (reexports I mean), and just need to make sure CI is cool. I'm assuming a test would catch if I got an export wrong
hmm why is bevy still in there?
I guess because it's a dev dependency?
π€·ββοΈ
looks good to me either way π
oh, dev deps
i recommend putting default-features = false on every bevy subcrate :)
good rule of thumb for library authors, to avoid enabling unnecessary features
oh what, those have features too? π
TIL
tial
probably good to include...can't see the lock diff though because of the dev dep
// SAFETY: This is not unsafe, but anything using the updated jump table is.
// The table must be built carefully
unsafe { apply_patch(jumptable).unwrap() };
idk why but I find this so funny
Should have hired a carpenter 
Oh I know π
I just stole that line from Francois π
that's such a rare thing to hear...only in policy debate have I heard someone call out a carping critique
does the #[hot] macro break Locals?
thread locals? if that, not anymore
like Local<u32> as a system param
the answer seems to be yes, it works again with //#[hot]. created issue: https://github.com/TheBevyFlock/bevy_simple_subsecond_system/issues/15
yep broken, nice
Making great progress though, good job birbs 
TIL what "carping" is
I meant "carpenter" because those sure know how to build a table carefully π
Fairly sure that's because Locals from SystemStates don't get saved. We'd have to get them as part of your exclusive wrapper function signature
Which should be possible
"just" parse the arguments and look for mentions of Local
And I guess EventReader
I am working on a way for both my implementation and subsecond to rehydrate locals from old ones
And hope the user has no custom query params that use locals π
Oh that'd be neat too
I think we can do one better here with some smol support from bevy_ecs
hmm can you use run_system_cached somehow
i'm assuming no but idk how this works internally
I ran into some issue with it, but I don't remember what it was
Maybe that was a mistake on my part tho
(wasn't supposed to be a reply whoops)
saving system state is somewhat relevant, it's the difference between run_system_once and run_system_cached
so required for local, eventreader, and any system param wrapping one of those to function, plus things like Query want to save their system state to avoid re-computation every frame
This here:
use bevy::prelude::*;
use bevy_simple_subsecond_system::prelude::*;
fn main() {
App::new()
.add_plugins(DefaultPlugins)
.add_plugins(SimpleSubsecondPlugin::default())
.add_systems(Update, greet)
.run();
}
#[hot]
fn greet() {
info_once!("Hello from a hotpatched system! Try changing this string while the app is running!")
}
gets expanded into:
from pyrious' point: https://docs.rs/bevy_ecs/0.16.0/bevy_ecs/system/struct.SystemState.html#warning
gist?
Ah good idea
@idle stone I think you should be able to understand it
it's mostly noisy namespaces heh
we could wrap the type passed into HotFn::call with a function that will call World::run_system
greet is what is registered in the App, __greet_hotpatched is the function with a stable signature that we hot-patch, __greet_original is the system the user actually wrote
Wouldn't it make more sense to run run_system in __greet_hotpatched?
that is right
well not exactly, because consider the system before hotpatching
because the original will not update either
or will it? goodness...need like 30 to find out
maybe it's 1269
it was like 600 in the end
i was close :)
nvm using world.run_system_cached the way I did just breaks hot-patching
let's try run_system_once
that works
now let's try locals
run_system_once should be basically the same as what you were doing before, it initializes the system every time you call it
https://docs.rs/bevy_ecs/0.16.0/bevy_ecs/world/struct.World.html#method.run_system seems like this comment here also says nay
yep, didn't work
@idle stone I think run_system_cached is working too well π
Eh, I guess it makes sense
From the ECS' point of view, it's a brand new system
or wait
hmm
actually, I don't know how the caching works
run_system_cached registers the system once and saves its SystemId in a resource differentiated by the type id of the system function, basically
so there's one "slot" for a system per function type
hmm I see
@idle stone if you have an idea, here's the relevant code: https://github.com/TheBevyFlock/bevy_simple_subsecond_system/blob/main/macros/src/lib.rs#L157-L161
can you put the SystemState in a Resource?
recreating it only on hotpatch
like in __HotPatchedSystems maybe
the docs for SystemState give an example of that
Uff I need to add the 'static lifetimes to all things in there
also SystemState impls ExclusiveSystemParam
so you could do fn greet(&mut World, SystemState<()>)
That would break when changing signatures at runtime
ah ok
The hack to make that work is to let the hotpatched function have a stable signature
anything in here useful? https://dev-docs.bevyengine.org/bevy_ecs/system/lifetimeless/index.html
potentially π
I could try to use ...::SQuery as Query
i wonder if that would fall apart for custom system params though
still needs a lifetime
wait this is important. are you also implying that the hotpatched function's TypeId is stable
yep
That's why __HotPatchedSystems works
The keys are stable, the values are not
btw i think you have a memory leak since you keep registering new systems
maybe not a proper memory leak because the ecs world still holds a reference to the memory, but effectively
Oh yeah I believe so
that might not be a huge deal since this is a dev tool and it only increases memory usage when you hotpatch
oh wait no
I don't think so
yeah it's only registered one time
ah ok that's a different system you're registering
At least not if you mean this line
yeah
if I can get the TypeId of the hotpatch fn within itself, it's game on
That one should be only registered exactly once per system, as the generated exclusive systems have stable type IDs
Should be easy
yeah π
use std::any::Any as _;
let id = #my_function_name.type_id();
@elder heart I'll let you cook on your solution
wait, I wrote out the macro expansion. so I wrote everything manually. it's hot patching on the hotpatch function changing as well
hmm
not expected
I'd expect it to break. I was not expecting typeid to remain unchanged when the body of the function changes. beautiful
If that does not work, we may be able to work with this, as long as we insert 'static after every &
what is __HotPatchedSystem.system_ptr_update_id used for?
that's the system ID of the system that in PreUpdate updates the subsecond HotFn pointers
For every hotpatched system, we also spawn a second system that updates its entry in __HotPatchedSystems
I think then it just comes down into forcing world to update its the function pointer relationship to SystemId on every call so you can always get that relevant state data
yeah that sounds about right
I used this roundabout way because there is no world.add_systems(PreUpdate, foo)
But I've since learned that you can get Schedules out of World
And that one does have .add_systems
So we could simplify that part now
What if we add a field here to cache the system_id of the function the user changes. if the world has it, then we'll change the referencing entity in place
what do you mean by "referencing entity"?
SystemId doesn't expose its inner Entity field, the thing that holds the actual system reference
but I feel like there's gotta be a way to change this
it does, you can use SystemId::entity() or SystemId::from_entity()


ok