#Hotpatching Rust code πŸ”₯

1 messages Β· Page 2 of 1

mellow flint
#

If you want to explicitly manually hot-patch a non-system, I can provide a snippet πŸ™‚

#

Just note that it won’t reload when its signature changes

idle stone
#

i didn't test that all of these signatures actually worked in 0.1.3, but they did compile (potentially with _x: Local<()> added)

idle stone
mellow flint
#

(Time to hit chat GPT bavy )

#

Could I get a minimal definition for these types?

  • ConfigRef
  • CurrentRef
  • Progress
  • ScheduleConfigs
  • ScheduleSystem
idle stone
#

btw how do i get the latest version of dioxus CLI to test DX_LINKER? cargo install --rev?

mellow flint
mellow flint
#

Uff, generic params are proving to be quite hard to fix

raven valley
#

@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

mellow flint
#

Are you piping the last two?

idle stone
mellow flint
idle stone
#

yep

mellow flint
#

Puh, no clue how to support that

#

I should be possible

idle stone
#

understandable if it's not supported πŸ˜„

mellow flint
#

But not sure how

#

Can you declare an fn inside the function body and return that?

idle stone
#

maybe a macro on the closure itself?

#

yeah i could do that and try putting #[hot] on that

mellow flint
#

But I can show you how to hotpatch it manually

idle stone
#

ah in this particular case it's a closure that returns Progress and i call .track_progress() on that internally lol

#

so double whammy

mellow flint
# idle stone maybe a macro on the closure itself?
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

idle stone
#

can you do something like Result<ActualReturnValue, ReturnedEarlyFromMacro>?

mellow flint
#

Not sure how that would work with things like Progress tbh

idle stone
#

ofc that could just be an Option

mellow flint
#

Then you can't pipe

#

Because suddenly, the function has another signature

idle stone
#

ic

mellow flint
#

Not sure if I can fix this from a third-party crate hmm

#

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

idle stone
#

interesting. sounds like an upstream bevy issue

raven valley
idle stone
#

run_system already returns a Result, i'd expect "system skipped due to fallible system param" to be in the error case

raven valley
#

I cant figure out how to get the linker to look at my damn paths the second time πŸ˜‚

mellow flint
#

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

idle stone
#

i updated to dioxus-cli main (ab76) and moved my /usr/bin/ld-real back to /usr/bin/ld, and then:

  • dx serve --hot-patch ran but failed to hot patch
  • all of DX_LINKER=mold, DX_LINKER=/usr/bin/mold, DX_HOST_LINKER=mold, and DX_HOST_LINKER=/usr/bin/mold as prefix failed to run with error: Failed to generate fat binary: mold: fatal: unknown -m argument: 64
  • DX_LINKER=lld as 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

raven valley
#

🀞

#

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

idle stone
#

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

raven valley
#

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

mellow flint
mellow flint
idle stone
mellow flint
#

thanks πŸ™‚

idle stone
mellow flint
#

I guess you'd have to hotpatch a function from inside the observer to not have to do that

raven valley
#

Gonna see if i can add system adding to your crate jan

#

Because my linker fuckery isn't liked by bevy 0.17 lmao

mellow flint
#

@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

mellow flint
#

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

idle stone
#

i'm down to only 5 //#[hot] commented out now though πŸ˜„

mellow flint
mellow flint
#

let me see if that's easy to fix

mellow flint
#

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

mellow flint
#

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 πŸ™‚

idle stone
mellow flint
idle stone
#

incidentally

mellow flint
#

hehe

idle stone
idle stone
#

can't confirm that it actually worked because it's a Startup system, but it's probably good

mellow flint
idle stone
#

ok let me try that

mellow flint
#

(will spawn stuff again if you spawn in there though)

idle stone
#

can confirm that it reran it. also i'm seeing logs now, is that new?

#

Hot-patched system ...

mellow flint
#

I yoinked that logging trick from Francois' PR

idle stone
#

it seems to be logging for systems that i didn't directly edit, is that expected?

mellow flint
idle stone
#

i wonder if it should be moved to DEBUG logging

mellow flint
#

That's fair

idle stone
#

well i only say that because it's noisy with the false positives

mellow flint
#

Oh btw, the logs also tell you if your system reran

idle stone
#

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 ...

mellow flint
#

good idea

#

@idle stone done, use 0.1.7 πŸ™‚

idle stone
#

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

mellow flint
mellow flint
mellow flint
idle stone
#

i actually think inspectors still have a place here, in particular as actual inspectors instead of ad hoc editors

idle stone
#

since hot reloading doesn't give you visibility into your entity hierarchy etc unless you add lines to manually print stuff out

mellow flint
#

But also, being able to hotpatch a little info! call right into my system made me very happy πŸ˜„

idle stone
#

don't forget info_once

mellow flint
#

Oh right, I completely forgot about that

#

that's even better

idle stone
#

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

idle stone
#

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"
mellow flint
idle stone
#

dioxus-cli probably has its reasons for it, so i think an option to disable the behavior would be good enough

mellow flint
mellow flint
viral dust
viral dust
idle stone
#

but i might be doing it wrong

viral dust
#

Don't know about Linux tho

#

I suspect not, since I think the env variable was added to fix the Windows issues haha

idle stone
#

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:

mellow flint
viral dust
#

There are definitely some rough edges to the CLI-side of this experience (no hate btw, it looks amazing)

raven valley
#

This isn't working and im losing my mind

#

πŸ˜‚

viral dust
#

We're in this together

raven valley
#

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

mellow flint
raven valley
#

GOTTA upload to YouTube

#

Gonna then link

elder heart
#

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!

mellow flint
elder heart
mellow flint
raven valley
#

πŸ’€ youtube is taking 15 minutes to upload the video, don't hold your breath l

elder heart
#

I've since passed

mellow flint
elder heart
#

still figuring out how to get cmake to work on windows LOL

#

chocolatey is NOT helping

languid sable
#

BTW @mellow flint you may be able to get access to the system that spawned the entity using the track_locations feature

mellow flint
mellow flint
#

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

viral dust
#

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

mellow flint
mellow flint
raven valley
mellow flint
raven valley
#

hehe 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

mellow flint
raven valley
#

!!!!! Right?

#

I am losing it πŸ˜‚

mellow flint
#

that's super weird yeah

#

though maybe

#

wait, let me test something

elder heart
#

ok onto linux

raven valley
mellow flint
elder heart
#

that's crazy

#

"u didnt uppercase"

#

oh nvm it's an \r problem

#

LOL

raven valley
#

Doesn't do it with hotfn either

lyric jetty
#

Will he eventually be able to support workspaces?

raven valley
#

Unless I misunderstand how hotfn is supposed to be used

#

Lemme try using it a different way

mellow flint
mellow flint
raven valley
#

No

mellow flint
elder heart
#

I don't know. wandows

raven valley
#

Ima try something else

#

Maybe i need to persistently store the hot fn

#

NO

#

Doing this doesnt work either

raven valley
#

Well, for the laptop

mellow flint
raven valley
#

Yea

mellow flint
#

The behavior does seem quite puzzling to me hmm

trim quest
#

ez just compress the code and put it in a QR code πŸ™ƒ

mellow flint
#

But how does Malek get a QR code creator without Wi-Fi?

trim quest
#

They have rust! Just write it from scratch

#

How bad could it beℒ️

mellow flint
#

If only they had a QR code decoder, we could send them the QR code creator as a QR code

elder heart
#

we're chillin

#

don't hold your breath

#

wow right as I say that

#

just to spite me

mellow flint
mellow flint
elder heart
#

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

mellow flint
mellow flint
raven valley
#

Wait

#

Jan

#

You cant use &mut world as your system param?

mellow flint
#

Update your branch πŸ™‚

raven valley
#

Ahhh

#

Okay!

raven valley
#

Okay

#

I got adding/removing systems working with lots of caveats

mellow flint
raven valley
#

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

mellow flint
raven valley
#

And means we need a special spot to put systems / plugins that dont rely on that idea

mellow flint
#

Yeah that sounds hard πŸ˜…

raven valley
#

Yeah

elder heart
raven valley
#

I think I have a better solution though it doesnt look like pure bevy

mellow flint
mellow flint
# raven valley

remove_resource::<Schedules>()
Never have I seen such a wild line in Bevy user code

raven valley
mellow flint
#

That might be the issue here /j

mellow flint
elder heart
#

my thumbs up didn't cut it? what ok

#

but after I try out linux

raven valley
#

Okay so, new idea

raven valley
#

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

idle stone
#

plugins just need a rework overall anyways

mellow flint
elder heart
#

awesome, thanks

mellow flint
# elder heart 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 πŸ˜…

mellow flint
viral dust
#

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

mellow flint
viral dust
#

That's crazy, I wonder what they did to get it working

mellow flint
#

But they also ran into a completely different issue than you

elder heart
#
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

raven valley
#

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

elder heart
#

are you running without default features?

#

I must be pulling in something that's using channels

raven valley
#

No im just running things as is

somber lily
#

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

viral dust
somber lily
#

gotcha

elder heart
#

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

viral dust
elder heart
#

I'll see if I can run this without mangling

viral dust
elder heart
#

makes sense, and this appears to be an anonymous function

viral dust
#

It looks like some code inside a const _:() = { /* ... */ }; block

elder heart
#

oh, so this is being spat out from the linker

viral dust
#

Is it from the linker?

elder heart
#

I believe that's the case

#

makes sense, I think my knowledge of linking is apparent from that comment πŸ˜†

viral dust
#

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"

elder heart
raven valley
#

YES

#

YES OKAY

#

THIS IS ACTUALLY GONNA BE PRETTY GOOD

raven valley
#

Lets see if i can make it betterrfr

raven valley
elder heart
#

holy fuck

#

a sick one-liner

#

that was a bit premature

#

I have never seen such a horrific error message for what comes after

elder heart
#

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

raven valley
#

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

elder heart
#

this is nice

#

keep going and we might get a JIT

raven valley
#

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 😀

viral dust
#

I'm still fighting for my life out here

raven valley
#

Ahah I forked the toool

#

To get it to work

#

And it doesnt work on francois pr

#

Lmao

viral dust
raven valley
#

Manually added some libs to the linker

viral dust
#

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

raven valley
#

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

viral dust
#

Ahh all good, I'm sure I wont have it working by then haha

raven valley
#

Haahahaah

viral dust
#

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

mellow flint
#

Is the hot-patching part also working? πŸ™‚

viral dust
#

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
viral dust
mellow flint
viral dust
#

Hopefully some of these steps can be removed, and others built into dx instead

mellow flint
# raven valley Adding new update systems works

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?

mellow flint
mellow flint
mellow flint
amber grotto
# raven valley Adding new update systems works

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

gritty wren
#

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 πŸ˜†

worn spear
#

What are the current workspace limitations? Is it just being in a workspace, or multiple workspace crates changing at the same time?

worldly ether
viral dust
# worldly ether Can you try this PR? We are imitating the env the rust sets when doing thin comp...

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
worldly ether
viral dust
#

Note that only LIB needs to be set, but the other variables mirror how x64 native tools works

viral dust
quartz whale
worldly ether
#

can you run where link.exe - curious where its coming from for you

viral dust
worldly ether
#

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

viral dust
worldly ether
#

sadly emulating x86 windows is just too slow

viral dust
worldly ether
#

I need some cloud vms... will probably end up building a little product around it

worldly ether
viral dust
#

Makes sense. I'll checkout that PR now and see what happens, might take a bit though, dx is a slow build haha

worldly ether
viral dust
worldly ether
# elder heart https://github.com/DioxusLabs/dioxus/pull/4171 goodnight

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?

viral dust
worldly ether
#

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

viral dust
worldly ether
#

yay!

viral dust
#

I'll leave a review on the PR

worldly ether
#

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

viral dust
#

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

mellow flint
mellow flint
granite kraken
#

My implementation is finally above the biggest hurdle

mellow flint
# granite kraken

My phone does not want to play the video, but I assume you've got rendering support working? πŸ™‚

granite kraken
#

Yep rainbowheart

#

And we still have the ability to add/remove systems

mellow flint
granite kraken
#

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

mellow flint
granite kraken
#

Yeah my implementation also supports workspaces

mellow flint
granite kraken
#

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

mellow flint
granite kraken
#

The diff if you're curious

#

The reload handler has the signature Fn(App) -> App

worldly ether
#

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?

granite kraken
#

So the runners need to provide the current app and then they will get back a new app that represents the reloaded app

granite kraken
worldly ether
#

If you add tokio as a direct dependency then it’ll be statically linked

granite kraken
#

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

mellow flint
worldly ether
#

That’s the patching part of hot-patching. We manually define override symbols using addresses from the running program

mellow flint
granite kraken
#

So new TODO list for me

#
  1. Handle doing something like using tokio
  2. Deal with Locals
  3. Give nice error messages when Resources change
worldly ether
#

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

mellow flint
weary vigil
#

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

Lib.rs

Load and resolve Cargo configuration

worldly ether
granite kraken
#

@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 rainbowheart

mellow flint
granite kraken
elder heart
mellow flint
elder heart
#

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

elder heart
#

Thanks for fixing this! (also it makes sense TLS isn't changed every patch imo)

raven valley
elder heart
#

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...

mellow flint
elder heart
mellow flint
#

Same story on GH agents, multi-OS test suites always take ages on the Windows runners :/

elder heart
#

keep running into this problem as well...where is my integrated terminal

mellow flint
#

AKA pwsh.exe

#

winget install --id Microsoft.PowerShell --source winget

elder heart
#

interesting...gonna see if this breaks everything rq

#

wait how on earth do I differentiate between this and powershell
edit: 7

mellow flint
mellow flint
elder heart
#

nice, yeah it's great. thanks

foggy zodiac
#

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. LUL

mellow flint
elder heart
elder heart
mellow flint
#

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

mellow flint
quartz whale
#

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

mellow flint
#

I imagine it it probably pretty easy

#

But I'm very much a beginner at proc macros

raven valley
#

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?

raven valley
#

Auto-track and despawn entities spawned within startup systems that you reload

mellow flint
raven valley
#

Mkay

mellow flint
#

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
}
mellow flint
karmic current
#

so 0.17/main only, but perhaps useful

raven valley
#

Oo

mellow flint
#

Oh, I forgot, Alice also had an idea

#

track_location could be used right now, maybe

idle stone
mellow flint
raven valley
#

Hmm

#

OH jan

#

I HAVE AN IDEA

mellow flint
raven valley
#

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

mellow flint
#

GOOD reactions

raven valley
#

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

raven valley
#

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

mellow flint
raven valley
#

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

mellow flint
#

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 πŸ™‚

mellow flint
raven valley
#

Actually on second thought this is orthogonal to resources added by startup systems so we would need both systems

#

But yeah!

#

Okay!

idle stone
mellow flint
idle stone
#

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.)

granite kraken
raven valley
#

OWO yeah

granite kraken
#

Did you get a chance to push your code anywhere? peeks_FB

raven valley
#

I did not! I can try to push it somewhere later today

mellow flint
#

cannot reproduce

raven valley
#

But I can also just take some pictures lol

idle stone
#

also i'm doing #[cfg_attr(feature = "native_dev", hot)] if it matters, with rust-analyzer configured to have native_dev enabled

granite kraken
raven valley
#

Okie

languid sable
#

FYI I've promoted this work for the upcoming jam

lone token
#

@worldly ether do you think you'll do a new alpha release? anything you would want to see in it where we can help?

worldly ether
# lone token <@183410029624295424> do you think you'll do a new alpha release? anything you w...

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

mellow flint
lone token
#

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 πŸ˜„

mellow flint
#

(Still very impressed by that)

lone token
#

well my personal template is a workspace, I'll just change that for this jam πŸ˜„

idle stone
#

yeah i changed my lib.rs + src/bin/ to a single main.rs for now

raven valley
#

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

mellow flint
#

Pinging @raven valley @elder heart

raven valley
#

I dont wanna touch my windows setup for it rn im too invested in the aforementioned code

mellow flint
#

@viral dust did you have to do any setup after this PR to get it working? E.g. setting the linker env var

worldly ether
#

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" }
lone token
mellow flint
worldly ether
mellow flint
#

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 πŸ™‚

granite kraken
#

For what it’s worth my implementation supports workspaces today and I’ll streamline it before the Jam Thumbs3_ACL

mellow flint
granite kraken
#

Yeah I’ll be and I’m already looking into possible workarounds and/or solutions

karmic current
opaque mulch
mellow flint
mellow flint
#

Thanks for the PR, @amber grotto πŸ™‚

raven valley
#

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

mellow flint
raven valley
#

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

elder heart
#

need to figure out how to undo some implicit target dir

viral dust
raven valley
#

LMAO WAIT

#

YOU DONT EVEN NEED TO HOT ANNOTATE THE SYSTEM INSIDE RELOADABLE

#

Lmaooo

#

@mellow flint made the pr

granite kraken
#

Oh sweet I wanna check this one out

raven valley
#

Yeye

elder heart
#

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

raven valley
#

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)

worldly ether
raven valley
#

Wait

#

The hot reload message gives you the file, line, column, and index right?

worldly ether
#

the subsecond api is just jump table and some addresses of anchors

raven valley
#

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

worldly ether
#

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

mellow flint
mellow flint
mellow flint
elder heart
#

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

raven valley
#

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

worldly ether
mellow flint
#

As the linked PR is supposed to not require a smol path

mellow flint
elder heart
#

didn't notice link

mellow flint
elder heart
#

ok one sec making a few images

mellow flint
#

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

mellow flint
#

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

mellow flint
#

It looks right to me, but I'm veeeery untrained in reflection πŸ˜…

mellow flint
#

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

mellow flint
#

@worldly ether want me to bisect?

mellow flint
#

We could also set up a CI step for Linux fairly easily that verifies that dx supports various linker setups

mellow flint
idle stone
#

is it possible that the #[hot] macro is breaking resource change detection?

mellow flint
idle stone
#

it's probably just a bug in my code

#

ok

mellow flint
#

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

idle stone
#

like inline_tweak compiles out of release builds

mellow flint
idle stone
#

then it wouldn't have to be an optional dependency at all and i could just do #[hot] everywhere

mellow flint
#

(ah yeah, @worldly ether I forgot to ask you: how should one use subsecond for Wasm?)

granite kraken
#

It is possible for it to break change detection if you’re recreating the systems in any way

elder heart
mellow flint
idle stone
mellow flint
#

In theory, yes. In practice, its deps are already all deps of Bevy

idle stone
#

what about dioxus-devtools

mellow flint
#

(why do I always curse like a weird Christian online hmm )

idle stone
#

i think #[cfg]-ing itself out internally is still correct fwiw, better than accidentally breaking builds

mellow flint
#

Oh shit that's right

elder heart
#

so true, first thing I thought, that jan guy's a weird Christian

elder heart
#

ah I see, I'll have to figure out how to get this branch to compile

mellow flint
elder heart
#

are you on wandows

mellow flint
elder heart
#
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

idle stone
#

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

mellow flint
#

Nope, only thing you can do is have a dev or release feature

elder heart
idle stone
mellow flint
idle stone
#

i've confirmed this particular instance is not related to hotpatching, because i compiled with hotpatching fully disabled and it still occurs

mellow flint
#

I'll now prepare a release that does not break Wasm

#

I guess I'll just print a WARNING

worldly ether
#

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

mellow flint
#

let me confirm

worldly ether
#

Oh you can’t use connect on web

mellow flint
worldly ether
mellow flint
worldly ether
mellow flint
#

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 πŸ™‚

worldly ether
worldly ether
#

No canvas, the root is <div id="main></div>

elder heart
mellow flint
elder heart
#

like before app run

worldly ether
#

if you want, you can use dioxus

use dioxus::prelude::*;

fn main() {
    dioxus::launch(|| {
        rsx! {
            canvas { id: "my-canvas" }
        }
    });
}
elder heart
#

omg forgot LOL, yeah!!

mellow flint
worldly ether
#

then you get the websocket, patching, etc

elder heart
#

yeah that sounds way better actually

mellow flint
#

Really not sure how the plugin would be able to do that though hmm

elder heart
mellow flint
elder heart
#

I'm actually so on board with this, I've got an idea. Will experiment

worldly ether
#

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" }
        }
    });
}
elder heart
#

loved leptos but it's time for dioxus

mellow flint
#

So I don't think that would work

worldly ether
#

is there no way to customize where bevy renders on the web?

mellow flint
#

needs to be a canvas AFAIK

elder heart
#

wait, doesn't it also have the ability to make one when canvas isn't present per the docs?

mellow flint
#

Absolutely!

worldly ether
#

yes, just name the canvas something and then in the effect do bevy stuff

elder heart
#

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

mellow flint
elder heart
#

well, we just use those other plugin trait methods there is no before build step

mellow flint
#

Fair enough

#

Do you think you could do a PR for something like that?

elder heart
#

yeah I'm gonna work on it rn

mellow flint
worldly ether
#

effects run after the element is mounted

mellow flint
#

Give me 5 mins so you don't have a merge conflict πŸ™‚

worldly ether
#

the canvas will be alive when the bevy code runs

#

we also have onmounted

elder heart
#

interesting...yeah I've been so giddy about trying dioxus

#

we could even do some really cool things with signals/events

worldly ether
elder heart
mellow flint
#

@idle stone I think the proc_macro crate does not receive the #[cfg]s hmm

#

Inline tweak also does not remove their macro expansions on release?

elder heart
#

im gonna go make food, on standby

mellow flint
mellow flint
elder heart
mellow flint
elder heart
#

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

mellow flint
#

Oh wait, I can quote! it!

#

That was the missing piece

elder heart
#

that too
edit: oh I see, didn't understand. back in 30

idle stone
#

maybe the readme is wrong: "In release mode, the tweaking code is disabled and compiled away."

mellow flint
#

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 πŸ™‚

elder heart
#

idk if it matters at all, prepending things with :: like ::std or ::bevy

#

dont quite remember why people do that

viral dust
elder heart
#

ah

#

maybe I should make that pr

viral dust
#

As ::foo will only match an external crate named foo

elder heart
#

totally

viral dust
#

I don't think it's a big deal in practice, but it's not too painful to do so might as well

elder heart
#

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

viral dust
#

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

elder heart
#

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

idle stone
#

oh dang if your hotpatch has a compilation error it gets logged, nice

#

i've just been perfect up til now πŸ’…

elder heart
elder heart
#

give me a sec

mellow flint
elder heart
#

meaning, the reexports module and importing individual bevy crates as opposed to bevy itself

#

unsure about the latter

mellow flint
#

Other than that, looks fine to me πŸ™‚

elder heart
#

oh right

#

gotta fix that up. that's me!

mellow flint
elder heart
#

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

mellow flint
#

hmm why is bevy still in there?

#

I guess because it's a dev dependency?

#

πŸ€·β€β™‚οΈ

#

looks good to me either way πŸ™‚

elder heart
mellow flint
#

@elder heart you missed an underscore πŸ˜‰

#

Merged check_accept

idle stone
#

i recommend putting default-features = false on every bevy subcrate :)

#

good rule of thumb for library authors, to avoid enabling unnecessary features

mellow flint
idle stone
#

some of them do πŸ˜„

elder heart
#

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

mellow flint
elder heart
#

LMAO I'm not criticizing just made me giggle

#

idk how it works

mellow flint
mellow flint
elder heart
#

that's such a rare thing to hear...only in policy debate have I heard someone call out a carping critique

idle stone
#

does the #[hot] macro break Locals?

elder heart
idle stone
#

like Local<u32> as a system param

elder heart
#

yep broken, nice

gentle socket
#

Making great progress though, good job birbs bevy

mellow flint
mellow flint
#

Which should be possible

#

"just" parse the arguments and look for mentions of Local

#

And I guess EventReader

granite kraken
#

I am working on a way for both my implementation and subsecond to rehydrate locals from old ones

mellow flint
#

And hope the user has no custom query params that use locals πŸ‘€

granite kraken
#

I think we can do one better here with some smol support from bevy_ecs

idle stone
#

i'm assuming no but idk how this works internally

mellow flint
mellow flint
#

(wasn't supposed to be a reply whoops)

idle stone
#

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

mellow flint
# idle stone i'm assuming no but idk how this works internally

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:

elder heart
idle stone
#

gist?

mellow flint
#

Ah good idea

mellow flint
#

@idle stone I think you should be able to understand it

idle stone
#

it's mostly noisy namespaces heh

elder heart
#

we could wrap the type passed into HotFn::call with a function that will call World::run_system

mellow flint
#

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

mellow flint
elder heart
#

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

mellow flint
#

Oh wait I think I already have it

#

oookay dx

idle stone
#

maybe it's 1269

mellow flint
idle stone
#

i was close :)

mellow flint
#

let's try run_system_once

#

that works

#

now let's try locals

idle stone
#

run_system_once should be basically the same as what you were doing before, it initializes the system every time you call it

elder heart
mellow flint
#

@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

idle stone
#

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

mellow flint
#

hmm I see

elder heart
#

I might have it one sec

#

or I'm on fire

idle stone
#

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

mellow flint
idle stone
#

also SystemState impls ExclusiveSystemParam

#

so you could do fn greet(&mut World, SystemState<()>)

mellow flint
idle stone
#

ah ok

mellow flint
#

The hack to make that work is to let the hotpatched function have a stable signature

mellow flint
#

I could try to use ...::SQuery as Query

idle stone
#

i wonder if that would fall apart for custom system params though

elder heart
mellow flint
#

That's why __HotPatchedSystems works

#

The keys are stable, the values are not

elder heart
#

because of the registered closure

#

makes sense

idle stone
#

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

idle stone
#

that might not be a huge deal since this is a dev tool and it only increases memory usage when you hotpatch

mellow flint
#

I don't think so

elder heart
#

yeah it's only registered one time

idle stone
#

ah ok that's a different system you're registering

mellow flint
#

At least not if you mean this line

idle stone
#

yeah

elder heart
#

if I can get the TypeId of the hotpatch fn within itself, it's game on

mellow flint
#

That one should be only registered exactly once per system, as the generated exclusive systems have stable type IDs

elder heart
#

that is wild that you can

#

but i guess it is stable

mellow flint
mellow flint
#

@elder heart I'll let you cook on your solution

elder heart
#

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

mellow flint
# mellow flint

If that does not work, we may be able to work with this, as long as we insert 'static after every &

elder heart
mellow flint
#

For every hotpatched system, we also spawn a second system that updates its entry in __HotPatchedSystems

elder heart
#

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

mellow flint
#

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

elder heart
#

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

mellow flint
elder heart
#

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

idle stone