use std::collections::HashMap;
use bevy::{app::ScheduleRunnerPlugin, log::LogPlugin, prelude::*};
use bevy_quinnet::{
server::{
certificate::CertificateRetrievalMode, endpoint::Endpoint, ConnectionLostEvent,
EndpointAddrConfiguration, QuinnetServer, QuinnetServerPlugin, ServerEndpointConfiguration,
},
shared::ClientId,
};
use protocol::{ClientMessage, ServerMessage};
mod protocol;
#[derive(Resource, Debug, Clone, Default)]
struct Users {
names: HashMap<ClientId, String>,
}
fn handle_client_messages(mut server: ResMut<QuinnetServer>, mut users: ResMut<Users>) {
let endpoint = server.endpoint_mut();
for client_id in endpoint.clients() {
while let Some(message) = endpoint.try_receive_message(client_id) {
match message {
ClientMessage::Join { name } => {
if users.names.contains_key(&client_id) {
warn!(
"Received a Join from an already connected client: {}",
client_id
)
} else {
info!("{} connected", name);
users.names.insert(client_id, name.clone());
endpoint
.send_message(
client_id,
ServerMessage::InitClient {
client_id: client_id,
usernames: users.names.clone(),
},
)
.unwrap();
endpoint
.send_group_message(
users.names.keys(),
ServerMessage::ClientConnected {
client_id: client_id,
username: name,
},
)
.unwrap();
}
}
ClientMessage::Disconnect {} => {
endpoint.disconnect_client(client_id).unwrap();
handle_disconnect(endpoint, &mut users, client_id);
}
ClientMessage::ChatMessage { message } => {
info!(
"Chat message | {:?}: {}",
users.names.get(&client_id),
message
);
endpoint.try_send_group_message(
users.names.keys(),
ServerMessage::ChatMessage {
client_id: client_id,
message: message,
},
);
}
}
}
}
}
fn handle_server_events(
mut connection_lost_events: MessageReader<ConnectionLostEvent>,
mut server: ResMut<QuinnetServer>,
mut users: ResMut<Users>,
) {
for client in connection_lost_events.read() {
handle_disconnect(server.endpoint_mut(), &mut users, client.id);
}
}
fn handle_disconnect(endpoint: &mut Endpoint, users: &mut ResMut<Users>, client_id: ClientId) {
if let Some(username) = users.names.remove(&client_id) {
endpoint
.send_group_message(
users.names.keys(),
ServerMessage::ClientDisconnected {
client_id: client_id,
},
)
.unwrap();
info!("{} disconnected", username);
} else {
warn!(
"Received a Disconnect from an unknown or disconnected client: {}",
client_id
)
}
}
fn start_listening(mut server: ResMut<QuinnetServer>) {
server
.start_endpoint(ServerEndpointConfiguration {
addr_config: EndpointAddrConfiguration::from_string("[::]:6000").unwrap(),
cert_mode: CertificateRetrievalMode::GenerateSelfSigned {
server_hostname: "::1".to_owned(),
},
defaultables: Default::default(),
})
.unwrap();
}
fn main() {
App::new()
.add_plugins((
ScheduleRunnerPlugin::default(),
LogPlugin::default(),
QuinnetServerPlugin::default(),
))
.insert_resource(Users::default())
.add_systems(Startup, start_listening)
.add_systems(Update, (handle_client_messages, handle_server_events))
.run();
}