bevy_replicon_renet 0.11.1

Integration with renet for bevy_replicon
use bevy::prelude::*;
#[cfg(feature = "renet_netcode")]
use bevy_renet::netcode::NetcodeClientPlugin;
#[cfg(feature = "renet_steam")]
use bevy_renet::steam::SteamClientPlugin;
use bevy_renet::{self, RenetClientPlugin, RenetReceive, RenetSend, renet::RenetClient};
use bevy_replicon::prelude::*;

/// Adds Renet as the client messaging backend.
///
/// Initializes [`RenetClientPlugin`] and the systems that pass data between [`RenetClient`]
/// and [`ClientMessages`], and update the [`ClientState`].
pub struct RepliconRenetClientPlugin;

impl Plugin for RepliconRenetClientPlugin {
    fn build(&self, app: &mut App) {
        app.add_plugins(RenetClientPlugin)
            .configure_sets(PreUpdate, ClientSystems::ReceivePackets.after(RenetReceive))
            .configure_sets(PostUpdate, ClientSystems::SendPackets.before(RenetSend))
            .add_systems(
                PreUpdate,
                (
                    set_connecting.run_if(resource_added::<RenetClient>),
                    set_connected.run_if(
                        in_state(ClientState::Connecting).and(bevy_renet::client_just_connected),
                    ),
                    set_disconnected.run_if(bevy_renet::client_just_disconnected),
                    receive_packets.run_if(bevy_renet::client_connected),
                )
                    .in_set(ClientSystems::ReceivePackets),
            )
            .add_systems(
                PostUpdate,
                send_packets
                    .in_set(ClientSystems::SendPackets)
                    .run_if(bevy_renet::client_connected),
            );

        #[cfg(feature = "renet_netcode")]
        app.add_plugins(NetcodeClientPlugin);
        #[cfg(feature = "renet_steam")]
        app.add_plugins(SteamClientPlugin);
    }
}

fn set_connecting(mut state: ResMut<NextState<ClientState>>) {
    state.set(ClientState::Connecting);
}

fn set_connected(mut state: ResMut<NextState<ClientState>>) {
    state.set(ClientState::Connected);
}

fn set_disconnected(mut state: ResMut<NextState<ClientState>>) {
    state.set(ClientState::Disconnected);
}

fn receive_packets(
    channels: Res<RepliconChannels>,
    mut client: ResMut<RenetClient>,
    mut messages: ResMut<ClientMessages>,
    mut stats: ResMut<ClientStats>,
) {
    for channel_id in 0..channels.server_channels().len() as u8 {
        while let Some(message) = client.receive_message(channel_id) {
            trace!(
                "forwarding {} received bytes over channel {channel_id}",
                message.len()
            );
            messages.insert_received(channel_id, message);
        }
    }

    stats.rtt = client.rtt();
    stats.packet_loss = client.packet_loss();
    stats.sent_bps = client.bytes_sent_per_sec();
    stats.received_bps = client.bytes_received_per_sec();
}

fn send_packets(mut client: ResMut<RenetClient>, mut messages: ResMut<ClientMessages>) {
    for (channel_id, message) in messages.drain_sent() {
        trace!(
            "forwarding {} sent bytes over channel {channel_id}",
            message.len()
        );
        client.send_message(channel_id as u8, message)
    }
}