use std::sync::mpsc;
use bevy_app::App;
use bevy_ecs::{schedule::ScheduleLabel, system::NonSend};
use bevy_gizmos::gizmos::Gizmos;
use tracing::{
field::{Field, Visit},
Event, Subscriber,
};
use tracing_subscriber::{layer::Context, Layer};
use crate::gizmo::GizmoCommand;
pub struct GizmoLayer {
sender: mpsc::Sender<GizmoCommand>,
}
impl GizmoLayer {
pub fn new(app: &mut App, schedule: impl ScheduleLabel) -> Self {
let (sender, receiver) = std::sync::mpsc::channel();
app.insert_non_send_resource(GizmoLogEventReceiver(receiver));
app.add_systems(schedule, render_gizmo_log_events);
GizmoLayer { sender }
}
}
impl<S: Subscriber> Layer<S> for GizmoLayer {
fn on_event(&self, event: &Event<'_>, _ctx: Context<'_, S>) {
if let Some(gizmo_command) = extract_gizmo_command(event) {
let _ = self.sender.send(gizmo_command);
}
}
}
struct GizmoVisitor(Option<GizmoCommand>);
impl Visit for GizmoVisitor {
fn record_debug(&mut self, _field: &Field, _value: &dyn std::fmt::Debug) {
}
fn record_str(&mut self, field: &Field, value: &str) {
if field.name() == "gizmo" {
if let Ok(gizmo_command) = ron::de::from_str(value) {
self.0 = Some(gizmo_command);
}
}
}
}
fn extract_gizmo_command(event: &Event<'_>) -> Option<GizmoCommand> {
let mut visitor = GizmoVisitor(None);
event.record(&mut visitor);
visitor.0
}
pub struct GizmoLogEventReceiver(mpsc::Receiver<GizmoCommand>);
pub fn render_gizmo_log_events(receiver: NonSend<GizmoLogEventReceiver>, mut gizmos: Gizmos) {
for gizmo_command in receiver.0.try_iter() {
gizmo_command.draw(&mut gizmos);
}
}