Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add TransportSocket trait for injecting the socket into netcode transports #145

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions bevy_renet/examples/simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ use bevy_renet::{
RenetClientPlugin, RenetServerPlugin,
};
use renet::{
transport::{NetcodeClientTransport, NetcodeServerTransport, NetcodeTransportError},
transport::{NativeSocket, NetcodeClientTransport, NetcodeServerTransport, NetcodeTransportError},
ClientId,
};

Expand Down Expand Up @@ -58,7 +58,7 @@ fn new_renet_client() -> (RenetClient, NetcodeClientTransport) {
user_data: None,
};

let transport = NetcodeClientTransport::new(current_time, authentication, socket).unwrap();
let transport = NetcodeClientTransport::new(current_time, authentication, NativeSocket::new(socket).unwrap()).unwrap();
let client = RenetClient::new(ConnectionConfig::default());

(client, transport)
Expand All @@ -76,7 +76,7 @@ fn new_renet_server() -> (RenetServer, NetcodeServerTransport) {
authentication: ServerAuthentication::Unsecure,
};

let transport = NetcodeServerTransport::new(server_config, socket).unwrap();
let transport = NetcodeServerTransport::new(server_config, NativeSocket::new(socket).unwrap()).unwrap();
let server = RenetServer::new(ConnectionConfig::default());

(server, transport)
Expand Down
4 changes: 2 additions & 2 deletions demo_bevy/src/bin/client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use bevy::{
use bevy_egui::{EguiContexts, EguiPlugin};
use bevy_renet::{
client_connected,
renet::{ClientId, RenetClient},
renet::{transport::NativeSocket, ClientId, RenetClient},
RenetClientPlugin,
};
use demo_bevy::{
Expand Down Expand Up @@ -63,7 +63,7 @@ fn add_netcode_network(app: &mut App) {
user_data: None,
};

let transport = NetcodeClientTransport::new(current_time, authentication, socket).unwrap();
let transport = NetcodeClientTransport::new(current_time, authentication, NativeSocket::new(socket).unwrap()).unwrap();

app.insert_resource(client);
app.insert_resource(transport);
Expand Down
4 changes: 2 additions & 2 deletions demo_bevy/src/bin/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use bevy::{
};
use bevy_egui::{EguiContexts, EguiPlugin};
use bevy_renet::{
renet::{ClientId, RenetServer, ServerEvent},
renet::{transport::NativeSocket, ClientId, RenetServer, ServerEvent},
RenetServerPlugin,
};
use demo_bevy::{
Expand Down Expand Up @@ -52,7 +52,7 @@ fn add_netcode_network(app: &mut App) {
authentication: ServerAuthentication::Unsecure,
};

let transport = NetcodeServerTransport::new(server_config, socket).unwrap();
let transport = NetcodeServerTransport::new(server_config, NativeSocket::new(socket).unwrap()).unwrap();
app.insert_resource(server);
app.insert_resource(transport);
}
Expand Down
4 changes: 2 additions & 2 deletions demo_chat/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use std::{
};

use renet::{
transport::{NetcodeServerTransport, ServerAuthentication, ServerConfig},
transport::{NativeSocket, NetcodeServerTransport, ServerAuthentication, ServerConfig},
ClientId, ConnectionConfig, DefaultChannel, RenetServer, ServerEvent,
};
use renet_visualizer::RenetServerVisualizer;
Expand Down Expand Up @@ -38,7 +38,7 @@ impl ChatServer {
authentication: ServerAuthentication::Unsecure,
};

let transport = NetcodeServerTransport::new(server_config, socket).unwrap();
let transport = NetcodeServerTransport::new(server_config, NativeSocket::new(socket).unwrap()).unwrap();

let server: RenetServer = RenetServer::new(ConnectionConfig::default());

Expand Down
4 changes: 2 additions & 2 deletions demo_chat/src/ui.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use eframe::{
epaint::PathShape,
};
use renet::{
transport::{ClientAuthentication, NetcodeClientTransport},
transport::{ClientAuthentication, NativeSocket, NetcodeClientTransport},
ClientId, ConnectionConfig, DefaultChannel, RenetClient,
};

Expand Down Expand Up @@ -267,7 +267,7 @@ fn create_renet_client(username: String, server_addr: SocketAddr) -> (RenetClien
protocol_id: PROTOCOL_ID,
};

let transport = NetcodeClientTransport::new(current_time, authentication, socket).unwrap();
let transport = NetcodeClientTransport::new(current_time, authentication, NativeSocket::new(socket).unwrap()).unwrap();

(client, transport)
}
7 changes: 4 additions & 3 deletions renet/examples/echo.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ use std::{

use renet::{
transport::{
ClientAuthentication, NetcodeClientTransport, NetcodeServerTransport, ServerAuthentication, ServerConfig, NETCODE_USER_DATA_BYTES,
ClientAuthentication, NativeSocket, NetcodeClientTransport, NetcodeServerTransport, ServerAuthentication, ServerConfig,
NETCODE_USER_DATA_BYTES,
},
ClientId, ConnectionConfig, DefaultChannel, RenetClient, RenetServer, ServerEvent,
};
Expand Down Expand Up @@ -77,7 +78,7 @@ fn server(public_addr: SocketAddr) {
};
let socket: UdpSocket = UdpSocket::bind(public_addr).unwrap();

let mut transport = NetcodeServerTransport::new(server_config, socket).unwrap();
let mut transport = NetcodeServerTransport::new(server_config, NativeSocket::new(socket).unwrap()).unwrap();

let mut usernames: HashMap<ClientId, String> = HashMap::new();
let mut received_messages = vec![];
Expand Down Expand Up @@ -152,7 +153,7 @@ fn client(server_addr: SocketAddr, username: Username) {
protocol_id: PROTOCOL_ID,
};

let mut transport = NetcodeClientTransport::new(current_time, authentication, socket).unwrap();
let mut transport = NetcodeClientTransport::new(current_time, authentication, NativeSocket::new(socket).unwrap()).unwrap();
let stdin_channel: Receiver<String> = spawn_stdin_channel();

let mut last_updated = Instant::now();
Expand Down
48 changes: 29 additions & 19 deletions renet/src/transport/client.rs
Original file line number Diff line number Diff line change
@@ -1,50 +1,47 @@
use std::{
io,
net::{SocketAddr, UdpSocket},
time::Duration,
};
use std::{io, net::SocketAddr, time::Duration};

use renetcode::{ClientAuthentication, DisconnectReason, NetcodeClient, NetcodeError, NETCODE_MAX_PACKET_BYTES};

use crate::{remote_connection::RenetClient, ClientId};

use super::NetcodeTransportError;
use super::{NetcodeTransportError, TransportSocket};

#[derive(Debug)]
#[cfg_attr(feature = "bevy", derive(bevy_ecs::system::Resource))]
pub struct NetcodeClientTransport {
socket: UdpSocket,
socket: Box<dyn TransportSocket>,
netcode_client: NetcodeClient,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you considered using generic instead?

Copy link
Contributor Author

@UkoeHB UkoeHB Feb 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah generic would get rid of the dynamic dispatch, but then all user code that gets the netcode transport resources has to parameterize on the socket type.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense.

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)?;
pub fn new(current_time: Duration, authentication: ClientAuthentication, socket: impl TransportSocket) -> Result<Self, NetcodeError> {
let netcode_client = NetcodeClient::new(current_time, authentication)?;

Ok(Self {
buffer: [0u8; NETCODE_MAX_PACKET_BYTES],
socket,
socket: Box::new(socket),
netcode_client,
buffer: [0u8; NETCODE_MAX_PACKET_BYTES],
})
}

pub fn addr(&self) -> io::Result<SocketAddr> {
self.socket.local_addr()
self.socket.addr()
}

pub fn client_id(&self) -> ClientId {
ClientId(self.netcode_client.client_id())
}

/// Returns the duration since the client last received a packet.
/// Usefull to detect timeouts.
///
/// Useful to detect timeouts.
pub fn time_since_last_received_packet(&self) -> Duration {
self.netcode_client.time_since_last_received_packet()
}

/// Disconnect the client from the transport layer.
///
/// This sends the disconnect packet instantly, use this when closing/exiting games,
/// should use [RenetClient::disconnect][crate::RenetClient::disconnect] otherwise.
pub fn disconnect(&mut self) {
Expand All @@ -54,7 +51,7 @@ impl NetcodeClientTransport {

match self.netcode_client.disconnect() {
Ok((addr, packet)) => {
if let Err(e) = self.socket.send_to(packet, addr) {
if let Err(e) = self.socket.send(addr, packet) {
log::error!("Failed to send disconnect packet: {e}");
}
}
Expand All @@ -68,7 +65,8 @@ impl NetcodeClientTransport {
}

/// Send packets to the server.
/// Should be called every tick
///
/// Should be called every tick.
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());
Expand All @@ -77,7 +75,7 @@ impl NetcodeClientTransport {
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)?;
self.socket.send(addr, payload)?;
}

Ok(())
Expand All @@ -88,13 +86,21 @@ impl NetcodeClientTransport {
if let Some(reason) = self.netcode_client.disconnect_reason() {
// Mark the client as disconnected if an error occured in the transport layer
client.disconnect_due_to_transport();
self.socket.close();

return Err(NetcodeError::Disconnected(reason).into());
}

if self.socket.is_closed() {
client.disconnect_due_to_transport();
}

if let Some(error) = client.disconnect_reason() {
let (addr, disconnect_packet) = self.netcode_client.disconnect()?;
self.socket.send_to(disconnect_packet, addr)?;
if !self.socket.is_closed() {
self.socket.send(addr, disconnect_packet)?;
self.socket.close();
}
return Err(error.into());
}

Expand All @@ -104,8 +110,10 @@ impl NetcodeClientTransport {
client.set_connecting();
}

self.socket.preupdate();

loop {
let packet = match self.socket.recv_from(&mut self.buffer) {
let packet = match self.socket.try_recv(&mut self.buffer) {
Ok((len, addr)) => {
if addr != self.netcode_client.server_addr() {
log::debug!("Discarded packet from unknown server {:?}", addr);
Expand All @@ -125,9 +133,11 @@ impl NetcodeClientTransport {
}

if let Some((packet, addr)) = self.netcode_client.update(duration) {
self.socket.send_to(packet, addr)?;
self.socket.send(addr, packet)?;
}

self.socket.postupdate();

Ok(())
}
}
4 changes: 4 additions & 0 deletions renet/src/transport/mod.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
use std::{error::Error, fmt};

mod client;
mod native_socket;
mod server;
mod transport_socket;

pub use client::*;
pub use native_socket::*;
pub use server::*;
pub use transport_socket::*;

pub use renetcode::{
generate_random_bytes, ClientAuthentication, ConnectToken, DisconnectReason as NetcodeDisconnectReason, NetcodeError,
Expand Down
42 changes: 42 additions & 0 deletions renet/src/transport/native_socket.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
use std::net::{SocketAddr, UdpSocket};

use super::{NetcodeError, NetcodeTransportError, TransportSocket};

/// Implementation of [`TransportSocket`] for `UdpSockets`.
#[derive(Debug)]
pub struct NativeSocket {
socket: UdpSocket,
Copy link
Contributor

@Shatur Shatur Feb 4, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe implement From to make it easier to initialize?
And I would declare it as NativeSocket(UdpSocket).

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can't do it, new() returns a Result.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, I see.

}

impl NativeSocket {
/// Makes a new native socket.
pub fn new(socket: UdpSocket) -> Result<Self, NetcodeError> {
socket.set_nonblocking(true)?;
Ok(Self { socket })
}
}

impl TransportSocket for NativeSocket {
fn addr(&self) -> std::io::Result<SocketAddr> {
self.socket.local_addr()
}

fn is_closed(&mut self) -> bool {
false
}

fn close(&mut self) {}
fn disconnect(&mut self, _: SocketAddr) {}
fn preupdate(&mut self) {}

fn try_recv(&mut self, buffer: &mut [u8]) -> std::io::Result<(usize, SocketAddr)> {
self.socket.recv_from(buffer)
}

fn postupdate(&mut self) {}

fn send(&mut self, addr: SocketAddr, packet: &[u8]) -> Result<(), NetcodeTransportError> {
self.socket.send_to(packet, addr)?;
Ok(())
}
}
Loading
Loading