Skip to content

Commit

Permalink
feat: Increase networking performance by moving chunk updates into an…
Browse files Browse the repository at this point in the history
…other channel
  • Loading branch information
AudranTourneur committed Jan 27, 2025
1 parent d8b70f7 commit fd36153
Show file tree
Hide file tree
Showing 6 changed files with 116 additions and 56 deletions.
38 changes: 28 additions & 10 deletions client/src/network/extensions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,39 +2,57 @@ use bevy::prelude::*;
use bevy_renet::renet::RenetClient;
use bincode::ErrorKind;
use shared::{
game_message_to_payload, get_default_game_channel,
game_message_to_payload, get_customized_server_to_client_channels,
messages::{ClientToServerMessage, ServerToClientMessage},
ChannelResolvableExt,
};

pub trait SendGameMessageExtension {
fn send_game_message(&mut self, message: ClientToServerMessage);
fn receive_game_message(&mut self) -> Result<ServerToClientMessage, Box<ErrorKind>>;
fn receive_game_message_by_channel(
&mut self,
channel: u8,
) -> Option<Result<ServerToClientMessage, Box<ErrorKind>>>;
fn receive_game_message(&mut self) -> Option<Result<ServerToClientMessage, Box<ErrorKind>>>;
}

impl SendGameMessageExtension for RenetClient {
fn send_game_message(&mut self, message: ClientToServerMessage) {
let ch = message.get_channel_id();
let payload = game_message_to_payload(message);
self.send_message(get_default_game_channel(), payload);
self.send_message(ch, payload);
}

fn receive_game_message(&mut self) -> Result<ServerToClientMessage, Box<ErrorKind>> {
let payload = self.receive_message(get_default_game_channel());
fn receive_game_message_by_channel(
&mut self,
channel: u8,
) -> Option<Result<ServerToClientMessage, Box<ErrorKind>>> {
let payload = self.receive_message(channel);
if let Some(payload) = payload {
// debug!("Received payload: {:?}", payload);
let res = shared::payload_to_game_message::<ServerToClientMessage>(&payload);
match res {
Ok(msg) => {
// info!("Received message: {:?}", msg);
return Ok(msg);
return Some(Ok(msg));
}
Err(e) => {
warn!("Error deserializing message: {:?}", e);
return Err(e);
return Some(Err(e));
}
}
}
Err(Box::new(ErrorKind::Custom(
"No message received".to_string(),
)))
None
}

fn receive_game_message(&mut self) -> Option<Result<ServerToClientMessage, Box<ErrorKind>>> {
let channels = get_customized_server_to_client_channels();
for channel in channels {
let res = self.receive_game_message_by_channel(channel.channel_id);
if let Some(res) = res {
return Some(res);
}
}
None
}
}
2 changes: 1 addition & 1 deletion client/src/network/setup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,7 @@ pub fn establish_authenticated_connection_to_server(
target.state = TargetServerState::Establishing;
}

while let Ok(message) = client.receive_game_message() {
while let Some(Ok(message)) = client.receive_game_message() {
match message {
ServerToClientMessage::AuthRegisterResponse(message) => {
target.username = Some(message.username);
Expand Down
2 changes: 1 addition & 1 deletion client/src/network/world.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ pub fn update_world_from_network(
ev_item_stacks_update: &mut EventWriter<ItemStackUpdateEvent>,
ev_player_update: &mut EventWriter<PlayerUpdateEvent>,
) {
while let Ok(msg) = client.receive_game_message() {
while let Some(Ok(msg)) = client.receive_game_message() {
// truncate the message to 1000 characters
// let debug_msg = format!("{:?}", msg).chars().take(1000).collect::<String>();
// info!("Received message: {}", debug_msg);
Expand Down
2 changes: 1 addition & 1 deletion server/src/network/dispatcher.rs
Original file line number Diff line number Diff line change
Expand Up @@ -82,7 +82,7 @@ fn server_update_system(
}

for client_id in server.clients_id() {
while let Ok(message) = server.receive_game_message(client_id) {
while let Some(Ok(message)) = server.receive_game_message(client_id) {
match message {
ClientToServerMessage::AuthRegisterRequest(auth_req) => {
info!("Auth request received {:?}", auth_req);
Expand Down
63 changes: 40 additions & 23 deletions server/src/network/extensions.rs
Original file line number Diff line number Diff line change
@@ -1,48 +1,53 @@
use bevy::prelude::*;
use bevy_renet::renet::{ClientId, RenetServer};
use shared::{get_default_game_channel, utils::format_bytes};
use shared::{
get_customized_client_to_server_channels,
messages::{ClientToServerMessage, ServerToClientMessage},
utils::format_bytes,
ChannelResolvableExt,
};

pub trait SendGameMessageExtension {
fn send_game_message(
fn send_game_message(&mut self, client_id: ClientId, message: ServerToClientMessage);
fn broadcast_game_message(&mut self, message: ServerToClientMessage);
fn receive_game_message(
&mut self,
client_id: ClientId,
message: shared::messages::ServerToClientMessage,
);
fn broadcast_game_message(&mut self, message: shared::messages::ServerToClientMessage);
fn receive_game_message(
) -> Option<Result<ClientToServerMessage, Box<bincode::ErrorKind>>>;
fn receive_game_message_by_channel(
&mut self,
client_id: ClientId,
) -> Result<shared::messages::ClientToServerMessage, Box<bincode::ErrorKind>>;
channel: u8,
) -> Option<Result<ClientToServerMessage, Box<bincode::ErrorKind>>>;
}

impl SendGameMessageExtension for RenetServer {
fn send_game_message(
&mut self,
client_id: ClientId,
message: shared::messages::ServerToClientMessage,
) {
fn send_game_message(&mut self, client_id: ClientId, message: ServerToClientMessage) {
let channel = message.get_channel_id();
let payload = shared::game_message_to_payload(message);
let size = payload.len() as u64;
if size > (10 * 1024) {
info!("Sending game message of size: {}", format_bytes(size));
}
self.send_message(client_id, get_default_game_channel(), payload);
self.send_message(client_id, channel, payload);
}

fn broadcast_game_message(&mut self, message: shared::messages::ServerToClientMessage) {
fn broadcast_game_message(&mut self, message: ServerToClientMessage) {
let channel = message.get_channel_id();
let payload = shared::game_message_to_payload(message);
let size = payload.len() as u64;
if size > (10 * 1024) {
info!("Broadcasting game message of size: {}", format_bytes(size));
}
self.broadcast_message(get_default_game_channel(), payload);
self.broadcast_message(channel, payload);
}

fn receive_game_message(
fn receive_game_message_by_channel(
&mut self,
client_id: ClientId,
) -> Result<shared::messages::ClientToServerMessage, Box<bincode::ErrorKind>> {
let payload = self.receive_message(client_id, get_default_game_channel());
channel: u8,
) -> Option<Result<ClientToServerMessage, Box<bincode::ErrorKind>>> {
let payload = self.receive_message(client_id, channel);
if let Some(payload) = payload {
// debug!("Received payload: {:?}", payload);
let msg = shared::payload_to_game_message::<shared::messages::ClientToServerMessage>(
Expand All @@ -51,16 +56,28 @@ impl SendGameMessageExtension for RenetServer {
match msg {
Ok(msg) => {
// info!("Received message: {:?}", msg);
return Ok(msg);
return Some(Ok(msg));
}
Err(e) => {
warn!("Error deserializing message: {:?}", e);
return Err(e);
return Some(Err(e));
}
}
}
Err(Box::new(bincode::ErrorKind::Custom(
"No message received".to_string(),
)))
None
}

fn receive_game_message(
&mut self,
client_id: ClientId,
) -> Option<Result<ClientToServerMessage, Box<bincode::ErrorKind>>> {
let channels = get_customized_client_to_server_channels();
for channel in channels {
let res = self.receive_game_message_by_channel(client_id, channel.channel_id);
if res.is_some() {
return res;
}
}
None
}
}
65 changes: 45 additions & 20 deletions shared/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use std::time::Duration;

use bevy::prelude::*;
use bevy_renet::renet::{ChannelConfig, ConnectionConfig, DefaultChannel, SendType};
use bevy_renet::renet::{ChannelConfig, ConnectionConfig, SendType};
use bincode::Options;

pub mod constants;
Expand All @@ -11,6 +11,7 @@ pub mod utils;
pub mod world;

pub use constants::*;
use messages::{ClientToServerMessage, ServerToClientMessage};
use utils::format_bytes;

#[derive(Resource, Debug, Clone)]
Expand All @@ -30,36 +31,45 @@ pub struct GameServerConfig {
pub is_solo: bool,
}

fn get_customized_default_channels() -> Vec<ChannelConfig> {
let memory = 128 * 1024 * 1024;
vec![
ChannelConfig {
channel_id: 0,
max_memory_usage_bytes: memory,
send_type: SendType::Unreliable,
const MAX_MEMORY: usize = 128 * 1024 * 1024;
const RESEND_TIME: Duration = Duration::from_millis(300);
const AVAILABLE_BYTES_PER_TICK: u64 = 5 * 1024 * 1024;

pub fn get_customized_client_to_server_channels() -> Vec<ChannelConfig> {
vec![ChannelConfig {
channel_id: 0, // Standard actions
max_memory_usage_bytes: MAX_MEMORY,
send_type: SendType::ReliableOrdered {
resend_time: RESEND_TIME,
},
}]
}

pub fn get_customized_server_to_client_channels() -> Vec<ChannelConfig> {
vec![
ChannelConfig {
channel_id: 1,
max_memory_usage_bytes: memory,
send_type: SendType::ReliableUnordered {
resend_time: Duration::from_millis(300),
channel_id: 0, // Standard actions
max_memory_usage_bytes: MAX_MEMORY,
send_type: SendType::ReliableOrdered {
resend_time: RESEND_TIME,
},
},
ChannelConfig {
channel_id: 2,
max_memory_usage_bytes: memory,
// Chunk data
channel_id: 1,
max_memory_usage_bytes: MAX_MEMORY,
send_type: SendType::ReliableOrdered {
resend_time: Duration::from_millis(300),
resend_time: RESEND_TIME,
},
},
]
}

pub fn get_shared_renet_config() -> ConnectionConfig {
ConnectionConfig {
client_channels_config: get_customized_default_channels(),
server_channels_config: get_customized_default_channels(),
..Default::default()
client_channels_config: get_customized_client_to_server_channels(),
server_channels_config: get_customized_server_to_client_channels(),
available_bytes_per_tick: AVAILABLE_BYTES_PER_TICK,
}
}

Expand All @@ -86,6 +96,21 @@ pub fn payload_to_game_message<T: serde::de::DeserializeOwned>(
bincode::options().deserialize(&decompressed_payload)
}

pub fn get_default_game_channel() -> DefaultChannel {
DefaultChannel::ReliableUnordered
pub trait ChannelResolvableExt {
fn get_channel_id(&self) -> u8;
}

impl ChannelResolvableExt for ClientToServerMessage {
fn get_channel_id(&self) -> u8 {
0
}
}

impl ChannelResolvableExt for ServerToClientMessage {
fn get_channel_id(&self) -> u8 {
match self {
ServerToClientMessage::WorldUpdate(_) => 1,
_ => 0,
}
}
}

0 comments on commit fd36153

Please sign in to comment.