renet_netcode/
server.rs

1use std::{
2    io,
3    net::{SocketAddr, UdpSocket},
4    time::Duration,
5};
6
7use renetcode::{NetcodeServer, ServerConfig, ServerResult, NETCODE_MAX_PACKET_BYTES, NETCODE_USER_DATA_BYTES};
8
9use renet::ClientId;
10use renet::RenetServer;
11
12use super::NetcodeTransportError;
13
14#[derive(Debug)]
15pub struct NetcodeServerTransport {
16    socket: UdpSocket,
17    netcode_server: NetcodeServer,
18    buffer: [u8; NETCODE_MAX_PACKET_BYTES],
19}
20
21impl NetcodeServerTransport {
22    pub fn new(server_config: ServerConfig, socket: UdpSocket) -> Result<Self, std::io::Error> {
23        socket.set_nonblocking(true)?;
24
25        let netcode_server = NetcodeServer::new(server_config);
26
27        Ok(Self {
28            socket,
29            netcode_server,
30            buffer: [0; NETCODE_MAX_PACKET_BYTES],
31        })
32    }
33
34    /// Returns the server public address
35    pub fn addresses(&self) -> Vec<SocketAddr> {
36        self.netcode_server.addresses()
37    }
38
39    /// Returns the maximum number of clients that can be connected.
40    pub fn max_clients(&self) -> usize {
41        self.netcode_server.max_clients()
42    }
43
44    /// Update the maximum numbers of clients that can be connected.
45    ///
46    /// Changing the `max_clients` to a lower value than the current number of connect clients
47    /// does not disconnect clients. So [`NetcodeServerTransport::connected_clients()`] can
48    /// return a higher value than [`NetcodeServerTransport::max_clients()`].
49    pub fn set_max_clients(&mut self, max_clients: usize) {
50        self.netcode_server.set_max_clients(max_clients);
51    }
52
53    /// Returns current number of clients connected.
54    pub fn connected_clients(&self) -> usize {
55        self.netcode_server.connected_clients()
56    }
57
58    /// Returns the user data for client if connected.
59    pub fn user_data(&self, client_id: ClientId) -> Option<[u8; NETCODE_USER_DATA_BYTES]> {
60        self.netcode_server.user_data(client_id)
61    }
62
63    /// Returns the client address if connected.
64    pub fn client_addr(&self, client_id: ClientId) -> Option<SocketAddr> {
65        self.netcode_server.client_addr(client_id)
66    }
67
68    /// Disconnects all connected clients.
69    /// This sends the disconnect packet instantly, use this when closing/exiting games,
70    /// should use [RenetServer::disconnect_all][crate::RenetServer::disconnect_all] otherwise.
71    pub fn disconnect_all(&mut self, server: &mut RenetServer) {
72        for client_id in self.netcode_server.clients_id() {
73            let server_result = self.netcode_server.disconnect(client_id);
74            handle_server_result(server_result, &self.socket, server);
75        }
76    }
77
78    /// Returns the duration since the connected client last received a packet.
79    /// Useful to detect users that are timing out.
80    pub fn time_since_last_received_packet(&self, client_id: ClientId) -> Option<Duration> {
81        self.netcode_server.time_since_last_received_packet(client_id)
82    }
83
84    /// Advances the transport by the duration, and receive packets from the network.
85    pub fn update(&mut self, duration: Duration, server: &mut RenetServer) -> Result<(), NetcodeTransportError> {
86        self.netcode_server.update(duration);
87
88        loop {
89            match self.socket.recv_from(&mut self.buffer) {
90                Ok((len, addr)) => {
91                    let server_result = self.netcode_server.process_packet(addr, &mut self.buffer[..len]);
92                    handle_server_result(server_result, &self.socket, server);
93                }
94                Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => break,
95                Err(ref e) if e.kind() == io::ErrorKind::Interrupted => break,
96                Err(ref e) if e.kind() == io::ErrorKind::ConnectionReset => continue,
97                Err(e) => return Err(e.into()),
98            };
99        }
100
101        for client_id in self.netcode_server.clients_id() {
102            let server_result = self.netcode_server.update_client(client_id);
103            handle_server_result(server_result, &self.socket, server);
104        }
105
106        for disconnection_id in server.disconnections_id() {
107            let server_result = self.netcode_server.disconnect(disconnection_id);
108            handle_server_result(server_result, &self.socket, server);
109        }
110
111        Ok(())
112    }
113
114    /// Send packets to connected clients.
115    pub fn send_packets(&mut self, server: &mut RenetServer) {
116        'clients: for client_id in server.clients_id() {
117            let packets = server.get_packets_to_send(client_id).unwrap();
118            for packet in packets {
119                match self.netcode_server.generate_payload_packet(client_id, &packet) {
120                    Ok((addr, payload)) => {
121                        if let Err(e) = self.socket.send_to(payload, addr) {
122                            log::error!("Failed to send packet to client {client_id} ({addr}): {e}");
123                            continue 'clients;
124                        }
125                    }
126                    Err(e) => {
127                        log::error!("Failed to encrypt payload packet for client {client_id}: {e}");
128                        continue 'clients;
129                    }
130                }
131            }
132        }
133    }
134}
135
136fn handle_server_result(server_result: ServerResult, socket: &UdpSocket, reliable_server: &mut RenetServer) {
137    let send_packet = |packet: &[u8], addr: SocketAddr| {
138        if let Err(err) = socket.send_to(packet, addr) {
139            log::error!("Failed to send packet to {addr}: {err}");
140        }
141    };
142
143    match server_result {
144        ServerResult::None => {}
145        ServerResult::PacketToSend { payload, addr } => {
146            send_packet(payload, addr);
147        }
148        ServerResult::Payload { client_id, payload } => {
149            if let Err(e) = reliable_server.process_packet_from(payload, client_id) {
150                log::error!("Error while processing payload for {}: {}", client_id, e);
151            }
152        }
153        ServerResult::ClientConnected {
154            client_id,
155            user_data: _,
156            addr,
157            payload,
158        } => {
159            reliable_server.add_connection(client_id);
160            send_packet(payload, addr);
161        }
162        ServerResult::ClientDisconnected { client_id, addr, payload } => {
163            reliable_server.remove_connection(client_id);
164            if let Some(payload) = payload {
165                send_packet(payload, addr);
166            }
167        }
168    }
169}