#![warn(missing_docs)]
#![allow(clippy::type_complexity)]
#![doc = include_str!("../readme.md")]
pub mod migration;
#[cfg(debug_assertions)]
use __macros_internal::__HotPatchedSystems as HotPatchedSystems;
use bevy_app::{App, Last, Plugin, PostStartup, PreUpdate};
use bevy_ecs::prelude::*;
pub use bevy_hotpatching_experiments_macros::*;
pub use dioxus_devtools;
#[cfg(debug_assertions)]
use dioxus_devtools::{subsecond::apply_patch, *};
#[cfg(target_arch = "wasm32")]
use web_sys::{
CloseEvent, MessageEvent, WebSocket,
js_sys::JsString,
wasm_bindgen::{JsCast, JsValue, closure::Closure},
window,
};
pub mod hot_patched_app;
pub mod prelude {
pub use super::{
HotPatched, SimpleSubsecondPlugin,
hot_patched_app::{HotPatchedAppExt as _, StartupRerunHotPatch},
};
pub use crate::migration::*;
pub use bevy_hotpatching_experiments_macros::*;
}
#[derive(Debug, Default)]
#[non_exhaustive]
pub struct SimpleSubsecondPlugin;
impl Plugin for SimpleSubsecondPlugin {
fn build(&self, app: &mut App) {
app.configure_sets(
PreUpdate,
(
SimpleSubsecondSystemSet::UpdateFunctionPtrs,
SimpleSubsecondSystemSet::ComponentMigrations,
)
.chain(),
);
#[cfg(not(debug_assertions))]
{
return;
}
#[cfg(debug_assertions)]
{
let (sender, receiver) = crossbeam_channel::bounded::<HotPatched>(1);
#[cfg(not(target_arch = "wasm32"))]
connect(move |msg| {
if let DevserverMsg::HotReload(hot_reload_msg) = msg {
if let Some(jumptable) = hot_reload_msg.jump_table {
unsafe { apply_patch(jumptable).unwrap() };
sender.send(HotPatched).unwrap();
}
}
});
#[cfg(target_arch = "wasm32")]
{
let location = web_sys::window().unwrap().location();
let url = format!(
"{protocol}//{host}/_dioxus?build_id={build_id}",
protocol = match location.protocol().unwrap() {
prot if prot == "https:" => "wss:",
_ => "ws:",
},
host = location.host().unwrap(),
build_id = dioxus_cli_config::build_id(),
);
let ws = WebSocket::new(&url).unwrap();
ws.set_onmessage(Some(
Closure::<dyn FnMut(MessageEvent)>::new(move |e: MessageEvent| {
let Ok(text) = e.data().dyn_into::<JsString>() else {
return;
};
let string: String = text.into();
let string = Box::leak(string.into_boxed_str());
match serde_json::from_str::<DevserverMsg>(string) {
Ok(DevserverMsg::HotReload(hr)) => {
if let Some(jumptable) = hr.jump_table {
unsafe { apply_patch(jumptable).unwrap() };
sender.send(HotPatched).unwrap();
}
}
Ok(_) => {
}
Err(e) => web_sys::console::error_1(
&format!("Error parsing devserver message: {}", e).into(),
),
e => {
web_sys::console::error_1(
&format!("Error parsing devserver message: {:?}", e).into(),
);
}
}
})
.into_js_value()
.as_ref()
.unchecked_ref(),
));
}
app.init_resource::<HotPatchedSystems>();
app.add_message::<HotPatched>().add_systems(
Last,
move |mut events: MessageWriter<HotPatched>| {
if receiver.try_recv().is_ok() {
events.write_default();
}
},
);
app.init_resource::<migration::ComponentMigrations>();
app.add_systems(PostStartup, migration::register_migratable_components)
.add_systems(
PreUpdate,
migration::migrate.in_set(SimpleSubsecondSystemSet::ComponentMigrations),
);
}
}
}
#[derive(Message, Default)]
pub struct HotPatched;
#[derive(SystemSet, Debug, Clone, PartialEq, Eq, Hash)]
pub enum SimpleSubsecondSystemSet {
UpdateFunctionPtrs,
ComponentMigrations,
}
#[doc(hidden)]
pub mod __macros_internal {
pub use bevy_app::PreUpdate;
use bevy_derive::{Deref, DerefMut};
pub use bevy_ecs::{
schedule::Schedules,
system::{IntoSystem, SystemId, SystemState},
world::World,
};
pub use bevy_ecs_macros::Resource;
pub use bevy_log::debug;
use bevy_platform::collections::{HashMap, HashSet};
use dioxus_devtools::subsecond::HotFnPtr;
use std::any::TypeId;
#[derive(Resource, Default)]
pub struct __HotPatchedSystems(pub HashMap<TypeId, __HotPatchedSystem>);
#[doc(hidden)]
pub struct __HotPatchedSystem {
pub current_ptr: HotFnPtr,
pub last_ptr: HotFnPtr,
}
#[doc(hidden)]
#[derive(Deref, DerefMut, Resource, Default, Debug)]
pub struct __ReloadPositions(pub HashSet<(&'static str, u32, u32)>);
}