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)
}
}