From 8d200b816e333f62355a5528b2c52a8f21f790aa Mon Sep 17 00:00:00 2001 From: Paul Bellchambers Date: Wed, 13 Jul 2022 18:27:15 +0100 Subject: [PATCH] feat: large data transfers (#74) * feat: initial commit to enable large map data * chore: update dependencies * chore: refactoring and tidying of messaging code --- Cargo.lock | 7 +- rustyhack_client/Cargo.toml | 5 +- rustyhack_client/src/game.rs | 5 +- .../src/game/commands/look_command.rs | 2 +- rustyhack_client/src/game/input_handler.rs | 2 +- rustyhack_client/src/game/map_handler.rs | 53 ++++++-- rustyhack_client/src/game/new_player.rs | 14 +-- rustyhack_client/src/game/updates_handler.rs | 14 +-- .../src/networking/message_handler.rs | 45 +++---- rustyhack_client/src/screens.rs | 2 +- rustyhack_client/src/screens/viewport.rs | 2 +- rustyhack_lib/Cargo.toml | 4 +- rustyhack_lib/src/background_map.rs | 2 + rustyhack_lib/src/message_handler.rs | 2 +- .../{player_message.rs => messages.rs} | 15 ++- rustyhack_server/Cargo.toml | 4 +- rustyhack_server/src/game/monsters.rs | 2 +- rustyhack_server/src/game/player_updates.rs | 29 +++-- rustyhack_server/src/game/spawns.rs | 2 +- rustyhack_server/src/networking.rs | 1 - .../src/networking/message_handler.rs | 116 +++++++++++++----- 21 files changed, 211 insertions(+), 117 deletions(-) rename rustyhack_lib/src/message_handler/{player_message.rs => messages.rs} (77%) diff --git a/Cargo.lock b/Cargo.lock index 713e221..5243831 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -572,13 +572,14 @@ checksum = "a0a5f7c728f5d284929a1cccb5bc19884422bfe6ef4d6c409da2c41838983fcf" [[package]] name = "rustyhack_client" -version = "0.2.1" +version = "0.2.2" dependencies = [ "bincode", "chrono", "console_engine", "crossbeam-channel", "crossterm", + "itertools", "laminar", "log", "regex", @@ -589,7 +590,7 @@ dependencies = [ [[package]] name = "rustyhack_lib" -version = "0.2.1" +version = "0.2.2" dependencies = [ "console_engine", "crossterm", @@ -603,7 +604,7 @@ dependencies = [ [[package]] name = "rustyhack_server" -version = "0.2.1" +version = "0.2.2" dependencies = [ "bincode", "console_engine", diff --git a/rustyhack_client/Cargo.toml b/rustyhack_client/Cargo.toml index f338d4e..7aa0427 100644 --- a/rustyhack_client/Cargo.toml +++ b/rustyhack_client/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustyhack_client" -version = "0.2.1" +version = "0.2.2" authors = ["pbellchambers "] edition = "2021" repository = "https://github.com/pbellchambers/rustyhack-mmo" @@ -16,7 +16,8 @@ console_engine = "2.4.0" crossterm = { version = "0.23.2", features = ["serde"] } laminar = "0.5.0" crossbeam-channel = "0.5.5" -serde = { version = "1.0.138", features = ["derive"] } +serde = { version = "1.0.139", features = ["derive"] } bincode = "1.3.3" regex = "1.6.0" chrono = "0.4.19" +itertools = "0.10.3" diff --git a/rustyhack_client/src/game.rs b/rustyhack_client/src/game.rs index 9e5ed4f..3da016e 100644 --- a/rustyhack_client/src/game.rs +++ b/rustyhack_client/src/game.rs @@ -3,7 +3,7 @@ use crossbeam_channel::{Receiver, Sender}; use laminar::{Packet, SocketEvent}; use std::collections::HashMap; -use rustyhack_lib::message_handler::player_message::EntityUpdates; +use rustyhack_lib::message_handler::messages::EntityUpdates; use crate::consts::{CONSOLE_HEIGHT, CONSOLE_WIDTH, GAME_TITLE, TARGET_FPS}; use crate::networking::message_handler; @@ -48,8 +48,7 @@ pub(crate) fn run( ); //initialise console engine - let mut console = - console_engine::ConsoleEngine::init(CONSOLE_WIDTH, CONSOLE_HEIGHT, TARGET_FPS).unwrap(); + let mut console = ConsoleEngine::init(CONSOLE_WIDTH, CONSOLE_HEIGHT, TARGET_FPS).unwrap(); console.set_title(GAME_TITLE); info!("Initialised console engine."); diff --git a/rustyhack_client/src/game/commands/look_command.rs b/rustyhack_client/src/game/commands/look_command.rs index 3879035..9f738c6 100644 --- a/rustyhack_client/src/game/commands/look_command.rs +++ b/rustyhack_client/src/game/commands/look_command.rs @@ -1,7 +1,7 @@ use chrono::{DateTime, Local}; use rustyhack_lib::background_map::AllMaps; use rustyhack_lib::ecs::player::Player; -use rustyhack_lib::message_handler::player_message::EntityUpdates; +use rustyhack_lib::message_handler::messages::EntityUpdates; pub(crate) fn get_what_player_sees( status_messages: &mut Vec, diff --git a/rustyhack_client/src/game/input_handler.rs b/rustyhack_client/src/game/input_handler.rs index 6ddb842..e323f21 100644 --- a/rustyhack_client/src/game/input_handler.rs +++ b/rustyhack_client/src/game/input_handler.rs @@ -2,7 +2,7 @@ use crate::game::commands; use console_engine::{ConsoleEngine, KeyCode}; use rustyhack_lib::background_map::AllMaps; use rustyhack_lib::ecs::player::Player; -use rustyhack_lib::message_handler::player_message::EntityUpdates; +use rustyhack_lib::message_handler::messages::EntityUpdates; pub(crate) fn handle_other_input( console: &mut ConsoleEngine, diff --git a/rustyhack_client/src/game/map_handler.rs b/rustyhack_client/src/game/map_handler.rs index 6def22d..853c828 100644 --- a/rustyhack_client/src/game/map_handler.rs +++ b/rustyhack_client/src/game/map_handler.rs @@ -1,9 +1,10 @@ use crate::networking::message_handler; -use bincode::serialize; +use bincode::{deserialize, serialize}; use crossbeam_channel::{Receiver, Sender}; +use itertools::Itertools; use laminar::Packet; -use rustyhack_lib::background_map::AllMaps; -use rustyhack_lib::message_handler::player_message::{PlayerMessage, PlayerReply}; +use rustyhack_lib::background_map::{AllMaps, BackgroundMap}; +use rustyhack_lib::message_handler::messages::{PlayerRequest, ServerMessage}; use std::collections::HashMap; use std::thread; use std::time::Duration; @@ -11,13 +12,14 @@ use std::time::Duration; pub(crate) fn request_all_maps_data( sender: &Sender, server_addr: &str, - channel_receiver: &Receiver, + channel_receiver: &Receiver, ) -> AllMaps { let get_all_maps_request_packet = Packet::reliable_ordered( server_addr .parse() .expect("Server address format is invalid."), - serialize(&PlayerMessage::GetAllMaps).expect("Error serialising GetAllMaps request."), + serialize(&PlayerRequest::GetChunkedAllMaps) + .expect("Error serializing GetAllMaps request."), Some(1), ); message_handler::send_packet(get_all_maps_request_packet, sender); @@ -25,17 +27,22 @@ pub(crate) fn request_all_maps_data( wait_for_all_maps_response(channel_receiver) } -fn wait_for_all_maps_response(channel_receiver: &Receiver) -> AllMaps { +fn wait_for_all_maps_response(channel_receiver: &Receiver) -> AllMaps { let mut all_maps_downloaded = false; let mut all_maps = HashMap::new(); + let mut all_maps_chunks = HashMap::new(); loop { let received = channel_receiver.recv(); if let Ok(received_message) = received { match received_message { - PlayerReply::AllMaps(message) => { - info!("All maps downloaded from server."); + ServerMessage::AllMapsChunk(message) => { + info!("All maps chunk received from server: {}", message.0); + all_maps_chunks.insert(message.0, message.1); + } + ServerMessage::AllMapsChunksComplete => { + info!("All maps chunks downloaded from server."); + all_maps = combine_all_maps_chunks(&all_maps_chunks); all_maps_downloaded = true; - all_maps = message; } _ => { info!( @@ -54,3 +61,31 @@ fn wait_for_all_maps_response(channel_receiver: &Receiver) -> AllMa debug!("All maps is: {:?}", all_maps); all_maps } + +fn combine_all_maps_chunks( + all_maps_chunks: &HashMap>, +) -> HashMap { + deserialize_all_maps_reply(combine_chunks(all_maps_chunks)) +} + +fn combine_chunks(all_maps_chunks: &HashMap>) -> Vec { + let mut combined_all_maps_chunks: Vec = Vec::new(); + for chunk in all_maps_chunks.keys().sorted() { + combined_all_maps_chunks.extend( + all_maps_chunks + .get(chunk) + .expect("Error combining all maps chunks on chunk."), + ); + } + combined_all_maps_chunks +} + +fn deserialize_all_maps_reply(combined_chunks: Vec) -> HashMap { + let deserialized_chunks = deserialize::(&combined_chunks) + .expect("Error deserializing combined all maps chunks."); + return if let ServerMessage::AllMaps(message) = deserialized_chunks { + message + } else { + panic!("Combined all maps chunks did not make a valid PlayerReply::AllMaps message"); + }; +} diff --git a/rustyhack_client/src/game/new_player.rs b/rustyhack_client/src/game/new_player.rs index 90e2d97..f29d7b4 100644 --- a/rustyhack_client/src/game/new_player.rs +++ b/rustyhack_client/src/game/new_player.rs @@ -3,9 +3,7 @@ use bincode::serialize; use crossbeam_channel::{Receiver, Sender}; use laminar::Packet; use rustyhack_lib::ecs::player::Player; -use rustyhack_lib::message_handler::player_message::{ - CreatePlayerMessage, PlayerMessage, PlayerReply, -}; +use rustyhack_lib::message_handler::messages::{CreatePlayerRequest, PlayerRequest, ServerMessage}; use std::time::Duration; use std::{process, thread}; @@ -14,13 +12,13 @@ pub(crate) fn send_new_player_request( player_name: &str, server_addr: &str, client_addr: &str, - channel_receiver: &Receiver, + channel_receiver: &Receiver, ) -> Player { let create_player_request_packet = Packet::reliable_unordered( server_addr .parse() .expect("Server address format is invalid."), - serialize(&PlayerMessage::PlayerJoin(CreatePlayerMessage { + serialize(&PlayerRequest::PlayerJoin(CreatePlayerRequest { client_addr: client_addr.to_string(), player_name: player_name.to_string(), })) @@ -31,19 +29,19 @@ pub(crate) fn send_new_player_request( wait_for_new_player_response(channel_receiver) } -fn wait_for_new_player_response(channel_receiver: &Receiver) -> Player { +fn wait_for_new_player_response(channel_receiver: &Receiver) -> Player { let mut new_player_confirmed = false; let mut player = Player::default(); loop { let received = channel_receiver.recv(); if let Ok(received_message) = received { match received_message { - PlayerReply::PlayerJoined(message) => { + ServerMessage::PlayerJoined(message) => { info!("New player creation confirmed."); new_player_confirmed = true; player = message; } - PlayerReply::PlayerAlreadyOnline => { + ServerMessage::PlayerAlreadyOnline => { error!( "This player name is already taken, and the player is currently online." ); diff --git a/rustyhack_client/src/game/updates_handler.rs b/rustyhack_client/src/game/updates_handler.rs index b090d3c..7d5aaf1 100644 --- a/rustyhack_client/src/game/updates_handler.rs +++ b/rustyhack_client/src/game/updates_handler.rs @@ -5,8 +5,8 @@ use crossbeam_channel::{Receiver, Sender}; use laminar::Packet; use rustyhack_lib::ecs::components::Velocity; use rustyhack_lib::ecs::player::Player; -use rustyhack_lib::message_handler::player_message::{ - EntityUpdates, PlayerMessage, PlayerReply, VelocityMessage, +use rustyhack_lib::message_handler::messages::{ + EntityUpdates, PlayerRequest, ServerMessage, VelocityMessage, }; pub(crate) fn send_player_updates( @@ -42,7 +42,7 @@ fn send_velocity_packet( server_addr .parse() .expect("Server address format is invalid."), - serialize(&PlayerMessage::UpdateVelocity(VelocityMessage { + serialize(&PlayerRequest::UpdateVelocity(VelocityMessage { player_name: player.player_details.player_name.clone(), velocity, })) @@ -54,7 +54,7 @@ fn send_velocity_packet( } pub(crate) fn check_for_received_player_updates( - channel_receiver: &Receiver, + channel_receiver: &Receiver, mut player: Player, ) -> Player { debug!("Checking for received player position from server."); @@ -62,7 +62,7 @@ pub(crate) fn check_for_received_player_updates( let received = channel_receiver.recv(); if let Ok(received_message) = received { match received_message { - PlayerReply::UpdatePosition(new_position) => { + ServerMessage::UpdatePosition(new_position) => { debug!("Player position update received: {:?}", &new_position); player.position = new_position } @@ -79,7 +79,7 @@ pub(crate) fn check_for_received_player_updates( } pub(crate) fn check_for_received_entity_updates( - channel_receiver: &Receiver, + channel_receiver: &Receiver, mut entity_updates: EntityUpdates, ) -> EntityUpdates { debug!("Checking for received entity updates from server."); @@ -87,7 +87,7 @@ pub(crate) fn check_for_received_entity_updates( let received = channel_receiver.recv(); if let Ok(received_message) = received { match received_message { - PlayerReply::UpdateOtherEntities(new_updates) => { + ServerMessage::UpdateOtherEntities(new_updates) => { debug!("Entity updates received: {:?}", &new_updates); entity_updates = new_updates; } diff --git a/rustyhack_client/src/networking/message_handler.rs b/rustyhack_client/src/networking/message_handler.rs index 68f733a..83a17a0 100644 --- a/rustyhack_client/src/networking/message_handler.rs +++ b/rustyhack_client/src/networking/message_handler.rs @@ -1,26 +1,23 @@ -use crate::networking::message_handler; use bincode::deserialize; use crossbeam_channel::{Receiver, Sender}; use laminar::{Packet, SocketEvent}; -use rustyhack_lib::message_handler::player_message::PlayerReply; +use rustyhack_lib::message_handler::messages::ServerMessage; use std::{process, thread}; pub(crate) fn spawn_message_handler_thread( sender: Sender, receiver: Receiver, - player_update_sender: Sender, - entity_update_sender: Sender, + player_update_sender: Sender, + entity_update_sender: Sender, ) { - thread::spawn(move || { - message_handler::run(sender, receiver, player_update_sender, entity_update_sender) - }); + thread::spawn(move || run(sender, receiver, player_update_sender, entity_update_sender)); } pub(crate) fn run( _sender: Sender, receiver: Receiver, - player_update_sender: Sender, - entity_update_sender: Sender, + player_update_sender: Sender, + entity_update_sender: Sender, ) { info!("Spawned message handler thread."); loop { @@ -32,12 +29,12 @@ pub(crate) fn run( let msg = packet.payload(); let address = packet.addr(); - let player_reply_result = deserialize::(msg); + let player_reply_result = deserialize::(msg); let player_reply = match player_reply_result { Ok(_) => player_reply_result.unwrap(), Err(error) => { warn!( - "Error when deserialising player reply packet from server: {}", + "Error when deserializing player reply packet from server: {}", error ); //try again with next packet @@ -47,20 +44,26 @@ pub(crate) fn run( debug!("Received {:?} from {:?}", player_reply, address); let channel_send_status = match player_reply { - PlayerReply::PlayerJoined(message) => { - player_update_sender.send(PlayerReply::PlayerJoined(message)) + ServerMessage::PlayerJoined(message) => { + player_update_sender.send(ServerMessage::PlayerJoined(message)) } - PlayerReply::AllMaps(message) => { - player_update_sender.send(PlayerReply::AllMaps(message)) + ServerMessage::AllMaps(message) => { + player_update_sender.send(ServerMessage::AllMaps(message)) } - PlayerReply::UpdatePosition(message) => { - player_update_sender.send(PlayerReply::UpdatePosition(message)) + ServerMessage::AllMapsChunk(message) => { + player_update_sender.send(ServerMessage::AllMapsChunk(message)) } - PlayerReply::UpdateOtherEntities(message) => { - entity_update_sender.send(PlayerReply::UpdateOtherEntities(message)) + ServerMessage::AllMapsChunksComplete => { + player_update_sender.send(ServerMessage::AllMapsChunksComplete) } - PlayerReply::PlayerAlreadyOnline => { - player_update_sender.send(PlayerReply::PlayerAlreadyOnline) + ServerMessage::UpdatePosition(message) => { + player_update_sender.send(ServerMessage::UpdatePosition(message)) + } + ServerMessage::UpdateOtherEntities(message) => { + entity_update_sender.send(ServerMessage::UpdateOtherEntities(message)) + } + ServerMessage::PlayerAlreadyOnline => { + player_update_sender.send(ServerMessage::PlayerAlreadyOnline) } }; diff --git a/rustyhack_client/src/screens.rs b/rustyhack_client/src/screens.rs index 9fba8e2..58017af 100644 --- a/rustyhack_client/src/screens.rs +++ b/rustyhack_client/src/screens.rs @@ -2,7 +2,7 @@ use crate::consts; use console_engine::ConsoleEngine; use rustyhack_lib::background_map::AllMaps; use rustyhack_lib::ecs::player::Player; -use rustyhack_lib::message_handler::player_message::EntityUpdates; +use rustyhack_lib::message_handler::messages::EntityUpdates; use std::process; mod bottom_text_window; diff --git a/rustyhack_client/src/screens/viewport.rs b/rustyhack_client/src/screens/viewport.rs index b458cf6..f953076 100644 --- a/rustyhack_client/src/screens/viewport.rs +++ b/rustyhack_client/src/screens/viewport.rs @@ -5,7 +5,7 @@ use rustyhack_lib::background_map::tiles::{Tile, TilePosition}; use rustyhack_lib::background_map::BackgroundMap; use rustyhack_lib::ecs::components::DisplayDetails; use rustyhack_lib::ecs::player::Player; -use rustyhack_lib::message_handler::player_message::EntityUpdates; +use rustyhack_lib::message_handler::messages::EntityUpdates; struct Viewport { width: u32, diff --git a/rustyhack_lib/Cargo.toml b/rustyhack_lib/Cargo.toml index 0972b41..4ad1f6c 100644 --- a/rustyhack_lib/Cargo.toml +++ b/rustyhack_lib/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustyhack_lib" -version = "0.2.1" +version = "0.2.2" authors = ["pbellchambers "] edition = "2021" repository = "https://github.com/pbellchambers/rustyhack-mmo" @@ -11,7 +11,7 @@ license = "AGPL-3.0" [dependencies] log = "0.4.17" simplelog = "0.12.0" -serde = { version = "1.0.138", features = ["derive"] } +serde = { version = "1.0.139", features = ["derive"] } console_engine = "2.4.0" crossterm = { version = "0.23.0", features = ["serde"] } uuid = { version = "1.1.2", features = ["serde", "v4"] } diff --git a/rustyhack_lib/src/background_map.rs b/rustyhack_lib/src/background_map.rs index 3afe94e..23d7abf 100644 --- a/rustyhack_lib/src/background_map.rs +++ b/rustyhack_lib/src/background_map.rs @@ -21,3 +21,5 @@ impl BackgroundMap { } pub type AllMaps = HashMap; + +pub type AllMapsChunk = (usize, Vec); diff --git a/rustyhack_lib/src/message_handler.rs b/rustyhack_lib/src/message_handler.rs index d51be82..ba63992 100644 --- a/rustyhack_lib/src/message_handler.rs +++ b/rustyhack_lib/src/message_handler.rs @@ -1 +1 @@ -pub mod player_message; +pub mod messages; diff --git a/rustyhack_lib/src/message_handler/player_message.rs b/rustyhack_lib/src/message_handler/messages.rs similarity index 77% rename from rustyhack_lib/src/message_handler/player_message.rs rename to rustyhack_lib/src/message_handler/messages.rs index 813cd04..9e3b42d 100644 --- a/rustyhack_lib/src/message_handler/player_message.rs +++ b/rustyhack_lib/src/message_handler/messages.rs @@ -2,29 +2,32 @@ use std::collections::HashMap; use serde::{Deserialize, Serialize}; -use crate::background_map::AllMaps; +use crate::background_map::{AllMaps, AllMapsChunk}; use crate::ecs::components::{DisplayDetails, Position, Velocity}; use crate::ecs::player::Player; #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub enum PlayerMessage { - PlayerJoin(CreatePlayerMessage), +pub enum PlayerRequest { + PlayerJoin(CreatePlayerRequest), UpdateVelocity(VelocityMessage), - GetAllMaps, + GetChunkedAllMaps, Timeout(String), + Undefined, } #[derive(Debug, Serialize, Deserialize)] -pub enum PlayerReply { +pub enum ServerMessage { PlayerJoined(Player), PlayerAlreadyOnline, AllMaps(AllMaps), + AllMapsChunk(AllMapsChunk), + AllMapsChunksComplete, UpdatePosition(Position), UpdateOtherEntities(EntityUpdates), } #[derive(Clone, Debug, PartialEq, Serialize, Deserialize)] -pub struct CreatePlayerMessage { +pub struct CreatePlayerRequest { pub client_addr: String, pub player_name: String, } diff --git a/rustyhack_server/Cargo.toml b/rustyhack_server/Cargo.toml index f940cd9..3a4d098 100644 --- a/rustyhack_server/Cargo.toml +++ b/rustyhack_server/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustyhack_server" -version = "0.2.1" +version = "0.2.2" authors = ["pbellchambers "] edition = "2021" repository = "https://github.com/pbellchambers/rustyhack-mmo" @@ -17,7 +17,7 @@ crossterm = { version = "0.23.0", features = ["serde"] } legion = "0.4.0" laminar = "0.5.0" crossbeam-channel = "0.5.5" -serde = { version = "1.0.138", features = ["derive"] } +serde = { version = "1.0.139", features = ["derive"] } serde_json = "1.0.82" bincode = "1.3.3" rand = "0.8.5" diff --git a/rustyhack_server/src/game/monsters.rs b/rustyhack_server/src/game/monsters.rs index 4142c52..0c9b954 100644 --- a/rustyhack_server/src/game/monsters.rs +++ b/rustyhack_server/src/game/monsters.rs @@ -56,7 +56,7 @@ fn get_monster_definition_from_path(path: &Path) -> Monster { let buf_reader = BufReader::new(file); serde_json::from_reader(buf_reader).unwrap_or_else(|err| { error!( - "Problem deserialising monster definition from file: {:?}, error: {}", + "Problem deserializing monster definition from file: {:?}, error: {}", path, err ); process::exit(1); diff --git a/rustyhack_server/src/game/player_updates.rs b/rustyhack_server/src/game/player_updates.rs index 1c3f441..cfa2676 100644 --- a/rustyhack_server/src/game/player_updates.rs +++ b/rustyhack_server/src/game/player_updates.rs @@ -3,18 +3,17 @@ use bincode::serialize; use crossbeam_channel::{Receiver, Sender}; use laminar::Packet; use legion::{IntoQuery, World}; -use rustyhack_lib::ecs::components; use rustyhack_lib::ecs::components::{ DisplayDetails, MonsterDetails, PlayerDetails, Position, Stats, Velocity, }; use rustyhack_lib::ecs::player::Player; -use rustyhack_lib::message_handler::player_message::{EntityUpdates, PlayerMessage, PlayerReply}; +use rustyhack_lib::message_handler::messages::{EntityUpdates, PlayerRequest, ServerMessage}; use std::collections::HashMap; use std::process; pub(crate) fn process_player_messages( world: &mut World, - channel_receiver: &Receiver, + channel_receiver: &Receiver, sender: &Sender, mut player_velocity_updates: HashMap, ) -> HashMap { @@ -23,19 +22,19 @@ pub(crate) fn process_player_messages( let received = channel_receiver.try_recv(); if let Ok(received_message) = received { match received_message { - PlayerMessage::PlayerJoin(message) => { + PlayerRequest::PlayerJoin(message) => { info!( "Player joined request received for {} from: {}", &message.player_name, &message.client_addr ); join_player(world, message.player_name, message.client_addr, sender); } - PlayerMessage::UpdateVelocity(message) => { + PlayerRequest::UpdateVelocity(message) => { debug!("Velocity update received for {}", &message.player_name); player_velocity_updates.insert(message.player_name, message.velocity); debug!("Processed velocity update: {:?}", &player_velocity_updates); } - PlayerMessage::Timeout(address) => { + PlayerRequest::Timeout(address) => { set_player_disconnected(world, address); } _ => { @@ -91,9 +90,9 @@ fn join_player(world: &mut World, name: String, client_addr: String, sender: &Se break; } else if player_details.player_name == name && player_details.currently_online { warn!("Player join request from {} for existing player that's currently online ({} at {}).", &client_addr, &name, &player_details.client_addr); - let response = serialize(&PlayerReply::PlayerAlreadyOnline).unwrap_or_else(|err| { + let response = serialize(&ServerMessage::PlayerAlreadyOnline).unwrap_or_else(|err| { error!( - "Failed to serialise player already online response, error: {}", + "Failed to serialize player already online response, error: {}", err ); process::exit(1); @@ -129,16 +128,16 @@ fn create_player(world: &mut World, name: String, client_addr: String, sender: & player.display_details, player.position.clone(), player.stats, - components::Velocity { x: 0, y: 0 }, + Velocity { x: 0, y: 0 }, )); info!("New player \"{}\" created: {:?}", name, &player_entity); send_player_joined_response(player, sender); } fn send_player_joined_response(player: Player, sender: &Sender) { - let response = serialize(&PlayerReply::PlayerJoined(player.clone())).unwrap_or_else(|err| { + let response = serialize(&ServerMessage::PlayerJoined(player.clone())).unwrap_or_else(|err| { error!( - "Failed to serialise player created response, error: {}", + "Failed to serialize player created response, error: {}", err ); process::exit(1); @@ -167,10 +166,10 @@ pub(crate) fn send_player_updates( "Sending player velocity update for: {}", &player_details.player_name ); - let response = serialize(&PlayerReply::UpdatePosition(position.clone())) + let response = serialize(&ServerMessage::UpdatePosition(position.clone())) .unwrap_or_else(|err| { error!( - "Failed to serialise player position: {:?}, error: {}", + "Failed to serialize player position: {:?}, error: {}", &position, err ); process::exit(1); @@ -214,13 +213,13 @@ pub(crate) fn send_other_entities_updates(world: &World, sender: &Sender for player_details in query.iter(world) { if player_details.currently_online { debug!("Sending entity updates to: {}", &player_details.client_addr); - let response = serialize(&PlayerReply::UpdateOtherEntities(EntityUpdates { + let response = serialize(&ServerMessage::UpdateOtherEntities(EntityUpdates { position_updates: position_updates.clone(), display_details: display_details.clone(), })) .unwrap_or_else(|err| { error!( - "Failed to serialise entity updates: {:?}, error: {}", + "Failed to serialize entity updates: {:?}, error: {}", &position_updates, err ); process::exit(1); diff --git a/rustyhack_server/src/game/spawns.rs b/rustyhack_server/src/game/spawns.rs index 6958200..5d24861 100644 --- a/rustyhack_server/src/game/spawns.rs +++ b/rustyhack_server/src/game/spawns.rs @@ -67,7 +67,7 @@ fn get_spawns_definition_from_path(path: &Path) -> Spawns { let buf_reader = BufReader::new(file); serde_json::from_reader(buf_reader).unwrap_or_else(|err| { error!( - "Problem deserialising spawns definition from file: {:?}, error: {}", + "Problem deserializing spawns definition from file: {:?}, error: {}", path, err ); process::exit(1); diff --git a/rustyhack_server/src/networking.rs b/rustyhack_server/src/networking.rs index f2dadec..af77d46 100644 --- a/rustyhack_server/src/networking.rs +++ b/rustyhack_server/src/networking.rs @@ -26,7 +26,6 @@ pub(crate) fn bind_to_socket(server_addr: String) -> (Sender, Receiver laminar::Config { laminar::Config { idle_connection_timeout: Duration::from_secs(10), - max_fragments: 255, ..Default::default() } } diff --git a/rustyhack_server/src/networking/message_handler.rs b/rustyhack_server/src/networking/message_handler.rs index 9c9512d..1371bee 100644 --- a/rustyhack_server/src/networking/message_handler.rs +++ b/rustyhack_server/src/networking/message_handler.rs @@ -2,14 +2,15 @@ use bincode::{deserialize, serialize}; use crossbeam_channel::{Receiver, Sender}; use laminar::{Packet, SocketEvent}; use rustyhack_lib::background_map::AllMaps; -use rustyhack_lib::message_handler::player_message::{PlayerMessage, PlayerReply}; +use rustyhack_lib::message_handler::messages::{PlayerRequest, ServerMessage}; +use std::net::SocketAddr; use std::thread; pub(crate) fn spawn_message_handler_thread( sender: Sender, receiver: Receiver, all_maps: AllMaps, - channel_sender: Sender, + channel_sender: Sender, ) { thread::spawn(move || run(sender, receiver, all_maps, channel_sender)); } @@ -18,7 +19,7 @@ pub(crate) fn run( sender: Sender, receiver: Receiver, all_maps: AllMaps, - channel_sender: Sender, + channel_sender: Sender, ) { info!("Spawned message handler thread."); loop { @@ -30,41 +31,28 @@ pub(crate) fn run( let msg = packet.payload(); let address = packet.addr(); - let player_message_result = deserialize::(msg); - let player_message = match player_message_result { - Ok(_) => player_message_result.unwrap(), - Err(error) => { - warn!( - "Error when deserialising player message from client {}: {}", - &packet.addr(), - error - ); - //try again with next packet - continue; - } - }; - debug!("Received {:?} from {:?}", player_message, address); + let player_request = deserialize_player_request(msg, address); + debug!("Received {:?} from {:?}", player_request, address); - match player_message { - PlayerMessage::PlayerJoin(message) => { - let mut create_player_message = message.clone(); - create_player_message.client_addr = packet.addr().to_string(); + match player_request { + PlayerRequest::PlayerJoin(message) => { + let mut create_player_request = message.clone(); + create_player_request.client_addr = address.to_string(); send_channel_message( - PlayerMessage::PlayerJoin(create_player_message), + PlayerRequest::PlayerJoin(create_player_request), &channel_sender, ); } - PlayerMessage::UpdateVelocity(message) => { + PlayerRequest::UpdateVelocity(message) => { send_channel_message( - PlayerMessage::UpdateVelocity(message), + PlayerRequest::UpdateVelocity(message), &channel_sender, ); } - PlayerMessage::GetAllMaps => { - let response = serialize(&PlayerReply::AllMaps(all_maps.clone())) - .expect("Error serialising AllMaps response."); - send_packet( - Packet::reliable_ordered(packet.addr(), response, Some(2)), + PlayerRequest::GetChunkedAllMaps => { + send_all_maps_chunks( + serialize_all_maps(all_maps.clone()), + address, &sender, ); } @@ -77,7 +65,7 @@ pub(crate) fn run( SocketEvent::Timeout(address) => { info!("Client timed out: {}", address); send_channel_message( - PlayerMessage::Timeout(address.to_string()), + PlayerRequest::Timeout(address.to_string()), &channel_sender, ); } @@ -87,6 +75,72 @@ pub(crate) fn run( } } +fn serialize_all_maps(all_maps: AllMaps) -> Vec { + serialize(&ServerMessage::AllMaps(all_maps)).expect("Error serializing AllMaps data.") +} + +fn send_all_maps_chunks( + all_maps_serialized: Vec, + address: SocketAddr, + sender: &Sender, +) { + let all_maps_chunks = all_maps_serialized + .chunks(1450) + .map(|s| s.into()) + .enumerate(); + let chunked_response_length = all_maps_chunks.size_hint(); + + for (i, chunk) in all_maps_chunks { + let chunk_packet = serialize(&ServerMessage::AllMapsChunk((i, chunk))) + .expect("Error serializing AllMapsChunk."); + if i == 0 { + info!("Sending first AllMapsChunk packet {} to: {}", i, address); + send_packet( + Packet::reliable_ordered(address, chunk_packet, Some(i as u8)), + sender, + ); + } else if i + == chunked_response_length + .1 + .expect("Error: chunked all maps length is zero") + - 1 + { + info!("Sending last AllMapsChunk packet {} to: {}", i, address); + send_packet( + Packet::reliable_ordered(address, chunk_packet, Some(i as u8)), + sender, + ); + + let complete_response = serialize(&ServerMessage::AllMapsChunksComplete) + .expect("Error serializing AllMapsChunksComplete response."); + send_packet( + Packet::reliable_ordered(address, complete_response, Some(i as u8 + 1)), + sender, + ); + } else { + debug!("Sending AllMapsChunk packet {} to: {}", i, address); + send_packet( + Packet::reliable_ordered(address, chunk_packet, Some(i as u8)), + sender, + ); + } + } +} + +fn deserialize_player_request(msg: &[u8], address: SocketAddr) -> PlayerRequest { + let player_request_result = deserialize::(msg); + match player_request_result { + Ok(_) => player_request_result.unwrap(), + Err(error) => { + warn!( + "Error when deserializing player request from client {}: {}", + &address, error + ); + PlayerRequest::Undefined + } + } +} + pub(crate) fn send_packet(packet: Packet, sender: &Sender) { let send_result = sender.send(packet); match send_result { @@ -100,7 +154,7 @@ pub(crate) fn send_packet(packet: Packet, sender: &Sender) { } } -fn send_channel_message(message: PlayerMessage, sender: &Sender) { +fn send_channel_message(message: PlayerRequest, sender: &Sender) { let send_result = sender.send(message); match send_result { Ok(_) => {