use crate::named::Named;
pub trait Channel: Named + 'static {}
#[derive(Clone)]
pub struct ChannelSettings {
pub mode: ChannelMode,
pub direction: ChannelDirection,
pub criticality: ChannelCriticality,
}
impl ChannelSettings {
pub fn new(mode: ChannelMode, direction: ChannelDirection) -> Self {
if mode.tick_buffered() && direction != ChannelDirection::ClientToServer {
panic!("TickBuffered Messages are only allowed to be sent from Client to Server");
}
let criticality = ChannelCriticality::default_for(&mode);
Self {
mode,
direction,
criticality,
}
}
pub fn with_criticality(mut self, criticality: ChannelCriticality) -> Self {
self.criticality = criticality;
self
}
pub fn reliable(&self) -> bool {
match &self.mode {
ChannelMode::UnorderedUnreliable => false,
ChannelMode::SequencedUnreliable => false,
ChannelMode::UnorderedReliable(_) => true,
ChannelMode::SequencedReliable(_) => true,
ChannelMode::OrderedReliable(_) => true,
ChannelMode::TickBuffered(_) => false,
}
}
pub fn tick_buffered(&self) -> bool {
self.mode.tick_buffered()
}
pub fn can_send_to_server(&self) -> bool {
match &self.direction {
ChannelDirection::ClientToServer => true,
ChannelDirection::ServerToClient => false,
ChannelDirection::Bidirectional => true,
}
}
pub fn can_send_to_client(&self) -> bool {
match &self.direction {
ChannelDirection::ClientToServer => false,
ChannelDirection::ServerToClient => true,
ChannelDirection::Bidirectional => true,
}
}
pub fn can_request_and_respond(&self) -> bool {
self.reliable() && self.can_send_to_server() && self.can_send_to_client()
}
}
#[derive(Clone)]
pub struct ReliableSettings {
pub rtt_resend_factor: f32,
pub max_messages_per_tick: Option<u16>,
pub max_queue_depth: Option<usize>,
}
impl ReliableSettings {
pub const fn default() -> Self {
Self {
rtt_resend_factor: 1.5,
max_messages_per_tick: None,
max_queue_depth: Some(1024),
}
}
}
#[derive(Clone)]
pub struct TickBufferSettings {
pub message_capacity: usize,
}
impl TickBufferSettings {
pub const fn default() -> Self {
Self {
message_capacity: 64,
}
}
}
#[derive(Clone)]
pub enum ChannelMode {
UnorderedUnreliable,
SequencedUnreliable,
UnorderedReliable(ReliableSettings),
SequencedReliable(ReliableSettings),
OrderedReliable(ReliableSettings),
TickBuffered(TickBufferSettings),
}
impl ChannelMode {
pub fn tick_buffered(&self) -> bool {
matches!(self, ChannelMode::TickBuffered(_))
}
}
#[derive(Clone, Eq, PartialEq)]
pub enum ChannelDirection {
ClientToServer,
ServerToClient,
Bidirectional,
}
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum ChannelCriticality {
Low,
Normal,
High,
}
impl ChannelCriticality {
pub const fn default_for(mode: &ChannelMode) -> Self {
match mode {
ChannelMode::TickBuffered(_) => ChannelCriticality::High,
_ => ChannelCriticality::Normal,
}
}
pub const fn base_gain(&self) -> f32 {
match self {
ChannelCriticality::Low => 0.5,
ChannelCriticality::Normal => 1.0,
ChannelCriticality::High => 10.0,
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn with_criticality_overrides_mode_default() {
let s = ChannelSettings::new(
ChannelMode::UnorderedReliable(ReliableSettings::default()),
ChannelDirection::Bidirectional,
);
assert_eq!(s.criticality, ChannelCriticality::Normal);
let s2 = s.with_criticality(ChannelCriticality::Low);
assert_eq!(s2.criticality, ChannelCriticality::Low);
assert!((s2.criticality.base_gain() - 0.5).abs() < f32::EPSILON);
}
#[test]
fn tick_buffered_defaults_to_high() {
let s = ChannelSettings::new(
ChannelMode::TickBuffered(TickBufferSettings::default()),
ChannelDirection::ClientToServer,
);
assert_eq!(s.criticality, ChannelCriticality::High);
assert!((s.criticality.base_gain() - 10.0).abs() < f32::EPSILON);
}
#[test]
fn unreliable_defaults_to_normal() {
let s = ChannelSettings::new(
ChannelMode::UnorderedUnreliable,
ChannelDirection::Bidirectional,
);
assert_eq!(s.criticality, ChannelCriticality::Normal);
}
#[test]
fn base_gain_ordering() {
let high = ChannelCriticality::High.base_gain();
let normal = ChannelCriticality::Normal.base_gain();
let low = ChannelCriticality::Low.base_gain();
assert!(high > normal);
assert!(normal > low);
}
}