mod business_logic_layer;
mod data_access_layer;
mod entities;
use crate::business_logic_layer as bll;
pub use crate::data_access_layer::MAX_DATAGRAM_SIZE;
use crate::data_access_layer::{TypedClientSocket, TypedServerSocket};
pub use crate::entities::Exception;
use std::collections::HashMap;
use std::net::{SocketAddr, ToSocketAddrs};
use std::time::Duration;
#[derive(Debug)]
pub enum ServerEvent {
ExceptionOnRecv(Exception),
ExceptionOnSend((SocketAddr, Exception)),
}
pub type ContinueRunning = bool;
pub trait Game {
fn handle_command(
&mut self,
delta_time: Duration,
commands: Vec<Vec<u8>>,
from: SocketAddr,
) -> ContinueRunning;
fn draw(&mut self, delta_time: Duration) -> Vec<u8>;
fn allow_connect(&mut self, _from: &SocketAddr) -> bool {
true
}
fn handle_server_event(&mut self, _event: ServerEvent) -> ContinueRunning {
true
}
fn add_client(&mut self) -> Option<SocketAddr> {
None
}
fn remove_client(&mut self) -> Option<SocketAddr> {
None
}
}
pub struct ClientSocket {
socket: TypedClientSocket,
client: bll::Client,
}
impl ClientSocket {
pub fn new(port: u16, server_address: impl ToSocketAddrs) -> Result<ClientSocket, Exception> {
Ok(ClientSocket {
socket: TypedClientSocket::new(port, server_address)?,
client: bll::Client::new(),
})
}
pub fn send(&mut self, command: Vec<u8>) -> Result<usize, Exception> {
let command = self.client.send(command);
self.socket.write(&command)
}
pub fn recv(&mut self) -> Result<Vec<u8>, Exception> {
let state = self.socket.read()?;
let (state, lost) = self.client.recv(state)?;
for command in lost {
self.socket.write(&command)?;
}
Ok(state)
}
}
struct ServerSocket {
socket: TypedServerSocket,
servers: HashMap<SocketAddr, bll::Server>,
}
impl ServerSocket {
pub fn new(port: u16) -> Result<ServerSocket, Exception> {
Ok(ServerSocket {
socket: TypedServerSocket::new(port)?,
servers: HashMap::new(),
})
}
pub fn recv(&mut self) -> Result<(Vec<Vec<u8>>, SocketAddr), Exception> {
let (command, from) = self.socket.read()?;
self.add(&from);
let command = self.servers.get_mut(&from).unwrap().recv(command)?;
Ok((command, from))
}
pub fn remove(&mut self, client: &SocketAddr) {
self.servers.remove(&client);
}
pub fn add(&mut self, client: &SocketAddr) {
if !self.servers.contains_key(client) {
self.servers.insert(client.clone(), bll::Server::new());
}
}
pub fn send_to_all(&mut self, state: Vec<u8>) -> Vec<(SocketAddr, Exception)> {
let mut exceptions = Vec::new();
for (a, s) in &mut self.servers {
let _ = self
.socket
.write(a, &s.send(state.clone()))
.map_err(|e| exceptions.push((*a, e)));
}
exceptions
}
}
const DRAW_PERIOD_IN_MILLIS: u64 = 30;
pub struct GameServer<T: Game> {
game: T,
socket: ServerSocket,
is_running: bool,
draw_timer: bll::timer::WaitTimer,
update_timer: bll::timer::ElapsedTimer,
after_draw_elapsed_timer: bll::timer::ElapsedTimer,
}
impl<T: Game> GameServer<T> {
pub fn new(game: T, port: u16) -> Result<GameServer<T>, Exception> {
Ok(GameServer {
game,
socket: ServerSocket::new(port)?,
is_running: true,
draw_timer: bll::timer::WaitTimer::new(DRAW_PERIOD_IN_MILLIS),
update_timer: bll::timer::ElapsedTimer::new(),
after_draw_elapsed_timer: bll::timer::ElapsedTimer::new(),
})
}
pub fn run(&mut self) {
while self.is_running {
self.update();
self.draw()
}
}
fn draw(&mut self) {
if self.draw_timer.continue_execution() {
let state = self.game.draw(self.after_draw_elapsed_timer.elapsed());
if state.is_empty() {
return;
}
self.game.add_client().map(|a| self.socket.add(&a));
self.game.remove_client().map(|a| self.socket.remove(&a));
self.is_running &= self
.socket
.send_to_all(state)
.into_iter()
.map(|ex| {
self.game
.handle_server_event(ServerEvent::ExceptionOnSend(ex))
})
.all(|b| b);
}
}
fn update(&mut self) {
let _ = self
.socket
.recv()
.map(|(commands, from)| {
if self.game.allow_connect(&from) {
self.is_running &=
self.game
.handle_command(self.update_timer.elapsed(), commands, from);
} else {
self.socket.remove(&from);
}
})
.map_err(|e| {
self.is_running &= self
.game
.handle_server_event(ServerEvent::ExceptionOnRecv(e))
});
}
}