use std::sync::Arc;
use std::sync::atomic::AtomicBool;
use crate::debug_hook::DebugHook;
use crate::ecs::World;
use crate::gfx::animation::AnimationSystem;
use crate::gfx::graphics_system::GraphicsSystem;
use super::state::{AssetHotReloadState, FrameHotReloadEffects, run_frame};
pub(crate) struct HotReloadDriver {
state: Option<AssetHotReloadState>,
notifier: Option<crate::editor::notify::Notifier>,
}
impl HotReloadDriver {
pub(crate) fn new() -> Self {
Self {
state: None,
notifier: None,
}
}
pub(crate) fn with_notifier(mut self, notifier: crate::editor::notify::Notifier) -> Self {
self.notifier = Some(notifier);
self
}
pub(crate) fn pending(&self) -> Option<Arc<AtomicBool>> {
self.state.as_ref().map(|s| Arc::clone(&s.pending))
}
pub(crate) fn arm(
&mut self,
sources: crate::gfx::graphics_system::hot_reload_sources::HotReloadSources,
) {
self.state = Some(AssetHotReloadState::from_sources(sources));
}
pub(crate) fn drive(&mut self, world: &mut World) {
let mut effects = None;
let (systems, mut backend) = concinnity_engine::ecs::systems_and_render_backend(world);
for system in systems {
if let Some(gs) = system.downcast_mut::<GraphicsSystem>() {
if let Some(sources) = gs.take_hot_reload_sources() {
self.arm(sources);
}
if let (Some(state), Some(backend)) = (self.state.as_mut(), backend.take()) {
let mut apply = gs.hot_reload_apply_parts(backend);
effects = Some(run_frame(state, &mut apply, self.notifier.as_ref()));
}
} else if let Some(anim) = system.downcast_mut::<AnimationSystem>() {
crate::anim_reload::reload_clips_if_pending(anim);
}
}
if let Some(effects) = effects {
apply_effects(world, effects);
}
}
}
impl DebugHook for HotReloadDriver {
fn tick(&mut self, world: &mut World) {
self.drive(world);
}
}
pub(crate) fn apply_effects(world: &mut World, effects: FrameHotReloadEffects) {
if !effects.skeleton_updates.is_empty() {
let index_to_new: std::collections::HashMap<usize, crate::gfx::skeleton::Skeleton> =
effects
.skeleton_updates
.into_iter()
.map(|u| (u.skinned_index, u.new_skeleton))
.collect();
let mut applied = 0usize;
for pose in world.query_mut::<crate::components::SkeletonPose>() {
if let Some(new_skel) = index_to_new.get(&pose.skinned_index) {
pose.skeleton = new_skel.clone();
pose.joint_matrices = pose.skeleton.bind_skinning_matrices();
pose.updated = true;
applied += 1;
}
}
tracing::info!(
"asset hot-reload: applied skeleton-shape change to {} SkeletonPose component(s)",
applied
);
}
for story in effects.story_updates {
world
.events_mut::<crate::components::StoryReload>()
.send(crate::components::StoryReload { story });
}
}