use crate::error::{ClientNotFound, DisconnectReason};
use crate::packet::Payload;
use crate::remote_connection::{ConnectionConfig, NetworkInfo, RenetClient};
use crate::ClientId;
use std::collections::{HashMap, VecDeque};
use std::time::Duration;
use bytes::Bytes;
#[derive(Debug, PartialEq, Eq)]
pub enum ServerEvent {
ClientConnected { client_id: ClientId },
ClientDisconnected { client_id: ClientId, reason: DisconnectReason },
}
#[derive(Debug)]
pub struct RenetServer {
connections: HashMap<ClientId, RenetClient>,
connection_config: ConnectionConfig,
events: VecDeque<ServerEvent>,
}
impl RenetServer {
pub fn new(connection_config: ConnectionConfig) -> Self {
Self {
connections: HashMap::new(),
connection_config,
events: VecDeque::new(),
}
}
pub fn add_connection(&mut self, client_id: ClientId) {
if self.connections.contains_key(&client_id) {
return;
}
let mut connection = RenetClient::new_from_server(self.connection_config.clone());
connection.set_connected();
self.connections.insert(client_id, connection);
self.events.push_back(ServerEvent::ClientConnected { client_id })
}
pub fn get_event(&mut self) -> Option<ServerEvent> {
self.events.pop_front()
}
pub fn has_connections(&self) -> bool {
!self.connections.is_empty()
}
pub fn disconnect_reason(&self, client_id: ClientId) -> Option<DisconnectReason> {
if let Some(connection) = self.connections.get(&client_id) {
return connection.disconnect_reason();
}
None
}
pub fn rtt(&self, client_id: ClientId) -> f64 {
match self.connections.get(&client_id) {
Some(connection) => connection.rtt(),
None => 0.0,
}
}
pub fn packet_loss(&self, client_id: ClientId) -> f64 {
match self.connections.get(&client_id) {
Some(connection) => connection.packet_loss(),
None => 0.0,
}
}
pub fn bytes_sent_per_sec(&self, client_id: ClientId) -> f64 {
match self.connections.get(&client_id) {
Some(connection) => connection.bytes_sent_per_sec(),
None => 0.0,
}
}
pub fn bytes_received_per_sec(&self, client_id: ClientId) -> f64 {
match self.connections.get(&client_id) {
Some(connection) => connection.bytes_received_per_sec(),
None => 0.0,
}
}
pub fn network_info(&self, client_id: ClientId) -> Result<NetworkInfo, ClientNotFound> {
match self.connections.get(&client_id) {
Some(connection) => Ok(connection.network_info()),
None => Err(ClientNotFound),
}
}
pub fn remove_connection(&mut self, client_id: ClientId) {
if let Some(connection) = self.connections.remove(&client_id) {
let reason = connection.disconnect_reason().unwrap_or(DisconnectReason::Transport);
self.events.push_back(ServerEvent::ClientDisconnected { client_id, reason });
}
}
pub fn disconnect(&mut self, client_id: ClientId) {
if let Some(connection) = self.connections.get_mut(&client_id) {
connection.disconnect_with_reason(DisconnectReason::DisconnectedByServer)
}
}
pub fn disconnect_all(&mut self) {
for connection in self.connections.values_mut() {
connection.disconnect_with_reason(DisconnectReason::DisconnectedByServer)
}
}
pub fn broadcast_message<I: Into<u8>, B: Into<Bytes>>(&mut self, channel_id: I, message: B) {
let channel_id = channel_id.into();
let message = message.into();
for connection in self.connections.values_mut() {
connection.send_message(channel_id, message.clone());
}
}
pub fn broadcast_message_except<I: Into<u8>, B: Into<Bytes>>(&mut self, except_id: ClientId, channel_id: I, message: B) {
let channel_id = channel_id.into();
let message = message.into();
for (connection_id, connection) in self.connections.iter_mut() {
if except_id == *connection_id {
continue;
}
connection.send_message(channel_id, message.clone());
}
}
pub fn channel_available_memory<I: Into<u8>>(&self, client_id: ClientId, channel_id: I) -> usize {
match self.connections.get(&client_id) {
Some(connection) => connection.channel_available_memory(channel_id),
None => 0,
}
}
pub fn can_send_message<I: Into<u8>>(&self, client_id: ClientId, channel_id: I, size_bytes: usize) -> bool {
match self.connections.get(&client_id) {
Some(connection) => connection.can_send_message(channel_id, size_bytes),
None => false,
}
}
pub fn send_message<I: Into<u8>, B: Into<Bytes>>(&mut self, client_id: ClientId, channel_id: I, message: B) {
match self.connections.get_mut(&client_id) {
Some(connection) => connection.send_message(channel_id, message),
None => log::error!("Tried to send a message to invalid client {:?}", client_id),
}
}
pub fn receive_message<I: Into<u8>>(&mut self, client_id: ClientId, channel_id: I) -> Option<Bytes> {
if let Some(connection) = self.connections.get_mut(&client_id) {
return connection.receive_message(channel_id);
}
None
}
pub fn clients_id_iter(&self) -> impl Iterator<Item = ClientId> + '_ {
self.connections.iter().filter(|(_, c)| c.is_connected()).map(|(id, _)| *id)
}
pub fn clients_id(&self) -> Vec<ClientId> {
self.clients_id_iter().collect()
}
pub fn disconnections_id_iter(&self) -> impl Iterator<Item = ClientId> + '_ {
self.connections.iter().filter(|(_, c)| c.is_disconnected()).map(|(id, _)| *id)
}
pub fn disconnections_id(&self) -> Vec<ClientId> {
self.disconnections_id_iter().collect()
}
pub fn connected_clients(&self) -> usize {
self.connections.iter().filter(|(_, c)| c.is_connected()).count()
}
pub fn is_connected(&self, client_id: ClientId) -> bool {
if let Some(connection) = self.connections.get(&client_id) {
return connection.is_connected();
}
false
}
pub fn update(&mut self, duration: Duration) {
for connection in self.connections.values_mut() {
connection.update(duration);
}
}
pub fn get_packets_to_send(&mut self, client_id: ClientId) -> Result<Vec<Payload>, ClientNotFound> {
match self.connections.get_mut(&client_id) {
Some(connection) => Ok(connection.get_packets_to_send()),
None => Err(ClientNotFound),
}
}
pub fn process_packet_from(&mut self, payload: &[u8], client_id: ClientId) -> Result<(), ClientNotFound> {
match self.connections.get_mut(&client_id) {
Some(connection) => {
connection.process_packet(payload);
Ok(())
}
None => Err(ClientNotFound),
}
}
pub fn new_local_client(&mut self, client_id: ClientId) -> RenetClient {
let mut client = RenetClient::new_from_server(self.connection_config.clone());
client.set_connected();
self.add_connection(client_id);
client
}
pub fn disconnect_local_client(&mut self, client_id: ClientId, client: &mut RenetClient) {
if client.is_disconnected() {
return;
}
client.disconnect();
if self.connections.remove(&client_id).is_some() {
self.events.push_back(ServerEvent::ClientDisconnected {
client_id,
reason: DisconnectReason::DisconnectedByClient,
});
}
}
pub fn process_local_client(&mut self, client_id: ClientId, client: &mut RenetClient) -> Result<(), ClientNotFound> {
for packet in self.get_packets_to_send(client_id)? {
client.process_packet(&packet);
}
for packet in client.get_packets_to_send() {
self.process_packet_from(&packet, client_id)?
}
Ok(())
}
}