bevy_renet 5.0.0

Bevy plugin for the renet crate: Server/Client network library for multiplayer games with authentication and connection management
Documentation
use std::{
    error::Error,
    fmt::{self, Display, Formatter},
    io,
    net::UdpSocket,
    time::Duration,
};

pub use renet_netcode::*;

use bevy_app::prelude::*;
use bevy_derive::{Deref, DerefMut};
use bevy_ecs::prelude::*;
use bevy_time::prelude::*;

use crate::{RenetClient, RenetClientPlugin, RenetReceive, RenetSend, RenetServer, RenetServerPlugin};

pub struct NetcodeServerPlugin;

pub struct NetcodeClientPlugin;

impl Plugin for NetcodeServerPlugin {
    fn build(&self, app: &mut App) {
        app.add_systems(
            PreUpdate,
            Self::update_system
                .in_set(RenetReceive)
                .run_if(resource_exists::<NetcodeServerTransport>)
                .run_if(resource_exists::<RenetServer>)
                .after(RenetServerPlugin::update_system)
                .before(RenetServerPlugin::emit_server_events_system),
        );

        app.add_systems(
            PostUpdate,
            Self::send_packets
                .in_set(RenetSend)
                .run_if(resource_exists::<NetcodeServerTransport>)
                .run_if(resource_exists::<RenetServer>),
        );

        app.add_systems(
            Last,
            Self::disconnect_on_exit
                .run_if(resource_exists::<NetcodeServerTransport>)
                .run_if(resource_exists::<RenetServer>),
        );
    }
}

impl NetcodeServerPlugin {
    pub fn update_system(
        mut commands: Commands,
        mut transport: ResMut<NetcodeServerTransport>,
        mut server: ResMut<RenetServer>,
        time: Res<Time<Real>>,
    ) {
        if let Err(e) = transport.update(time.delta(), &mut server) {
            commands.trigger(NetcodeErrorEvent(e));
        }
    }

    pub fn send_packets(mut transport: ResMut<NetcodeServerTransport>, mut server: ResMut<RenetServer>) {
        transport.send_packets(&mut server);
    }

    pub fn disconnect_on_exit(
        exit: MessageReader<AppExit>,
        mut transport: ResMut<NetcodeServerTransport>,
        mut server: ResMut<RenetServer>,
    ) {
        if !exit.is_empty() {
            transport.disconnect_all(&mut server);
        }
    }
}

impl Plugin for NetcodeClientPlugin {
    fn build(&self, app: &mut App) {
        app.add_systems(
            PreUpdate,
            Self::update_system
                .in_set(RenetReceive)
                .run_if(resource_exists::<NetcodeClientTransport>)
                .run_if(resource_exists::<RenetClient>)
                .after(RenetClientPlugin::update_system),
        );
        app.add_systems(
            PostUpdate,
            Self::send_packets
                .in_set(RenetSend)
                .run_if(resource_exists::<NetcodeClientTransport>)
                .run_if(resource_exists::<RenetClient>),
        );

        app.add_systems(
            Last,
            Self::disconnect_on_exit
                .run_if(resource_exists::<NetcodeClientTransport>)
                .run_if(resource_exists::<RenetClient>),
        );
    }
}

impl NetcodeClientPlugin {
    pub fn update_system(
        mut commands: Commands,
        mut transport: ResMut<NetcodeClientTransport>,
        mut client: ResMut<RenetClient>,
        time: Res<Time<Real>>,
    ) {
        if let Err(e) = transport.update(time.delta(), &mut client) {
            commands.trigger(NetcodeErrorEvent(e));
        }
    }

    pub fn send_packets(mut commands: Commands, mut transport: ResMut<NetcodeClientTransport>, mut client: ResMut<RenetClient>) {
        if let Err(e) = transport.send_packets(&mut client) {
            commands.trigger(NetcodeErrorEvent(e));
        }
    }

    pub fn disconnect_on_exit(exit: MessageReader<AppExit>, mut transport: ResMut<NetcodeClientTransport>) {
        if !exit.is_empty() {
            transport.disconnect();
        }
    }
}

#[derive(Resource, Deref, DerefMut, Debug)]
pub struct NetcodeClientTransport(pub renet_netcode::NetcodeClientTransport);

impl NetcodeClientTransport {
    pub fn new(current_time: Duration, authentication: ClientAuthentication, socket: UdpSocket) -> Result<Self, NetcodeError> {
        renet_netcode::NetcodeClientTransport::new(current_time, authentication, socket).map(Self)
    }
}

#[derive(Resource, Deref, DerefMut)]
pub struct NetcodeServerTransport(pub renet_netcode::NetcodeServerTransport);

impl NetcodeServerTransport {
    pub fn new(server_config: ServerConfig, socket: UdpSocket) -> Result<Self, io::Error> {
        renet_netcode::NetcodeServerTransport::new(server_config, socket).map(Self)
    }
}

#[derive(Event, Debug, Deref, DerefMut)]
pub struct NetcodeErrorEvent(pub NetcodeTransportError);

impl Error for NetcodeErrorEvent {}

impl Display for NetcodeErrorEvent {
    fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
        self.0.fmt(fmt)
    }
}

impl From<NetcodeTransportError> for NetcodeErrorEvent {
    fn from(value: NetcodeTransportError) -> Self {
        Self(value)
    }
}