use std::sync::OnceLock;
use bevy::{prelude::*, tasks::IoTaskPool};
use bevy_egui::egui::Align2;
use bevy_egui::EguiContexts;
use bevy_egui::{egui, EguiClipboard};
use libp2p::{relay, swarm::SwarmEvent, PeerId};
use yoke::Yoke;
use crate::cards::SituationCard;
use crate::player::Player;
use crate::{
menu::{MenuAssets, MenuData},
networking::{BehaviourEvent, NetworkEvent, NetworkManager},
AppState,
};
pub struct RoomsPlugin;
impl Plugin for RoomsPlugin {
fn build(&self, app: &mut App) {
app.add_systems(OnEnter(AppState::Rooms), setup_rooms)
.add_systems(Update, rooms.run_if(in_state(AppState::Rooms)))
.add_systems(OnExit(AppState::Rooms), cleanup_rooms);
}
}
fn cleanup_rooms(mut commands: Commands, menu_data: Res<MenuData>) {
commands
.entity(menu_data.logo_bw_entity)
.despawn_recursive();
commands.remove_resource::<MenuAssets>();
}
#[derive(Resource, Default)]
struct ChatBuffer {
buffer: String,
history: String,
}
pub struct SituationTable {
situation: Yoke<SituationCard<'static>, Vec<u8>>,
players: heapless::Vec<Player, 8>,
}
fn rooms(
mut next_state: ResMut<NextState<AppState>>,
mut text_buffer: ResMut<ChatBuffer>,
net_manager: Res<NetworkManager>,
mut clipboard_ctx: ResMut<EguiClipboard>,
mut contexts: EguiContexts,
) {
egui::Window::new("Chat room")
.anchor(Align2::CENTER_CENTER, egui::Vec2::ZERO)
.movable(false)
.show(contexts.ctx_mut(), |ui| {
egui::ScrollArea::vertical().show(ui, |ui| {
ui.label(&text_buffer.history);
});
ui.text_edit_singleline(&mut text_buffer.buffer);
if ui.button("Send").clicked() {
if text_buffer.buffer.starts_with("/dial") {
let address: PeerId = text_buffer
.buffer
.split(' ')
.nth(1)
.unwrap()
.parse()
.unwrap();
net_manager
.command_sender
.send(crate::networking::NetworkCommand::Dial(address))
.unwrap();
} else {
let mut buffer = String::new();
core::mem::swap(&mut buffer, &mut text_buffer.buffer);
net_manager
.command_sender
.send(crate::networking::NetworkCommand::Publish(
crate::networking::Message::Chat {
content: std::borrow::Cow::Owned(buffer),
},
))
.unwrap();
}
text_buffer.buffer.clear();
}
if ui.button("Copy Peer ID").clicked() {
clipboard_ctx.set_contents(net_manager.peer_id.get().unwrap().as_str());
}
});
if let Ok(event) = net_manager.events.try_recv() {
match event {
NetworkEvent::Event(event) => match event {
SwarmEvent::NewListenAddr { address, .. } => {
tracing::info!(%address, "Listening on address");
}
SwarmEvent::Behaviour(BehaviourEvent::RelayClient(
relay::client::Event::ReservationReqAccepted { .. },
)) => {
tracing::info!("Relay accepted our reservation request");
}
SwarmEvent::Behaviour(BehaviourEvent::RelayClient(event)) => {
tracing::info!(?event)
}
SwarmEvent::Behaviour(BehaviourEvent::Dcutr(event)) => {
tracing::info!(?event)
}
SwarmEvent::Behaviour(BehaviourEvent::Identify(event)) => {
tracing::info!(?event)
}
SwarmEvent::Behaviour(BehaviourEvent::Ping(_)) => {}
SwarmEvent::OutgoingConnectionError { peer_id, error, .. } => {
tracing::info!(peer=?peer_id, "Outgoing connection failed: {error}");
}
_ => {}
},
NetworkEvent::LocalPeerID(id) => {
std::fmt::Write::write_fmt(
&mut text_buffer.history,
format_args!("Peer ID: {}\n", id),
)
.unwrap();
let mut peer_id = String::new();
std::fmt::Write::write_fmt(&mut peer_id, format_args!("{}", id)).unwrap();
net_manager.peer_id.set(peer_id).unwrap();
}
NetworkEvent::Message(p, m) => {
std::fmt::Write::write_fmt(
&mut text_buffer.history,
format_args!("{:#?}\n", (p, m)),
)
.unwrap();
}
}
}
}
fn setup_rooms(mut commands: Commands) {
let task_pool = IoTaskPool::get();
let (command_tx, command_rx) = flume::unbounded::<super::networking::NetworkCommand>();
let (event_tx, event_rx) = flume::unbounded::<super::networking::NetworkEvent>();
task_pool
.spawn(super::networking::open_network(command_rx, event_tx))
.detach();
commands.insert_resource(NetworkManager {
events: event_rx,
command_sender: command_tx,
peer_id: OnceLock::new(),
});
commands.insert_resource(ChatBuffer::default());
}