use std::{
io,
net::{SocketAddr, UdpSocket},
time::Duration,
};
use renetcode::{ClientAuthentication, DisconnectReason, NetcodeClient, NetcodeError, NETCODE_MAX_PACKET_BYTES};
use renet::{ClientId, RenetClient};
use super::NetcodeTransportError;
#[derive(Debug)]
pub struct NetcodeClientTransport {
socket: UdpSocket,
netcode_client: NetcodeClient,
buffer: [u8; NETCODE_MAX_PACKET_BYTES],
}
impl NetcodeClientTransport {
pub fn new(current_time: Duration, authentication: ClientAuthentication, socket: UdpSocket) -> Result<Self, NetcodeError> {
socket.set_nonblocking(true)?;
let netcode_client = NetcodeClient::new(current_time, authentication)?;
Ok(Self {
buffer: [0u8; NETCODE_MAX_PACKET_BYTES],
socket,
netcode_client,
})
}
pub fn addr(&self) -> io::Result<SocketAddr> {
self.socket.local_addr()
}
pub fn client_id(&self) -> ClientId {
self.netcode_client.client_id()
}
pub fn time_since_last_received_packet(&self) -> Duration {
self.netcode_client.time_since_last_received_packet()
}
pub fn disconnect(&mut self) {
if self.netcode_client.is_disconnected() {
return;
}
match self.netcode_client.disconnect() {
Ok((addr, packet)) => {
if let Err(e) = self.socket.send_to(packet, addr) {
log::error!("Failed to send disconnect packet: {e}");
}
}
Err(e) => log::error!("Failed to generate disconnect packet: {e}"),
}
}
pub fn disconnect_reason(&self) -> Option<DisconnectReason> {
self.netcode_client.disconnect_reason()
}
pub fn send_packets(&mut self, connection: &mut RenetClient) -> Result<(), NetcodeTransportError> {
if let Some(reason) = self.netcode_client.disconnect_reason() {
return Err(NetcodeError::Disconnected(reason).into());
}
let packets = connection.get_packets_to_send();
for packet in packets {
let (addr, payload) = self.netcode_client.generate_payload_packet(&packet)?;
self.socket.send_to(payload, addr)?;
}
Ok(())
}
pub fn update(&mut self, duration: Duration, client: &mut RenetClient) -> Result<(), NetcodeTransportError> {
if let Some(reason) = self.netcode_client.disconnect_reason() {
client.disconnect_due_to_transport();
return Err(NetcodeError::Disconnected(reason).into());
}
if let Some(error) = client.disconnect_reason() {
let (addr, disconnect_packet) = self.netcode_client.disconnect()?;
self.socket.send_to(disconnect_packet, addr)?;
return Err(error.into());
}
if self.netcode_client.is_connected() {
client.set_connected();
} else if self.netcode_client.is_connecting() {
client.set_connecting();
}
loop {
let packet = match self.socket.recv_from(&mut self.buffer) {
Ok((len, addr)) => {
if addr != self.netcode_client.server_addr() {
log::debug!("Discarded packet from unknown server {:?}", addr);
continue;
}
&mut self.buffer[..len]
}
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => break,
Err(ref e) if e.kind() == io::ErrorKind::Interrupted => break,
Err(e) => return Err(NetcodeTransportError::IO(e)),
};
if let Some(payload) = self.netcode_client.process_packet(packet) {
client.process_packet(payload);
}
}
if let Some((packet, addr)) = self.netcode_client.update(duration) {
self.socket.send_to(packet, addr)?;
}
Ok(())
}
}