protocol id

This commit is contained in:
griffi-gh 2023-02-13 01:53:55 +01:00
parent a5b35ffa7d
commit 6b9243a556
12 changed files with 106 additions and 44 deletions

View file

@ -1,3 +1,4 @@
[server] [server]
address = "0.0.0.0:12345" address = "0.0.0.0:12345"
max_clients = 254 max_clients = 254
timeout_ms = 10000

View file

@ -6,6 +6,7 @@ use std::{fs, net::SocketAddr};
pub struct ConfigTableServer { pub struct ConfigTableServer {
pub address: SocketAddr, pub address: SocketAddr,
pub max_clients: usize, pub max_clients: usize,
pub timeout_ms: u64,
} }
#[derive(Unique, Serialize, Deserialize)] #[derive(Unique, Serialize, Deserialize)]

View file

@ -1,6 +1,7 @@
use shipyard::{AllStoragesView, Unique, UniqueView, UniqueViewMut}; use shipyard::{AllStoragesView, Unique, UniqueView, UniqueViewMut};
use kubi_udp::server::{Server, ServerConfig}; use kubi_udp::server::{Server, ServerConfig};
use kubi_shared::networking::messages::{ClientToServerMessage, ServerToClientMessage}; use kubi_shared::networking::messages::{ClientToServerMessage, ServerToClientMessage};
use std::time::Duration;
use crate::config::ConfigTable; use crate::config::ConfigTable;
#[derive(Unique)] #[derive(Unique)]
@ -14,7 +15,11 @@ pub fn bind_server(
let config = storages.borrow::<UniqueView<ConfigTable>>().unwrap(); let config = storages.borrow::<UniqueView<ConfigTable>>().unwrap();
let server: Server<ServerToClientMessage, ClientToServerMessage> = Server::bind( let server: Server<ServerToClientMessage, ClientToServerMessage> = Server::bind(
config.server.address, config.server.address,
ServerConfig { max_clients: config.server.max_clients } ServerConfig {
max_clients: config.server.max_clients,
client_timeout: Duration::from_millis(config.server.timeout_ms),
..Default::default()
}
).unwrap(); ).unwrap();
storages.add_unique(UdpServer(server)); storages.add_unique(UdpServer(server));
} }

View file

@ -5,7 +5,9 @@ type IVec3Arr = [i32; 3];
type Vec3Arr = [f32; 3]; type Vec3Arr = [f32; 3];
type QuatArr = [f32; 3]; type QuatArr = [f32; 3];
#[derive(Encode, Decode)] pub const PROTOCOL_ID: u16 = 1;
#[derive(Encode, Decode, Clone)]
pub enum ClientToServerMessage { pub enum ClientToServerMessage {
ClientHello { ClientHello {
username: String, username: String,
@ -21,7 +23,7 @@ pub enum ClientToServerMessage {
}, },
} }
#[derive(Encode, Decode)] #[derive(Encode, Decode, Clone)]
pub enum ServerToClientMessage { pub enum ServerToClientMessage {
ServerHello, ServerHello,
ServerFuckOff { ServerFuckOff {

View file

@ -6,11 +6,10 @@ use std::{
collections::{VecDeque, vec_deque::Drain as DrainDeque}, collections::{VecDeque, vec_deque::Drain as DrainDeque},
io::ErrorKind, io::ErrorKind,
}; };
use bincode::{Encode, Decode};
use crate::{ use crate::{
BINCODE_CONFIG, BINCODE_CONFIG,
packet::{ClientPacket, IdClientPacket, IdServerPacket, ServerPacket}, packet::{ClientPacket, IdClientPacket, IdServerPacket, ServerPacket, Message},
common::ClientId common::{ClientId, PROTOCOL_ID, DEFAULT_USER_PROTOCOL_ID}
}; };
#[derive(Default, Clone, Debug)] #[derive(Default, Clone, Debug)]
@ -22,6 +21,7 @@ pub enum DisconnectReason {
KickedByServer(Option<String>), KickedByServer(Option<String>),
Timeout, Timeout,
ConnectionReset, ConnectionReset,
InvalidProtocolId,
} }
#[derive(Clone, Copy, Debug, PartialEq, Eq)] #[derive(Clone, Copy, Debug, PartialEq, Eq)]
@ -33,25 +33,27 @@ pub enum ClientStatus {
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub struct ClientConfig { pub struct ClientConfig {
pub protocol_id: u16,
pub timeout: Duration, pub timeout: Duration,
pub heartbeat_interval: Duration, pub heartbeat_interval: Duration,
} }
impl Default for ClientConfig { impl Default for ClientConfig {
fn default() -> Self { fn default() -> Self {
Self { Self {
protocol_id: DEFAULT_USER_PROTOCOL_ID,
timeout: Duration::from_secs(5), timeout: Duration::from_secs(5),
heartbeat_interval: Duration::from_secs(3), heartbeat_interval: Duration::from_secs(3),
} }
} }
} }
pub enum ClientEvent<T> where T: Encode + Decode { pub enum ClientEvent<T> where T: Message {
Connected(ClientId), Connected(ClientId),
Disconnected(DisconnectReason), Disconnected(DisconnectReason),
MessageReceived(T) MessageReceived(T)
} }
pub struct Client<S, R> where S: Encode + Decode, R: Encode + Decode { pub struct Client<S, R> where S: Message, R: Message {
config: ClientConfig, config: ClientConfig,
addr: SocketAddr, addr: SocketAddr,
socket: UdpSocket, socket: UdpSocket,
@ -63,9 +65,15 @@ pub struct Client<S, R> where S: Encode + Decode, R: Encode + Decode {
event_queue: VecDeque<ClientEvent<R>>, event_queue: VecDeque<ClientEvent<R>>,
_s: PhantomData<S>, _s: PhantomData<S>,
} }
impl<S, R> Client<S, R> where S: Encode + Decode, R: Encode + Decode { impl<S, R> Client<S, R> where S: Message, R: Message {
#[inline] #[inline]
pub fn new(addr: SocketAddr, config: ClientConfig) -> Result<Self> { pub fn new(addr: SocketAddr, config: ClientConfig) -> Result<Self> {
if config.protocol_id == 0 {
log::warn!("Warning: using 0 as protocol_id is not recommended");
}
if config.protocol_id == DEFAULT_USER_PROTOCOL_ID {
log::warn!("Warning: using default protocol_id is not recommended");
}
let bind_addr: SocketAddr = "0.0.0.0:0".parse().unwrap(); let bind_addr: SocketAddr = "0.0.0.0:0".parse().unwrap();
let socket = UdpSocket::bind(bind_addr)?; let socket = UdpSocket::bind(bind_addr)?;
socket.set_nonblocking(true)?; socket.set_nonblocking(true)?;
@ -107,7 +115,7 @@ impl<S, R> Client<S, R> where S: Encode + Decode, R: Encode + Decode {
#[inline] #[inline]
pub fn connect(&mut self) -> Result<()> { pub fn connect(&mut self) -> Result<()> {
log::info!("client connect called"); log::info!("Client connecting..");
if self.status != ClientStatus::Disconnected { if self.status != ClientStatus::Disconnected {
bail!("Not Disconnected"); bail!("Not Disconnected");
} }
@ -115,7 +123,10 @@ impl<S, R> Client<S, R> where S: Encode + Decode, R: Encode + Decode {
self.last_heartbeat = Instant::now(); self.last_heartbeat = Instant::now();
self.reset_timeout(); self.reset_timeout();
self.socket.connect(self.addr)?; self.socket.connect(self.addr)?;
self.send_raw_packet(ClientPacket::Connect)?; self.send_raw_packet(ClientPacket::Connect{
user_protocol: self.config.protocol_id,
inner_protocol: PROTOCOL_ID,
})?;
Ok(()) Ok(())
} }
@ -216,6 +227,15 @@ impl<S, R> Client<S, R> where S: Encode + Decode, R: Encode + Decode {
}, },
ServerPacket::Data(message) => { ServerPacket::Data(message) => {
self.event_queue.push_back(ClientEvent::MessageReceived(message)); self.event_queue.push_back(ClientEvent::MessageReceived(message));
self.timeout = Instant::now();
},
ServerPacket::Heartbeat => {
self.timeout = Instant::now();
},
ServerPacket::ProtoDisconnect => {
let reason = DisconnectReason::InvalidProtocolId;
self.disconnect_inner(reason, true)?; //this should never fail but we're handling the error anyway
return Ok(());
} }
} }
}, },

View file

@ -3,3 +3,6 @@ use std::num::NonZeroU8;
pub type ClientId = NonZeroU8; pub type ClientId = NonZeroU8;
pub type ClientIdRepr = u8; pub type ClientIdRepr = u8;
pub const MAX_CLIENTS: usize = u8::MAX as _; pub const MAX_CLIENTS: usize = u8::MAX as _;
pub const PROTOCOL_ID: u16 = 1;
pub const DEFAULT_USER_PROTOCOL_ID: u16 = 0xcafe;

View file

@ -1,25 +1,33 @@
use bincode::{Encode, Decode}; use bincode::{Encode, Decode};
use crate::common::ClientId; use crate::common::ClientId;
pub trait Message: Encode + Decode + Clone {}
impl<T: Encode + Decode + Clone> Message for T {}
#[repr(u8)] #[repr(u8)]
#[derive(Encode, Decode)] #[derive(Encode, Decode)]
pub enum ClientPacket<T> where T: Encode + Decode { pub enum ClientPacket<T> where T: Message {
Connect {
inner_protocol: u16,
user_protocol: u16,
}, //should always stay 0!
Data(T), Data(T),
Connect,
Disconnect, Disconnect,
Heartbeat, Heartbeat,
} }
#[derive(Encode, Decode)] #[derive(Encode, Decode)]
pub struct IdClientPacket<T: Encode + Decode>(pub Option<ClientId>, pub ClientPacket<T>); pub struct IdClientPacket<T: Message>(pub Option<ClientId>, pub ClientPacket<T>);
#[repr(u8)] #[repr(u8)]
#[derive(Encode, Decode)] #[derive(Encode, Decode)]
pub enum ServerPacket<T> where T: Encode + Decode { pub enum ServerPacket<T> where T: Message {
ProtoDisconnect = 0,
Data(T), Data(T),
Connected(ClientId),
Disconnected(String), Disconnected(String),
Connected(ClientId),
Heartbeat,
} }
#[derive(Encode, Decode)] #[derive(Encode, Decode)]
pub struct IdServerPacket<T: Encode + Decode>(pub Option<ClientId>, pub ServerPacket<T>); pub struct IdServerPacket<T: Message>(pub Option<ClientId>, pub ServerPacket<T>);

View file

@ -1,18 +1,17 @@
use std::{ use std::{
net::{UdpSocket, SocketAddr}, net::{UdpSocket, SocketAddr},
time::Instant, time::{Instant, Duration},
marker::PhantomData, marker::PhantomData,
collections::{VecDeque, vec_deque::Drain as DrainDeque}, collections::{VecDeque, vec_deque::Drain as DrainDeque},
io::ErrorKind io::ErrorKind
}; };
use anyhow::{Result, bail}; use anyhow::{Result, bail};
use bincode::{Encode, Decode};
use hashbrown::HashMap; use hashbrown::HashMap;
use nohash_hasher::BuildNoHashHasher; use nohash_hasher::BuildNoHashHasher;
use crate::{ use crate::{
BINCODE_CONFIG, BINCODE_CONFIG,
common::{ClientId, ClientIdRepr, MAX_CLIENTS}, common::{ClientId, ClientIdRepr, MAX_CLIENTS, PROTOCOL_ID, DEFAULT_USER_PROTOCOL_ID},
packet::{IdClientPacket, ClientPacket, ServerPacket, IdServerPacket} packet::{IdClientPacket, ClientPacket, ServerPacket, IdServerPacket, Message}
}; };
//i was feeling a bit sick while writing most of this please excuse me for my terrible code :3 //i was feeling a bit sick while writing most of this please excuse me for my terrible code :3
@ -26,16 +25,20 @@ pub struct ConnectedClient {
#[derive(Clone, Copy, Debug)] #[derive(Clone, Copy, Debug)]
pub struct ServerConfig { pub struct ServerConfig {
pub max_clients: usize, pub max_clients: usize,
pub client_timeout: Duration,
pub protocol_id: u16,
} }
impl Default for ServerConfig { impl Default for ServerConfig {
fn default() -> Self { fn default() -> Self {
Self { Self {
max_clients: MAX_CLIENTS, max_clients: MAX_CLIENTS,
client_timeout: Duration::from_secs(5),
protocol_id: DEFAULT_USER_PROTOCOL_ID,
} }
} }
} }
pub enum ServerEvent<T> where T: Encode + Decode { pub enum ServerEvent<T> where T: Message {
Connected(ClientId), Connected(ClientId),
Disconnected(ClientId), Disconnected(ClientId),
MessageReceived { MessageReceived {
@ -44,16 +47,22 @@ pub enum ServerEvent<T> where T: Encode + Decode {
} }
} }
pub struct Server<S, R> where S: Encode + Decode, R: Encode + Decode { pub struct Server<S, R> where S: Message, R: Message {
socket: UdpSocket, socket: UdpSocket,
clients: HashMap<ClientId, ConnectedClient, BuildNoHashHasher<ClientIdRepr>>, clients: HashMap<ClientId, ConnectedClient, BuildNoHashHasher<ClientIdRepr>>,
config: ServerConfig, config: ServerConfig,
event_queue: VecDeque<ServerEvent<R>>, event_queue: VecDeque<ServerEvent<R>>,
_s: PhantomData<S>, _s: PhantomData<S>,
} }
impl<S, R> Server<S, R> where S: Encode + Decode, R: Encode + Decode { impl<S, R> Server<S, R> where S: Message, R: Message {
pub fn bind(addr: SocketAddr, config: ServerConfig) -> anyhow::Result<Self> { pub fn bind(addr: SocketAddr, config: ServerConfig) -> anyhow::Result<Self> {
assert!(config.max_clients <= MAX_CLIENTS); assert!(config.max_clients <= MAX_CLIENTS, "max_clients value exceeds the maximum allowed amount of clients");
if config.protocol_id == 0 {
log::warn!("Warning: using 0 as protocol_id is not recommended");
}
if config.protocol_id == DEFAULT_USER_PROTOCOL_ID {
log::warn!("Warning: using default protocol_id is not recommended");
}
let socket = UdpSocket::bind(addr)?; let socket = UdpSocket::bind(addr)?;
socket.set_nonblocking(true)?; socket.set_nonblocking(true)?;
Ok(Self { Ok(Self {
@ -127,6 +136,12 @@ impl<S, R> Server<S, R> where S: Encode + Decode, R: Encode + Decode {
self.send_packet(IdServerPacket(Some(id), ServerPacket::Data(message)))?; self.send_packet(IdServerPacket(Some(id), ServerPacket::Data(message)))?;
Ok(()) Ok(())
} }
pub fn multicast_message(&mut self, _clients: impl IntoIterator<Item = ClientId>, _message: S) {
todo!()
}
pub fn broadcast_message(&mut self, _message: S) -> anyhow::Result<()> {
todo!()
}
pub fn update(&mut self) -> Result<()> { pub fn update(&mut self) -> Result<()> {
//TODO client timeout //TODO client timeout
@ -141,7 +156,10 @@ impl<S, R> Server<S, R> where S: Encode + Decode, R: Encode + Decode {
Some(id) => { Some(id) => {
if !self.clients.contains_key(&id) { if !self.clients.contains_key(&id) {
bail!("Client with id {id} doesn't exist"); bail!("Client with id {id} doesn't exist");
}; }
if self.clients.get(&id).unwrap().addr != addr {
bail!("Client addr doesn't match");
}
match packet { match packet {
ClientPacket::Data(data) => { ClientPacket::Data(data) => {
self.event_queue.push_back(ServerEvent::MessageReceived { self.event_queue.push_back(ServerEvent::MessageReceived {
@ -155,21 +173,30 @@ impl<S, R> Server<S, R> where S: Encode + Decode, R: Encode + Decode {
self.disconnect_client_inner(id, "Disconnected".into())?; self.disconnect_client_inner(id, "Disconnected".into())?;
}, },
ClientPacket::Heartbeat => { ClientPacket::Heartbeat => {
self.clients.get_mut(&id).unwrap().timeout = Instant::now() self.clients.get_mut(&id).unwrap().timeout = Instant::now();
self.send_packet(IdServerPacket(Some(id), ServerPacket::Heartbeat))?;
}, },
ClientPacket::Connect => bail!("Client already connected"), ClientPacket::Connect{..} => bail!("Client already connected"),
} }
}, },
None => { None => {
match packet { match packet {
ClientPacket::Connect => { ClientPacket::Connect { user_protocol, inner_protocol } => {
if (inner_protocol != PROTOCOL_ID) || (user_protocol != self.config.protocol_id ) {
log::error!("Client conenction refused: Invalid protocol id");
self.send_to_addr(addr,
IdServerPacket(None, ServerPacket::ProtoDisconnect)
)?;
continue;
}
match self.add_client(addr) { match self.add_client(addr) {
Ok(id) => { Ok(id) => {
log::info!("Client with id {id} connected"); log::info!("Client with id {id} connected");
self.event_queue.push_back(ServerEvent::Connected(id)); self.event_queue.push_back(ServerEvent::Connected(id));
self.send_to_addr(addr, self.send_to_addr(addr,
IdServerPacket(None, ServerPacket::Connected(id) IdServerPacket(None, ServerPacket::Connected(id))
))?; )?;
}, },
Err(error) => { Err(error) => {
let reason = error.to_string(); let reason = error.to_string();

View file

@ -1,11 +1,11 @@
use shipyard::{Component, Unique, Workload, IntoWorkload, AllStoragesView, AllStoragesViewMut, View, UniqueView, NonSendSync, UniqueViewMut, IntoIter}; use shipyard::{Component, Unique, Workload, IntoWorkload, AllStoragesView, View, UniqueViewMut, IntoIter};
use glam::{Vec4, Mat3, vec2, Mat4}; use glam::{Vec4, Mat4};
use crate::{color::color_hex, transform::Transform2d, events::WindowResizedEvent, rendering::Renderer}; use crate::{color::color_hex, events::WindowResizedEvent};
pub mod text_widget; pub mod text_widget;
pub mod progressbar; pub mod progressbar;
use progressbar::{render_progressbars, ProgressbarComponent}; use progressbar::render_progressbars;
//TODO compute gui scale on window resize //TODO compute gui scale on window resize
#[derive(Unique, Clone, Copy, Debug, Default)] #[derive(Unique, Clone, Copy, Debug, Default)]

View file

@ -1,5 +1,5 @@
use shipyard::{AllStoragesViewMut, UniqueViewMut}; use shipyard::{AllStoragesViewMut, UniqueViewMut};
use std::{env, net::SocketAddr, borrow::BorrowMut}; use std::{env, net::SocketAddr};
use crate::{ use crate::{
networking::{GameType, ServerAddress}, networking::{GameType, ServerAddress},
state::{GameState, NextState} state::{GameState, NextState}

View file

@ -47,7 +47,7 @@ fn update_progress_bar_progress (
) { ) {
let bar = (&mut bar).get(eid.0).unwrap(); let bar = (&mut bar).get(eid.0).unwrap();
let loaded = world.chunks.iter().fold(0, |acc, (&_, chunk)| { let loaded = world.chunks.iter().fold(0, |acc, (&_, chunk)| {
acc + chunk.desired_state.matches(chunk.current_state) as usize acc + chunk.desired_state.matches_current(chunk.current_state) as usize
}); });
let total = world.chunks.len(); let total = world.chunks.len();
let progress = loaded as f32 / total as f32; let progress = loaded as f32 / total as f32;
@ -62,7 +62,7 @@ fn switch_to_ingame_if_loaded(
return return
} }
if world.chunks.iter().all(|(_, chunk)| { if world.chunks.iter().all(|(_, chunk)| {
chunk.desired_state.matches(chunk.current_state) chunk.desired_state.matches_current(chunk.current_state)
}) { }) {
log::info!("Finished loading chunks"); log::info!("Finished loading chunks");
state.0 = Some(GameState::InGame); state.0 = Some(GameState::InGame);

View file

@ -30,11 +30,6 @@ pub enum CurrentChunkState {
RecalculatingMesh, RecalculatingMesh,
Unloading, Unloading,
} }
impl CurrentChunkState {
pub fn matches(self, desired: DesiredChunkState) -> bool {
desired.matches(self)
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default)] #[derive(Clone, Copy, Debug, PartialEq, Eq, Default)]
pub enum DesiredChunkState { pub enum DesiredChunkState {
@ -45,7 +40,7 @@ pub enum DesiredChunkState {
ToUnload, ToUnload,
} }
impl DesiredChunkState { impl DesiredChunkState {
pub fn matches(self, current: CurrentChunkState) -> bool { pub fn matches_current(self, current: CurrentChunkState) -> bool {
(matches!(self, DesiredChunkState::Nothing) && matches!(current, CurrentChunkState::Nothing)) || (matches!(self, DesiredChunkState::Nothing) && matches!(current, CurrentChunkState::Nothing)) ||
(matches!(self, DesiredChunkState::Loaded) && matches!(current, CurrentChunkState::Loaded)) || (matches!(self, DesiredChunkState::Loaded) && matches!(current, CurrentChunkState::Loaded)) ||
(matches!(self, DesiredChunkState::Rendered) && matches!(current, CurrentChunkState::Rendered)) (matches!(self, DesiredChunkState::Rendered) && matches!(current, CurrentChunkState::Rendered))