use std::{any::TypeId, collections::HashMap, sync::atomic::AtomicBool};
use bevy::{
ecs::system::{Resource, SystemParam},
prelude::*,
};
use headless_webview::webview::RpcRequest;
use serde::{Deserialize, Serialize};
use crate::{systems, PostUpdateLabel, PreUpdateLabel};
#[derive(Default)]
pub(crate) struct InputEventMapping {
pub events: HashMap<TypeId, &'static str>,
}
#[derive(Default)]
pub(crate) struct OutputEventMapping {
pub events: HashMap<TypeId, &'static str>,
}
pub(crate) struct InputEvent {
pub entity: Entity,
pub request: RpcRequest,
pub matched: AtomicBool,
}
impl InputEvent {
pub fn new(entity: Entity, request: RpcRequest) -> Self {
Self {
matched: AtomicBool::new(false),
entity,
request,
}
}
}
#[derive(Deserialize, Serialize, Debug)]
pub struct WebviewEvent<T> {
pub(crate) entity: Option<Entity>,
pub(crate) val: T,
}
impl<T> WebviewEvent<T> {
pub fn new(entity: Option<Entity>, val: T) -> Self {
Self { entity, val }
}
}
#[derive(SystemParam)]
pub struct WebviewEventReader<'w, 's, T: Resource> {
pub events: EventReader<'w, 's, WebviewEvent<T>>,
}
impl<'w, 's, T: Resource> WebviewEventReader<'w, 's, T> {
pub fn iter(&mut self) -> impl DoubleEndedIterator<Item = &T> {
self.events
.iter_with_id()
.map(|(event, _id)| event)
.map(|event| &event.val)
}
pub fn iter_with_entity(&mut self) -> impl DoubleEndedIterator<Item = (&T, Entity)> {
self.events
.iter_with_id()
.map(|(event, _id)| event)
.map(|event| (&event.val, event.entity.unwrap()))
}
}
#[derive(SystemParam)]
pub struct WebviewEventWriter<'w, 's, T: Resource> {
pub events: EventWriter<'w, 's, WebviewEvent<T>>,
}
impl<'w, 's, T: Resource> WebviewEventWriter<'w, 's, T> {
pub fn send(&mut self, event: T) {
self.events.send(WebviewEvent::new(None, event));
}
pub fn send_to_entity(&mut self, entity: Entity, event: T) {
self.events.send(WebviewEvent::new(Some(entity), event));
}
}
pub trait WebviewApp {
fn add_webview_input_event<T>(&mut self, method: &'static str) -> &mut Self
where
T: Resource + for<'de> serde::Deserialize<'de>;
fn add_webview_output_event<T>(&mut self, method: &'static str) -> &mut Self
where
T: Resource + for<'de> serde::Serialize;
}
impl WebviewApp for App {
fn add_webview_input_event<T>(&mut self, method: &'static str) -> &mut Self
where
T: Resource + for<'de> serde::Deserialize<'de>,
{
let mut rpc_input_events = self
.world
.get_resource_mut::<InputEventMapping>()
.expect("Add `WebviewPlugin` before calling `.add_webview_input_event`");
rpc_input_events.events.insert(TypeId::of::<T>(), method);
self.add_event::<WebviewEvent<T>>();
self.add_system_to_stage(
CoreStage::PreUpdate,
systems::rpc_event_receiver::<T>.after(PreUpdateLabel::Pre),
);
self
}
fn add_webview_output_event<T>(&mut self, method: &'static str) -> &mut Self
where
T: Resource + for<'de> serde::Serialize,
{
let mut rpc_output_events = self
.world
.get_resource_mut::<OutputEventMapping>()
.expect("Add `WebviewPlugin` before calling `.add_webview_input_event`");
rpc_output_events.events.insert(TypeId::of::<T>(), method);
self.add_event::<WebviewEvent<T>>();
self.add_system_to_stage(
CoreStage::PostUpdate,
systems::rpc_event_sender::<T>.label(PostUpdateLabel::Pre),
);
self
}
}
#[derive(Deserialize, Debug)]
#[serde(rename_all(deserialize = "lowercase"))]
pub(crate) enum BuiltinWebviewEvent {
Despawn,
Initialize,
}