Renet is a network library for Server/Client games written in rust. It is focused on fast-paced games such as FPS, and competitive games. Provides the following features:
Renet communication is message based, and channels describe how the messages should be delivered.
Channels are unilateral, ConnectionConfig.client_channels_config
describes the channels that the clients sends to the server, and ConnectionConfig.server_channels_config
describes the channels that the server sends to the clients.
Each channel has its own configuration ChannelConfig
:
```rust // No garantee of message delivery or order let sendtype = SendType::Unreliable; // Garantee of message delivery and order let sendtype = SendType::ReliableOrdered { // If a message is lost, it will be resent after this duration resendtime: Duration::frommillis(300) };
// Garantee of message delivery but not order let sendtype = SendType::ReliableUnordered { resendtime: Duration::from_millis(300) };
let channelconfig = ChannelConfig { // The id for the channel, must be unique within its own list, // but it can be repeated between the server and client lists. channelid: 0, // Maximum number of bytes that the channel may hold without acknowledgement of messages before becoming full. maxmemoryusagebytes: 5 * 1024 * 1024, // 5 megabytes sendtype }; ```
Renet aims to have a simple API that is easy to integrate with any code base. Pool for new messages at the start of a frame with update
. Call send_packets
from the transport layer to send packets to the client/server.
```rust let mut server = RenetServer::new(ConnectionConfig::default());
// Setup transport layer const SERVERADDR: SocketAddr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1), 5000)); let socket: UdpSocket = UdpSocket::bind(SERVERADDR).unwrap(); let serverconfig = ServerConfig { maxclients:64 protocolid: 0, publicaddr: SERVERADDR, authentication: ServerAuthentication::Unsecure }; let currenttime = SystemTime::now().durationsince(SystemTime::UNIXEPOCH).unwrap(); let mut transport = NetcodeServerTransport::new(currenttime, serverconfig, socket).unwrap();
// Your gameplay loop loop { let deltatime = Duration::frommillis(16); // Receive new messages and update clients server.update(deltatime)?; transport.update(deltatime, &mut server)?;
// Check for client connections/disconnections
while let Some(event) = server.get_event() {
match event {
ServerEvent::ClientConnected { client_id } => {
println!("Client {client_id} connected");
}
ServerEvent::ClientDisconnected { client_id, reason } => {
println!("Client {client_id} disconnected: {reason}");
}
}
}
// Receive message from channel
for client_id in server.connections_id() {
// The enum DefaultChannel describe the channels used by the default configuration
while let Some(message) = server.receive_message(client_id, DefaultChannel::ReliableOrdered) {
// Handle received message
}
}
// Send a text message for all clients
server.broadcast_message(DefaultChannel::ReliableOrdered, "server message".as_bytes().to_vec());
// Send message to only one client
let client_id = 0;
server.send_message(client_id, DefaultChannel::ReliableOrdered, "server message".as_bytes().to_vec());
// Send packets to clients
transport.send_packets(&mut server);
} ```
```rust let mut client = RenetClient::new(ConnectionConfig::default());
// Setup transport layer const SERVERADDR: SocketAddr = SocketAddr::new(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1), 5000)); let socket = UdpSocket::bind("127.0.0.1:0").unwrap(); let currenttime = SystemTime::now().durationsince(SystemTime::UNIXEPOCH).unwrap(); let clientid: u64 = 0; let authentication = ClientAuthentication::Unsecure { serveraddr: SERVERADDR, clientid, userdata: None, protocolid: 0, };
let mut transport = NetcodeClientTransport::new(current_time, authentication, socket).unwrap();
// Your gameplay loop loop { let deltatime = Duration::frommillis(16); // Receive new messages and update client client.update(deltatime)?; transport.update(deltatime, &mut client).unwrap();
if client.is_connected() {
// Receive message from server
while let Some(message) = client.receive_message(DefaultChannel::ReliableOrdered) {
// Handle received message
}
// Send message
client.send_message(DefaultChannel::ReliableOrdered, "client text".as_bytes().to_vec());
}
// Send packets to server
transport.send_packets(&mut client)?;
} ```
You can checkout the echo example for a simple usage of the library. Or you can look into the two demos that have more complex uses of renet:
Bevy Demo
Simple bevy application to demonstrate how you could replicate entities and send reliable messages as commands from the server/client using renet:
Chat Demo
Simple chat application made with egui to demonstrate how you could handle errors, states transitions and client self hosting:
Checkout bevy_renet if you want to use renet as a plugin with the Bevy engine.
Checkout renet_visualizer for a egui plugin to plot metrics data from renet clients and servers:
https://user-images.githubusercontent.com/35241085/175834010-b1eafd77-7ea2-47dc-a915-a399099c7a99.mp4