-
Notifications
You must be signed in to change notification settings - Fork 72
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Allow dart messages to be easily handled as bevy events #349
Conversation
solution: add a bevy feature and use derive macro for event
Hi @Deep-co-de , thanks for the idea :) I'm not sure yet that Bevy, as a game engine, will benefit from being used together with Rinf. Perhaps it's because of my little knowledge about Bevy. Could you elaborate how Rinf will be used in combination with Bevy? Would Rinf be showing the output from Bevy on the screen? I wonder if Bevy doesn't have its own GUI solution. |
Thank you very much for your answer. |
I see. I think this |
rust_crate/src/interface.rs
Outdated
/// This is a mutable cell type that can be shared across threads. | ||
pub type SharedCell<T> = OnceLock<Mutex<RefCell<Option<T>>>>; | ||
|
||
/// This contains a message from Dart. | ||
/// Optionally, a custom binary called `binary` can also be included. | ||
/// This type is generic, and the message | ||
/// can be of any type declared in Protobuf. | ||
/// If the bevy feature is used, every message can be received as an event in bevy. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A small request here, do you mind change the sentence to:
If the bevy
feature is used, every message can be received as an event in Bevy.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I just did it. I hope everything fits.
Please find below a few code snippets: lib.rs mod flutter_events;
...
async fn main() {
let mut app = App::new()
.add_plugins(MinimalPlugins)
// This function is defined like mentioned here: https://github.com/bevyengine/bevy/issues/8983#issuecomment-1623432049
.add_event_channel(SmallText::get_dart_signal_receiver())
.add_systems(Update, handle_smalltext)
// for purpose see below
.add_systems(Update, (
initialize_database_connection
.run_if(in_state(MyAppState::LoadingScreen)),
))
.run()
}
fn receive_smalltext(
mut smalltexts: EventReader<SmallText>
) {
for smalltext in smalltexts.read() {
println!("{}", smalltext.text);
}
} flutter_events.rs ...
#[derive(Resource, Deref, DerefMut)]
struct ChannelReceiver<T>(Mutex<UnboundedReceiver<DartSignal<T>>>);
...
// This method is used to add a dart signa as event for usage in bevy
fn add_event_channel<T: Event>(&mut self, receiver: UnboundedReceiver<DartSignal<T>>) -> &mut Self {
assert!(
!self.world.contains_resource::<ChannelReceiver<T>>(),
"this event channel is already initialized",
);
self.add_event::<T>();
self.insert_resource(ChannelReceiver(Mutex::new(receiver)));
println!("ChannelReceiver added");
self.add_systems(PreUpdate,
channel_to_event::<T>
.after(event_update_system::<T>),
);
self
}
... somewhere in rust: (global state, or even for each page) #[derive(States, Default, Debug, Clone, PartialEq, Eq, Hash)]
enum MyAppState {
LoadingScreen,
#[default]
SimplePage,
SettingsPage,
} main.dart ...
StreamBuilder<GlobalState>(
stream: GlobalState.rustSignalStream,
builder: (BuildContext context, AsyncSnapshot<GlobalState> snapshot) {
if (snapshot.hasData) {
// e.g. GlobalState is a message from rust code
// with field state representing percentage of
// initialized backend procedures
if (snapshot.data.state != 1.0) {
return CircularProgressIndicator(value: snapshot.data.state);
} else {
return Text("Finished Loading");
}
} else {
return CircularProgressIndicator();
}
},
)
... There would be a system in rust that would be loaded at startup, which could then repeatedly increase the value of the CircularprogressIndicator: fn setup_tasks() {
GlobalState{state: 0.1}.send_signal_to_dart();
...
GlobalState{state: 0.2}.send_signal_to_dart();
} I have just realised that if the generated rust code of the messages were not just |
Thanks for the details, I think I now understand how things work(maybe). I did come up with one concern: Rinf spawns its own async multithreaded tokio runtime. It looks like Bevy has its own event loop(or runtime). As a consequence there will be tokio threads from Rinf(which is doing nothing), alongside Bevy threads. Wouldn't this be inefficient? Since each of the thread has to make its stack inside memory. Maybe we can discuss a little further about the combination of tokio system and Bevy system |
I see. I would try one more thing, after looking at the generated code again and the output of |
Yeah, FYI, the codebase will undergo some refactoring for one or more weeks, so I recommend diving in a bit later :) |
All right, thanks for the advice! |
I just wanted to ask how far you've got with refactoring the code? |
The big changes are almost done, but there would be a bit more tweaking about building the tokio runtime and spawning the main function. I would say it will take a week at most :) |
Also, could you add the following information in the |
I now have to make a small adjustment to enable the exit of the app without |
It would look like this:
|
However, you can utilize the shutdown logic of Rinf to properly exit If you take a look at this docs section above, you can understand how to properly run your finalization logic(as well as shutting down the whole tokio runtime before closing the app. ) Also, starting from Rinf 6.13 the default tokio runtime is single-threaded by default, so it wouldn't be too inefficient even if you have a separate 'Bevy world' threads now. |
I have found a solution that does not require any further adjustments. You can find a small example that has not yet been tidied up here: mwp Basically, bevy is in a loop that keeps synchronising with the main thread and is thus also terminated during shutdown, which was not the case before.
I think everything should work this way, I would code a few examples next anyway, but would consider this feature finished. |
Thank you very much for your contribution :) |
You're welcome |
Changes
I have added a feature bevy, and added bevy as an optional dependency for this feature. (I'm not sure if I did everything right in Cargo.toml).
I also added the derive macro optional for DartSignal. This would make it possible to use ecs in rust with bevy as follows and use the events:
With this feature users would still need to manually add these two lines to the generated message files:
I didn't know how to accomplish this automatically with prost-build.
I'm not sure if this option is in your favour at all. I thought it would make these two great projects wonderfully combinable and open up new possibilities.