Skip to content

Commit

Permalink
Export RTT and packet loss from the backend (#360)
Browse files Browse the repository at this point in the history
* Export statistics API

* Add `warning` to method docs that should be called from the backend
  • Loading branch information
Shatur authored Nov 22, 2024
1 parent 5ae9e5f commit df44894
Show file tree
Hide file tree
Showing 5 changed files with 135 additions and 13 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- RTT and packet loss information for `RepliconClient` and `ConnectedClients`.

### Changed

- `ConnectedClients` now store `ConnectedClient` instead of `ClientId` with more information about the client.
- All `TestFnsEntityExt` now accept `FnsId`.
- Move replication-related modules from `core` module under `core::replication`.
- Move `Replicated` to the `replication` module.
Expand Down
70 changes: 66 additions & 4 deletions src/core/connected_clients.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,23 +7,85 @@ use crate::core::ClientId;
/// Inserted as resource by [`ServerPlugin`](crate::server::ServerPlugin).
///
/// See also [ReplicatedClients](super::replication::replicated_clients::ReplicatedClients).
#[derive(Resource, Default, Deref)]
pub struct ConnectedClients(Vec<ClientId>);
#[derive(Resource, Default, Debug, Deref)]
pub struct ConnectedClients(Vec<ConnectedClient>);

impl ConnectedClients {
pub(crate) fn add(&mut self, client_id: ClientId) {
debug!("adding connected `{client_id:?}`");

self.0.push(client_id);
self.0.push(ConnectedClient::new(client_id));
}

pub(crate) fn remove(&mut self, client_id: ClientId) {
debug!("removing disconnected `{client_id:?}`");

let index = self
.iter()
.position(|test_id| *test_id == client_id)
.position(|client| client.id == client_id)
.unwrap_or_else(|| panic!("{client_id:?} should be added before removal"));
self.0.remove(index);
}

pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut ConnectedClient> {
self.0.iter_mut()
}
}

#[derive(Debug, Clone, Copy)]
pub struct ConnectedClient {
id: ClientId,
rtt: f64,
packet_loss: f64,
}

impl ConnectedClient {
pub fn new(id: ClientId) -> Self {
Self {
id,
rtt: 0.0,
packet_loss: 0.0,
}
}

/// Returns the associated ID.
pub fn id(&self) -> ClientId {
self.id
}

/// Returns the round-time trip for the connection.
///
/// Returns zero if not provided by the backend.
pub fn rtt(&self) -> f64 {
self.rtt
}

/// Sets the round-time trip for the connection.
///
/// <div class="warning">
///
/// Should only be called from the messaging backend.
///
/// </div>
pub fn set_rtt(&mut self, rtt: f64) {
self.rtt = rtt;
}

/// Returns the packet loss for the connection.
///
/// Returns zero if not provided by the backend.
pub fn packet_loss(&self) -> f64 {
self.packet_loss
}

/// Sets the packet loss for the connection.
///
/// <div class="warning">
///
/// Should only be called from the messaging backend.
///
/// </div>
pub fn set_packet_loss(&mut self, packet_loss: f64) {
self.packet_loss = packet_loss;
}
}
10 changes: 5 additions & 5 deletions src/core/event_registry/server_event.rs
Original file line number Diff line number Diff line change
Expand Up @@ -637,14 +637,14 @@ unsafe fn send_independent_event<E: Event>(

match *mode {
SendMode::Broadcast => {
for &client_id in connected_clients.iter() {
server.send(client_id, event_data.channel_id, message.clone());
for client in connected_clients.iter() {
server.send(client.id(), event_data.channel_id, message.clone());
}
}
SendMode::BroadcastExcept(id) => {
for &client_id in connected_clients.iter() {
if client_id != id {
server.send(client_id, event_data.channel_id, message.clone());
for client in connected_clients.iter() {
if client.id() != id {
server.send(client.id(), event_data.channel_id, message.clone());
}
}
}
Expand Down
51 changes: 49 additions & 2 deletions src/core/replicon_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ pub struct RepliconClient {

/// List of sent messages and their channels since the last tick.
sent_messages: Vec<(u8, Bytes)>,

rtt: f64,
packet_loss: f64,
}

impl RepliconClient {
Expand Down Expand Up @@ -153,14 +156,22 @@ impl RepliconClient {

/// Removes all sent messages, returning them as an iterator with channel.
///
/// Should be called only from the messaging backend.
/// <div class="warning">
///
/// Should only be called from the messaging backend.
///
/// </div>
pub fn drain_sent(&mut self) -> impl Iterator<Item = (u8, Bytes)> + '_ {
self.sent_messages.drain(..)
}

/// Adds a message from the server to the list of received messages.
///
/// Should be called only from the messaging backend.
/// <div class="warning">
///
/// Should only be called from the messaging backend.
///
/// </div>
pub fn insert_received<I: Into<u8>, B: Into<Bytes>>(&mut self, channel_id: I, message: B) {
if !self.is_connected() {
warn!("trying to insert a received message when the client is not connected");
Expand All @@ -175,6 +186,42 @@ impl RepliconClient {

channel_messages.push(message.into());
}

/// Returns the round-time trip for the connection.
///
/// Returns zero if not provided by the backend.
pub fn rtt(&self) -> f64 {
self.rtt
}

/// Sets the round-time trip for the connection.
///
/// <div class="warning">
///
/// Should only be called from the messaging backend.
///
/// </div>
pub fn set_rtt(&mut self, rtt: f64) {
self.rtt = rtt;
}

/// Returns the packet loss for the connection.
///
/// Returns zero if not provided by the backend.
pub fn packet_loss(&self) -> f64 {
self.packet_loss
}

/// Sets the packet loss for the connection.
///
/// <div class="warning">
///
/// Should only be called from the messaging backend.
///
/// </div>
pub fn set_packet_loss(&mut self, packet_loss: f64) {
self.packet_loss = packet_loss;
}
}

/// Connection status of the [`RepliconClient`].
Expand Down
12 changes: 10 additions & 2 deletions src/core/replicon_server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -125,14 +125,22 @@ impl RepliconServer {

/// Removes all sent messages, returning them as an iterator with client ID and channel.
///
/// Should be called only from the messaging backend.
/// <div class="warning">
///
/// Should only be called from the messaging backend.
///
/// </div>
pub fn drain_sent(&mut self) -> impl Iterator<Item = (ClientId, u8, Bytes)> + '_ {
self.sent_messages.drain(..)
}

/// Adds a message from a client to the list of received messages.
///
/// Should be called only from the messaging backend.
/// <div class="warning">
///
/// Should only be called from the messaging backend.
///
/// </div>
pub fn insert_received<I: Into<u8>, B: Into<Bytes>>(
&mut self,
client_id: ClientId,
Expand Down

0 comments on commit df44894

Please sign in to comment.