diff --git a/src/ship/mod.rs b/src/ship/mod.rs index 4b6b4d0..c0b74b2 100644 --- a/src/ship/mod.rs +++ b/src/ship/mod.rs @@ -7,3 +7,4 @@ pub mod item_stats; pub mod map; pub mod monster; pub mod drops; +pub mod packet; diff --git a/src/ship/packet/builder/lobby.rs b/src/ship/packet/builder/lobby.rs new file mode 100644 index 0000000..29a1b8b --- /dev/null +++ b/src/ship/packet/builder/lobby.rs @@ -0,0 +1,63 @@ +use std::collections::HashMap; +use libpso::packet::ship::*; +use crate::common::serverstate::ClientId; +use crate::common::leveltable::CharacterLevelTable; +use crate::ship::ship::{SendShipPacket, ShipError, ClientState, Clients}; +use crate::ship::character::{CharacterBytesBuilder, FullCharacterBytesBuilder}; +use crate::ship::location::{ClientLocation, LobbyId, AreaClient}; +use crate::entity::character::CharacterEntity; +use crate::ship::items::ActiveInventory; +use crate::ship::packet::builder::{player_header, player_info}; +use libpso::character::character::{Inventory, InventoryItem}; +use libpso::utf8_to_utf16_array; + + +pub fn join_lobby(id: ClientId, + lobby: LobbyId, + client_location: &ClientLocation, + clients: &Clients, + level_table: &CharacterLevelTable) + -> Result { + let lobby_clients = client_location.get_clients_in_lobby(lobby).map_err(|err| ShipError::ClientError(format!("{:?}", err)))?; + let playerinfo = lobby_clients.iter() + .map(|area_client| { + let client = clients.get(&area_client.client).ok_or(ShipError::ClientNotFound(area_client.client)).unwrap(); + player_info(0x100, &client, area_client, level_table) + }); + + let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id)).unwrap(); + let area_client = client_location.get_local_client(id).map_err(|err| ShipError::ClientError(format!("{:?}", err)))?; + let leader = client_location.get_lobby_leader(lobby).map_err(|err| ShipError::ClientError(format!("{:?}", err)))?; + Ok(JoinLobby { + client: area_client.local_client.id(), + leader: leader.local_client.id(), + one: 1, + lobby: lobby.id(), + block: client.block as u16, + event: 0, + padding: 0, + playerinfo: playerinfo.collect(), + }) +} + +pub fn add_to_lobby(id: ClientId, + lobby: LobbyId, + client_location: &ClientLocation, + clients: &Clients, + level_table: &CharacterLevelTable) + -> Result { + let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id)).unwrap(); + let area_client = client_location.get_local_client(id).map_err(|err| ShipError::ClientError(format!("{:?}", err)))?; + let leader = client_location.get_lobby_leader(lobby).map_err(|err| ShipError::ClientError(format!("{:?}", err)))?; + Ok(AddToLobby { + flag: 1, + client: area_client.local_client.id(), + leader: leader.local_client.id(), + one: 1, + lobby: lobby.id(), + block: client.block as u16, + event: 0, + padding: 0, + playerinfo: player_info(0x100, &client, &area_client, level_table), + }) +} diff --git a/src/ship/packet/builder/mod.rs b/src/ship/packet/builder/mod.rs new file mode 100644 index 0000000..19120f1 --- /dev/null +++ b/src/ship/packet/builder/mod.rs @@ -0,0 +1,41 @@ +pub mod lobby; +pub mod room; + +use libpso::character::character::Inventory; +use libpso::packet::ship::{PlayerHeader, PlayerInfo}; +use libpso::utf8_to_utf16_array; +use crate::common::leveltable::CharacterLevelTable; +use crate::ship::character::CharacterBytesBuilder; +use crate::ship::ship::ClientState; +use crate::ship::location::AreaClient; + +pub fn player_header(tag: u32, client: &ClientState, area_client: &AreaClient) -> PlayerHeader { + PlayerHeader { + tag: tag, + guildcard: client.user.id.0, + _unknown1: [0; 5], + client_id: area_client.local_client.id() as u32, + name: libpso::utf8_to_utf16_array!(client.character.name, 16), + _unknown2: 2, + } +} + +pub fn player_info(tag: u32, client: &ClientState, area_client: &AreaClient, level_table: &CharacterLevelTable) -> PlayerInfo { + let (level, stats) = level_table.get_stats_from_exp(client.character.char_class, client.character.exp); + let character = CharacterBytesBuilder::new() + .character(&client.character) + .stats(&stats) + .level(level - 1) + .build(); + PlayerInfo { + header: player_header(tag, client, area_client), + inventory: Inventory { + item_count: client.inventory.count() as u8, + hp_mats_used: 0, // TODO: materials + tp_mats_used: 0, // TODO: materials + language: 0, // TODO: account language + items: client.inventory.as_client_inventory_items(), + }, + character: character, + } +} diff --git a/src/ship/packet/builder/room.rs b/src/ship/packet/builder/room.rs new file mode 100644 index 0000000..26abdb3 --- /dev/null +++ b/src/ship/packet/builder/room.rs @@ -0,0 +1,77 @@ +use std::collections::HashMap; +use libpso::packet::ship::*; +use crate::common::serverstate::ClientId; +use crate::common::leveltable::CharacterLevelTable; +use crate::ship::ship::{SendShipPacket, ShipError, ClientState, Clients}; +use crate::ship::character::{CharacterBytesBuilder, FullCharacterBytesBuilder}; +use crate::ship::location::{ClientLocation, RoomId, AreaClient}; +use crate::entity::character::CharacterEntity; +use crate::ship::items::ActiveInventory; +use crate::ship::room::RoomState; +use crate::ship::packet::builder::{player_header, player_info}; +use libpso::character::character::{Inventory, InventoryItem}; +use libpso::utf8_to_utf16_array; + +pub fn join_room(id: ClientId, + clients: &Clients, + client_location: &ClientLocation, + room_id: RoomId, + room: &RoomState) + -> Result { + let all_clients = client_location.get_clients_in_room(room_id).map_err(|err| ShipError::ClientError(format!("{:?}", err)))?; + let players = all_clients.iter() + .enumerate() + .fold(Ok([PlayerHeader::default(); 4]), |acc, (i, c)| { + let header_client = clients.get(&c.client).ok_or(ShipError::ClientNotFound(id))?; + let header_area_client = client_location.get_local_client(id).map_err(|err| ShipError::ClientError(format!("{:?}", err)))?; + acc.map(|mut a| { + a[i] = player_header(0x10000, &header_client, &header_area_client); + a + }) + })?; + + let area_client = client_location.get_local_client(id).map_err(|err| ShipError::ClientError(format!("{:?}", err)))?; + let leader = client_location.get_room_leader(room_id).map_err(|err| ShipError::ClientError(format!("{:?}", err)))?; + Ok(JoinRoom { + flag: all_clients.len() as u32, + maps: room.maps.map_headers(), + players: players, + client: area_client.local_client.id(), + leader: leader.local_client.id(), + one: 1, + difficulty: room.mode.difficulty().into(), + battle: room.mode.battle(), + event: 0, + section: room.section_id.into(), + challenge: room.mode.challenge(), + random_seed: room.random_seed, + episode: room.mode.episode().into(), + one2: 1, + single_player: room.mode.single_player(), + unknown: 0, + }) +} + + +pub fn add_to_room(id: ClientId, + client: &ClientState, + area_client: &AreaClient, + leader: &AreaClient, + level_table: &CharacterLevelTable, + room_id: RoomId, +) + -> Result { + + Ok(AddToRoom { + flag: 1, + client: area_client.local_client.id(), + leader: leader.local_client.id(), + one: 0, // TODO: ???????? + lobby: 0xFF, + block: 0, + event: 0, + padding: 0, + playerinfo: player_info(0x10000, client, &area_client, level_table), + }) +} + diff --git a/src/ship/packet/handler/auth.rs b/src/ship/packet/handler/auth.rs new file mode 100644 index 0000000..4b61d6b --- /dev/null +++ b/src/ship/packet/handler/auth.rs @@ -0,0 +1,40 @@ +use std::collections::HashMap; +use libpso::packet::login::{Login, LoginResponse, AccountStatus, Session}; +use libpso::packet::ship::*; +use crate::common::serverstate::ClientId; +use crate::ship::ship::{SendShipPacket, ShipError, ClientState, Clients}; +use crate::login::login::get_login_status; +use crate::entity::gateway::EntityGateway; +use crate::ship::items::ActiveItemDatabase; + +pub fn validate_login(id: ClientId, + pkt: &Login, + entity_gateway: &mut EG, + clients: &mut Clients, + item_database: &mut ActiveItemDatabase, + ship_name: &String) + -> Result, ShipError> { + Ok(match get_login_status(entity_gateway, pkt) { + Ok(user) => { + let mut response = LoginResponse::by_status(AccountStatus::Ok, Session::new()); + response.guildcard = user.id.0 as u32; + response.team_id = user.team_id.map_or(31, |ti| ti) as u32; + let characters = entity_gateway.get_characters_by_user(&user); + let character = characters + .get(pkt.session.character_slot as usize) + .ok_or(ShipError::InvalidSlot(id, pkt.session.character_slot as u32))?.as_ref() + .ok_or(ShipError::NoCharacterInSlot(id, pkt.session.character_slot as u32))? + .clone(); + let settings = entity_gateway.get_user_settings_by_user(&user) + .ok_or(ShipError::ClientNotFound(id))?; + let inventory = item_database.get_character_inventory(entity_gateway, &character); + + clients.insert(id, ClientState::new(user, settings, character, inventory, pkt.session)); + vec![SendShipPacket::LoginResponse(response), SendShipPacket::ShipBlockList(ShipBlockList::new(&&ship_name, 3))] + }, + Err(err) => { + vec![SendShipPacket::LoginResponse(LoginResponse::by_status(err, Session::new()))] + } + }) +} + diff --git a/src/ship/packet/handler/communication.rs b/src/ship/packet/handler/communication.rs new file mode 100644 index 0000000..e2c84aa --- /dev/null +++ b/src/ship/packet/handler/communication.rs @@ -0,0 +1,52 @@ +use std::collections::HashMap; +use libpso::packet::ship::*; +use crate::common::serverstate::ClientId; +use crate::common::leveltable::CharacterLevelTable; +use crate::ship::ship::{SendShipPacket, ShipError, ClientState, Clients}; +use crate::ship::character::{CharacterBytesBuilder, FullCharacterBytesBuilder}; +use crate::ship::location::{ClientLocation, LobbyId, RoomId, RoomLobby, MAX_ROOMS}; +use libpso::character::character; +use crate::entity::gateway::EntityGateway; + +pub fn player_chat(id: ClientId, + msg: &PlayerChat, + client_location: &ClientLocation, + clients: &Clients) -> Result + Send>, ShipError> { + let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?; + let cmsg = PlayerChat::new(client.user.id.0, msg.message.clone()); + + Ok(Box::new(client_location.get_all_clients_by_client(id).unwrap().into_iter() + .map(move |client| { + (client.client, SendShipPacket::PlayerChat(cmsg.clone())) + }))) +} + +pub fn request_infoboard(id: ClientId, + request_infoboard: &ViewInfoboardRequest, + client_location: &ClientLocation, + clients: &Clients) + -> Box + Send> { + let area_clients = client_location.get_client_neighbors(id).unwrap(); + let r = area_clients.iter() + .filter_map(|c| { + clients.get(&c.client) + }) + .map(|client| { + InfoboardResponse { + name: libpso::utf8_to_utf16_array!(client.character.name, 16), + message: client.character.info_board.as_bytes(), + } + }).collect(); + Box::new(vec![(id, SendShipPacket::ViewInfoboardResponse(ViewInfoboardResponse {response: r}))].into_iter()) +} + +pub fn write_infoboard(id: ClientId, + new_infoboard: &WriteInfoboard, + clients: &mut Clients, + entity_gateway: &mut EG) + -> Box + Send> { + let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id)).unwrap(); + client.character.info_board.update_infoboard(new_infoboard); + entity_gateway.save_character(&client.character); + Box::new(None.into_iter()) +} diff --git a/src/ship/packet/handler/direct_message.rs b/src/ship/packet/handler/direct_message.rs new file mode 100644 index 0000000..a824684 --- /dev/null +++ b/src/ship/packet/handler/direct_message.rs @@ -0,0 +1,48 @@ +use std::collections::HashMap; +use log::warn; +use libpso::packet::ship::*; +use libpso::packet::messages::*; +use crate::common::serverstate::ClientId; +use crate::common::leveltable::CharacterLevelTable; +use crate::ship::ship::{SendShipPacket, ShipError, ClientState, Clients, Rooms}; +use crate::ship::character::{CharacterBytesBuilder, FullCharacterBytesBuilder}; +use crate::ship::location::{ClientLocation, LobbyId, RoomId, RoomLobby, MAX_ROOMS}; +use libpso::character::character; +use crate::entity::gateway::EntityGateway; +use libpso::{utf8_to_array, utf8_to_utf16_array}; + +fn send_to_client(id: ClientId, target: u8, msg: DirectMessage, client_location: &ClientLocation) + -> Box + Send> { + Box::new(client_location.get_all_clients_by_client(id).unwrap().into_iter() + .filter(move |client| client.local_client.id() == target) + .map(move |client| { + (client.client, SendShipPacket::DirectMessage(msg.clone())) + })) +} + + + +pub fn guildcard_send(id: ClientId, + guildcard_send: &GuildcardSend, + target: u32, + client_location: &ClientLocation, + clients: &Clients) + -> Box + Send> { + let client = clients.get(&id).unwrap(); + let msg = DirectMessage{ + flag: target, + msg: GameMessage::GuildcardRecv(GuildcardRecv { + client: guildcard_send.client, + target: guildcard_send.target, + guildcard: client.user.id.0, + name: utf8_to_utf16_array!(client.character.name, 0x18), + team: [0; 0x10], // TODO: teams not yet implemented + desc: utf8_to_utf16_array!(client.character.guildcard.description, 0x58), + one: 1, + language: 0, // TODO: add language flag to character + section_id: client.character.section_id.into(), + class: client.character.char_class.into(), + }), + }; + send_to_client(id, target as u8, msg, &client_location) +} diff --git a/src/ship/packet/handler/lobby.rs b/src/ship/packet/handler/lobby.rs new file mode 100644 index 0000000..9be8556 --- /dev/null +++ b/src/ship/packet/handler/lobby.rs @@ -0,0 +1,56 @@ +use std::collections::HashMap; +use libpso::packet::ship::*; +use crate::common::serverstate::ClientId; +use crate::common::leveltable::CharacterLevelTable; +use crate::ship::ship::{SendShipPacket, ShipError, ClientState, Clients}; +use crate::ship::character::{CharacterBytesBuilder, FullCharacterBytesBuilder}; +use crate::ship::location::{ClientLocation, LobbyId, RoomId, RoomLobby, MAX_ROOMS}; +use crate::ship::packet; +use libpso::character::character; + +// this function needs a better home +pub fn block_selected(id: ClientId, + pkt: &MenuSelect, + clients: &mut Clients, + level_table: &CharacterLevelTable) + -> Result, ShipError> { + let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; + client.block = pkt.item as u32; + + let (level, stats) = level_table.get_stats_from_exp(client.character.char_class, client.character.exp); + + let fc = FullCharacterBytesBuilder::new() + .character(&client.character) + .stats(&stats) + .level(level) + .inventory(&client.inventory) + .key_config(&client.settings.settings.key_config) + .joystick_config(&client.settings.settings.joystick_config) + .symbol_chat(&client.settings.settings.symbol_chats) + .tech_menu(&client.character.tech_menu.as_bytes()) + .build(); + + Ok(vec![ + SendShipPacket::FullCharacter(FullCharacter { + character: fc, + }), + SendShipPacket::CharDataRequest(CharDataRequest {}), + ]) +} + +pub fn send_player_to_lobby(id: ClientId, + _pkt: &CharData, + client_location: &mut ClientLocation, + clients: &Clients, + level_table: &CharacterLevelTable) + -> Result, ShipError> { + let lobby = client_location.add_client_to_next_available_lobby(id, LobbyId(0)).map_err(|_| ShipError::TooManyClients)?; + let join_lobby = packet::builder::lobby::join_lobby(id, lobby, client_location, clients, level_table)?; + let addto = packet::builder::lobby::add_to_lobby(id, lobby, client_location, clients, level_table)?; + + let neighbors = client_location.get_client_neighbors(id).unwrap(); + Ok(vec![(id, SendShipPacket::JoinLobby(join_lobby))] + .into_iter() + .chain(neighbors.into_iter() + .map(|c| (c.client, SendShipPacket::AddToLobby(addto.clone())))).collect()) +} diff --git a/src/ship/packet/handler/message.rs b/src/ship/packet/handler/message.rs new file mode 100644 index 0000000..a58de7c --- /dev/null +++ b/src/ship/packet/handler/message.rs @@ -0,0 +1,27 @@ +use std::collections::HashMap; +use log::warn; +use libpso::packet::ship::*; +use libpso::packet::messages::*; +use crate::common::serverstate::ClientId; +use crate::common::leveltable::CharacterLevelTable; +use crate::ship::ship::{SendShipPacket, ShipError, ClientState, Rooms}; +use crate::ship::character::{CharacterBytesBuilder, FullCharacterBytesBuilder}; +use crate::ship::location::{ClientLocation, LobbyId, RoomId, RoomLobby, MAX_ROOMS}; +use libpso::character::character; +use crate::entity::gateway::EntityGateway; + +pub fn request_exp(id: ClientId, + request_exp: &RequestExp, + client_location: &ClientLocation, + rooms: &Rooms) + -> Box + Send> { + + match client_location.get_area(id).unwrap() { + RoomLobby::Room(room) => { + let r = rooms[room.0].as_ref().unwrap(); + warn!("killed a {:?}", r.maps.enemy_by_id(request_exp.enemy_id as usize).monster); + }, + _ => {} + }; + Box::new(None.into_iter()) +} diff --git a/src/ship/packet/handler/mod.rs b/src/ship/packet/handler/mod.rs new file mode 100644 index 0000000..2021066 --- /dev/null +++ b/src/ship/packet/handler/mod.rs @@ -0,0 +1,7 @@ +pub mod auth; +pub mod communication; +pub mod direct_message; +pub mod lobby; +pub mod message; +pub mod room; +pub mod settings; diff --git a/src/ship/packet/handler/room.rs b/src/ship/packet/handler/room.rs new file mode 100644 index 0000000..ff82422 --- /dev/null +++ b/src/ship/packet/handler/room.rs @@ -0,0 +1,164 @@ +use std::collections::HashMap; +use libpso::packet::ship::*; +use crate::common::serverstate::ClientId; +use crate::common::leveltable::CharacterLevelTable; +use crate::ship::ship::{SendShipPacket, ShipError, ClientState, Rooms, Clients}; +use crate::ship::character::{CharacterBytesBuilder, FullCharacterBytesBuilder}; +use crate::ship::location::{ClientLocation, LobbyId, RoomId, RoomLobby, MAX_ROOMS}; +use crate::ship::packet::builder; +use libpso::character::character; +use crate::ship::room; + +pub fn create_room(id: ClientId, + create_room: &CreateRoom, + client_location: &mut ClientLocation, + clients: &mut Clients, + rooms: &mut Rooms) + -> Result + Send>, ShipError> { + let area = client_location.get_area(id).unwrap(); + let area_client = client_location.get_local_client(id).unwrap(); + let lobby_neighbors = client_location.get_client_neighbors(id).unwrap(); + let room_id = client_location.create_new_room(id).unwrap(); + + let client = clients.get_mut(&id).unwrap();//.ok_or(ShipError::ClientNotFound(id)).unwrap(); + let mut room = room::RoomState::from_create_room(create_room, client.character.section_id).unwrap(); + room.bursting = true; + + let join_room = builder::room::join_room(id, clients, client_location, room_id, &room)?; + rooms[room_id.0] = Some(room); + + let mut result: Box + Send> = Box::new( + vec![(id, SendShipPacket::JoinRoom(join_room))].into_iter() + ); + if let Ok(leader) = client_location.get_area_leader(area) { + let leave_lobby = SendShipPacket::LeaveLobby(LeaveLobby::new(area_client.local_client.id(), leader.local_client.id())); + result = Box::new(result.chain(lobby_neighbors + .into_iter() + .map(move |c| { + (c.client, leave_lobby.clone()) + }))); + } + + Ok(result) +} + +pub fn room_name_request(id: ClientId, + client_location: &ClientLocation, + rooms: &Rooms) + -> Box + Send> { + let area = client_location.get_area(id).unwrap(); + match area { + RoomLobby::Room(room) => Box::new(vec![(id, SendShipPacket::RoomNameResponse(RoomNameResponse {name: rooms[room.0].as_ref().unwrap().name.clone()}))].into_iter()), + RoomLobby::Lobby(_) => panic!() + } +} + +pub fn join_room(id: ClientId, + pkt: &MenuSelect, + client_location: &mut ClientLocation, + clients: &mut Clients, + level_table: &CharacterLevelTable, + rooms: &mut Rooms) + -> Result + Send>, ShipError> { + let original_area = client_location.get_area(id).unwrap(); + let original_neighbors = client_location.get_client_neighbors(id).unwrap(); + let room = rooms.get(pkt.item as usize) + .ok_or_else(|| ShipError::InvalidRoom(pkt.item))?.as_ref() + .ok_or_else(|| ShipError::InvalidRoom(pkt.item))?; + if room.bursting { + return Ok(Box::new(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("player is bursting\nplease wait".into())))].into_iter())) + } + let room_id = RoomId(pkt.item as usize); + let original_room_clients = client_location.get_clients_in_room(room_id).map_err(|err| ShipError::ClientError(format!("{:?}", err)))?; + client_location.add_client_to_room(id, room_id).unwrap(); // TODO: show room full error or whatever + + let client = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?; + let area_client = client_location.get_local_client(id).map_err(|err| ShipError::ClientError(format!("{:?}", err)))?; + let leader = client_location.get_room_leader(room_id).map_err(|err| ShipError::ClientError(format!("{:?}", err)))?; + let join_room = builder::room::join_room(id, clients, client_location, room_id, &room)?; + let add_to = builder::room::add_to_room(id, &client, &area_client, &leader, level_table, room_id)?; + + let room = rooms.get_mut(room_id.0).unwrap().as_mut().unwrap(); + room.bursting = true; + + let mut result: Box + Send> = Box::new( + vec![(id, SendShipPacket::JoinRoom(join_room))] + .into_iter() + .chain(original_room_clients.clone().into_iter() + .map(move |c| (c.client, SendShipPacket::AddToRoom(add_to.clone()))) + )); + + if let Ok(leader) = client_location.get_area_leader(original_area) { + let leave_lobby = SendShipPacket::LeaveLobby(LeaveLobby::new(area_client.local_client.id(), leader.local_client.id())); + result = Box::new(result.chain(original_neighbors.into_iter() + .map(move |c| (c.client, leave_lobby.clone())))) + } + + Ok(result) +} + +pub fn done_bursting(id: ClientId, + client_location: &ClientLocation, + rooms: &mut Rooms) + -> Box + Send> { + let area = client_location.get_area(id).unwrap(); + if let RoomLobby::Room(room_id) = area { + let room = rooms.get_mut(room_id.0).unwrap().as_mut().unwrap(); + room.bursting = false; + } + Box::new(client_location.get_client_neighbors(id).unwrap().into_iter() + .map(move |client| { + vec![ + (client.client, SendShipPacket::BurstDone72(BurstDone72::new())), + ] + }).flatten()) +} + + +pub fn request_room_list(id: ClientId, + client_location: &ClientLocation, + rooms: &Rooms) + -> Box + Send> { + let active_room_list = rooms.iter() + .enumerate() + .filter_map(|(i, r)| { + r.as_ref().map(|room| { + RoomList { + menu_id: ROOM_MENU_ID, + item_id: i as u32, + difficulty: room.get_difficulty_for_room_list(), + players: client_location.get_clients_in_room(RoomId(i)).unwrap().len() as u8, + name: libpso::utf8_to_utf16_array!(room.name, 16), + episode: room.get_episode_for_room_list(), + flags: room.get_flags_for_room_list(), + } + }) + }); + let baseroom: RoomList = RoomList { + menu_id: ROOM_MENU_ID, + item_id: ROOM_MENU_ID, + difficulty: 0x00, + players: 0x00, + name: libpso::utf8_to_utf16_array!("Room list menu", 16), + episode: 0, + flags: 0, + }; + + Box::new(vec![(id, SendShipPacket::RoomListResponse(RoomListResponse { + baseroom, + rooms: active_room_list.collect() + }))].into_iter()) +} + +pub fn cool_62(id: ClientId, + cool_62: &Like62ButCooler, + client_location: &ClientLocation) + -> Box + Send> { + let target = cool_62.flag as u8; + let cool_62 = cool_62.clone(); + Box::new(client_location.get_client_neighbors(id).unwrap().into_iter() + .filter(move |client| client.local_client.id() == target) + .map(move |client| { + (client.client, SendShipPacket::Like62ButCooler(cool_62.clone())) + })) +} diff --git a/src/ship/packet/handler/settings.rs b/src/ship/packet/handler/settings.rs new file mode 100644 index 0000000..93ed14a --- /dev/null +++ b/src/ship/packet/handler/settings.rs @@ -0,0 +1,20 @@ +use std::collections::HashMap; +use libpso::packet::ship::*; +use crate::common::serverstate::ClientId; +use crate::common::leveltable::CharacterLevelTable; +use crate::ship::ship::{SendShipPacket, ShipError, ClientState, Clients}; +use crate::ship::character::{CharacterBytesBuilder, FullCharacterBytesBuilder}; +use crate::ship::location::{ClientLocation, LobbyId, RoomId, RoomLobby, MAX_ROOMS}; +use libpso::character::character; +use crate::entity::gateway::EntityGateway; + +pub fn update_config(id: ClientId, + update_config: &UpdateConfig, + clients: &mut Clients, + entity_gateway: &mut EG) + -> Box + Send> { + let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id)).unwrap(); + client.character.config.update(update_config); + entity_gateway.save_character(&client.character); + Box::new(None.into_iter()) +} diff --git a/src/ship/packet/mod.rs b/src/ship/packet/mod.rs new file mode 100644 index 0000000..5b46ce1 --- /dev/null +++ b/src/ship/packet/mod.rs @@ -0,0 +1,2 @@ +pub mod builder; +pub mod handler; diff --git a/src/ship/room.rs b/src/ship/room.rs index b91c790..66c7830 100644 --- a/src/ship/room.rs +++ b/src/ship/room.rs @@ -117,6 +117,27 @@ impl RoomMode { RoomMode::Challenge {episode, ..} => *episode, } } + + pub fn battle(&self) -> u8 { + match self { + RoomMode::Battle {..} => 1, + _ => 0, + } + } + + pub fn challenge(&self) -> u8 { + match self { + RoomMode::Challenge {..} => 1, + _ => 0, + } + } + + pub fn single_player(&self) -> u8 { + match self { + RoomMode::Single {..} => 1, + _ => 0, + } + } } diff --git a/src/ship/ship.rs b/src/ship/ship.rs index 483e61c..595dc64 100644 --- a/src/ship/ship.rs +++ b/src/ship/ship.rs @@ -20,13 +20,15 @@ use crate::entity::gateway::EntityGateway; use crate::entity::account::{UserAccountEntity, UserSettingsEntity, USERFLAG_NEWCHAR, USERFLAG_DRESSINGROOM}; use crate::entity::character::CharacterEntity; use crate::entity::item::{ItemLocation, ItemEntity}; -use crate::login::login::get_login_status; use crate::ship::location::{ClientLocation, LobbyId, RoomId, RoomLobby, MAX_ROOMS}; use crate::ship::character::{CharacterBytesBuilder, FullCharacterBytesBuilder}; use crate::ship::items; use crate::ship::room; +use crate::ship::packet::handler; pub const SHIP_PORT: u16 = 23423; +pub type Rooms = [Option; MAX_ROOMS]; +pub type Clients = HashMap; #[derive(Debug)] pub enum ShipError { @@ -133,19 +135,19 @@ impl SendServerPacket for SendShipPacket { } } -struct ClientState { - user: UserAccountEntity, - settings: UserSettingsEntity, - character: CharacterEntity, +pub struct ClientState { + pub user: UserAccountEntity, + pub settings: UserSettingsEntity, + pub character: CharacterEntity, session: Session, //guildcard: GuildCard, - inventory: items::ActiveInventory, + pub inventory: items::ActiveInventory, //bank: Bank, - block: u32, + pub block: u32, } impl ClientState { - fn new(user: UserAccountEntity, settings: UserSettingsEntity, character: CharacterEntity, inventory: items::ActiveInventory, /*bank: Bank,*/ session: Session) -> ClientState { + pub fn new(user: UserAccountEntity, settings: UserSettingsEntity, character: CharacterEntity, inventory: items::ActiveInventory, /*bank: Bank,*/ session: Session) -> ClientState { ClientState { user: user, settings: settings, @@ -161,11 +163,11 @@ impl ClientState { pub struct ShipServerState { entity_gateway: EG, - clients: HashMap, + clients: Clients, client_location: ClientLocation, level_table: CharacterLevelTable, name: String, - rooms: [Option; MAX_ROOMS], + rooms: Rooms, item_database: items::ActiveItemDatabase, } @@ -182,483 +184,37 @@ impl ShipServerState { } } - fn validate_login(&mut self, id: ClientId, pkt: &Login) -> Result, ShipError> { - Ok(match get_login_status(&self.entity_gateway, pkt) { - Ok(user) => { - let mut response = LoginResponse::by_status(AccountStatus::Ok, Session::new()); - response.guildcard = user.id.0 as u32; - response.team_id = user.team_id.map_or(31, |ti| ti) as u32; - let characters = self.entity_gateway.get_characters_by_user(&user); - let character = characters - .get(pkt.session.character_slot as usize) - .ok_or(ShipError::InvalidSlot(id, pkt.session.character_slot as u32))?.as_ref() - .ok_or(ShipError::NoCharacterInSlot(id, pkt.session.character_slot as u32))? - .clone(); - let settings = self.entity_gateway.get_user_settings_by_user(&user) - .ok_or(ShipError::ClientNotFound(id))?; - let inventory = self.item_database.get_character_inventory(&mut self.entity_gateway, &character); - - self.clients.insert(id, ClientState::new(user, settings, character, inventory, pkt.session)); - vec![SendShipPacket::LoginResponse(response), SendShipPacket::ShipBlockList(ShipBlockList::new(&self.name, 3))] - }, - Err(err) => { - vec![SendShipPacket::LoginResponse(LoginResponse::by_status(err, Session::new()))] - } - }) - } - - fn block_selected(&mut self, id: ClientId, pkt: &MenuSelect) -> Result, ShipError> { - let client = self.clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; - client.block = pkt.item as u32; - - let (level, stats) = self.level_table.get_stats_from_exp(client.character.char_class, client.character.exp); - - let fc = FullCharacterBytesBuilder::new() - .character(&client.character) - .stats(&stats) - .level(level) - .inventory(&client.inventory) - .key_config(&client.settings.settings.key_config) - .joystick_config(&client.settings.settings.joystick_config) - .symbol_chat(&client.settings.settings.symbol_chats) - .tech_menu(&client.character.tech_menu.as_bytes()) - .build(); - - Ok(vec![ - SendShipPacket::FullCharacter(FullCharacter { - character: fc, - }), - SendShipPacket::CharDataRequest(CharDataRequest {}), - ]) - } - - fn join_room(&mut self, id: ClientId, pkt: &MenuSelect) -> Result, ShipError> { - let original_area = self.client_location.get_area(id).unwrap(); - let original_neighbors = self.client_location.get_client_neighbors(id).unwrap(); - let room = self.rooms.get(pkt.item as usize) - .ok_or_else(|| ShipError::InvalidRoom(pkt.item))?.as_ref() - .ok_or_else(|| ShipError::InvalidRoom(pkt.item))?; - if room.bursting { - return Ok(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("player is bursting\nplease wait".into())))]) - } - let room_id = RoomId(pkt.item as usize); - let original_room_clients = self.client_location.get_clients_in_room(room_id).map_err(|err| ShipError::ClientError(format!("{:?}", err)))?; - self.client_location.add_client_to_room(id, room_id).unwrap(); // TODO: show room full error or whatever - - let all_clients = self.client_location.get_clients_in_room(room_id).map_err(|err| ShipError::ClientError(format!("{:?}", err)))?; - let player_headers = all_clients.iter() - .enumerate() - .fold([PlayerHeader::default(); 4], |mut acc, (i, c)| { - let header_client = self.clients.get(&c.client).ok_or(ShipError::ClientNotFound(id)).unwrap(); - acc[i] = PlayerHeader { - tag: 0x100, - guildcard: header_client.user.id.0, - _unknown1: [0,0,0, c.local_client.id() as u32, 0], - client_id: 0, - name: libpso::utf8_to_utf16_array!(header_client.character.name, 16), - _unknown2: 2, - }; - acc - }); - - let area_client = self.client_location.get_local_client(id).map_err(|err| ShipError::ClientError(format!("{:?}", err)))?; - let leader = self.client_location.get_room_leader(room_id).map_err(|err| ShipError::ClientError(format!("{:?}", err)))?; - - let join_room = JoinRoom { - flag: all_clients.len() as u32, - maps: room.map_headers(), - players: player_headers, - client: area_client.local_client.id(), - leader: leader.local_client.id(), - one: 1, - difficulty: room.mode.difficulty().into(), - battle: matches!(room.mode, room::RoomMode::Battle {..}) as u8, - event: 0, - section: room.section_id.into(), - challenge: matches!(room.mode, room::RoomMode::Challenge {..}) as u8, - random_seed: room.random_seed, - episode: room.mode.episode().into(), - one2: 1, - single_player: 0, // TODO - unknown: 0, - }; - - let client = self.clients.get(&id).ok_or(ShipError::ClientNotFound(id))?; - let (level, stats) = self.level_table.get_stats_from_exp(client.character.char_class, client.character.exp); - let c = CharacterBytesBuilder::new() - .character(&client.character) - .stats(&stats) - .level(level - 1) - .build(); - let add_to = AddToRoom { - flag: 0x10000, - client: area_client.local_client.id(), - leader: leader.local_client.id(), - one: 0, // TODO: ?????????? - lobby: 0xff, - block: 0, - event: 0, - padding: 1, - playerinfo: PlayerInfo { - header: PlayerHeader { - tag: 0x10000, - guildcard: client.user.id.0, - _unknown1: [0; 5], - client_id: area_client.local_client.id() as u32, - name: libpso::utf8_to_utf16_array!(client.character.name, 16), - _unknown2: 2, - }, - inventory: character::Inventory { - item_count: 0, - hp_mats_used: 0, - tp_mats_used: 0, - language: 0, - items: [character::InventoryItem::default(); 30], // TOOD: this should be something - }, - character: c, - }, - }; - - let result = vec![(id, SendShipPacket::JoinRoom(join_room))] - .into_iter() - .chain(original_room_clients.clone().into_iter() - .map(|c| (c.client, SendShipPacket::AddToRoom(add_to.clone()))) - ); - - let room = self.rooms.get_mut(room_id.0).unwrap().as_mut().unwrap(); - room.bursting = true; - if let Ok(leader) = self.client_location.get_area_leader(original_area) { - let leave_lobby = SendShipPacket::LeaveLobby(LeaveLobby::new(area_client.local_client.id(), leader.local_client.id())); - Ok(result.chain(original_neighbors.into_iter() - .map(|c| (c.client, leave_lobby.clone()))).collect()) - } - else { - Ok(result.collect()) - } - } - - fn send_player_to_lobby(&mut self, id: ClientId, _pkt: &CharData) -> Result, ShipError> { - let lobby = self.client_location.add_client_to_next_available_lobby(id, LobbyId(0)).map_err(|_| ShipError::TooManyClients)?; - let clients = self.client_location.get_clients_in_lobby(lobby).map_err(|err| ShipError::ClientError(format!("{:?}", err)))?; - let playerinfo = clients.iter() - .map(|room_client| { - let client = self.clients.get(&room_client.client).ok_or(ShipError::ClientNotFound(id)).unwrap(); - let (level, stats) = self.level_table.get_stats_from_exp(client.character.char_class, client.character.exp); - let c = CharacterBytesBuilder::new() - .character(&client.character) - .stats(&stats) - .level(level - 1) - .build(); - PlayerInfo { - header: PlayerHeader { - tag: 0x100, - guildcard: client.user.id.0, - _unknown1: [0; 5], - client_id: room_client.local_client.id() as u32, - name: c.name, - _unknown2: 2, - }, - inventory: character::Inventory { - item_count: 0, - hp_mats_used: 0, - tp_mats_used: 0, - language: 0, - items: [character::InventoryItem::default(); 30], - }, - character: c, - } - }); - let area_client = self.client_location.get_local_client(id).map_err(|err| ShipError::ClientError(format!("{:?}", err)))?; - let leader = self.client_location.get_lobby_leader(lobby).map_err(|err| ShipError::ClientError(format!("{:?}", err)))?; - - let join_lobby = JoinLobby { - client: area_client.local_client.id(), - leader: leader.local_client.id(), - one: 1, - lobby: lobby.id(), - block: 1, - event: 0, - padding: 0, - playerinfo: playerinfo.collect(), - }; - - let client = self.clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; - let (level, stats) = self.level_table.get_stats_from_exp(client.character.char_class, client.character.exp); - let c = CharacterBytesBuilder::new() - .character(&client.character) - .stats(&stats) - .level(level - 1) - .build(); - let addto = AddToLobby { - flag: 1, - client: area_client.local_client.id(), - leader: leader.local_client.id(), - one: 1, - lobby: lobby.id(), - block: 1, - event: 0, - padding: 0, - playerinfo: PlayerInfo { - header: PlayerHeader { - tag: 0x100, - guildcard: client.user.id.0, - _unknown1: [0; 5], - client_id: area_client.local_client.id() as u32, - name: c.name, - _unknown2: 2, - }, - inventory: character::Inventory { - item_count: 0, - hp_mats_used: 0, - tp_mats_used: 0, - language: 0, - items: [character::InventoryItem::default(); 30], - }, - character: c, - }, - }; - - let neighbors = self.client_location.get_client_neighbors(id).unwrap(); - Ok(vec![(id, SendShipPacket::JoinLobby(join_lobby))] - .into_iter() - .chain(neighbors.into_iter() - .map(|c| (c.client, SendShipPacket::AddToLobby(addto.clone())))).collect()) - } - - fn done_bursting(&mut self, id: ClientId) -> Box + Send> { - let area = self.client_location.get_area(id).unwrap(); - if let RoomLobby::Room(room_id) = area { - let room = self.rooms.get_mut(room_id.0).unwrap().as_mut().unwrap(); - room.bursting = false; - } - Box::new(self.client_location.get_client_neighbors(id).unwrap().into_iter() - .map(move |client| { - vec![ - (client.client, SendShipPacket::BurstDone72(BurstDone72::new())), - ] - }).flatten()) - } - fn message(&mut self, id: ClientId, msg: &Message) -> Box + Send> { match &msg.msg { - GameMessage::RequestExp(killmonster) => { - match self.client_location.get_area(id).unwrap() { - RoomLobby::Room(room) => { - let r = self.rooms[room.0].as_ref().unwrap(); - warn!("killed a {:?}", r.maps.enemy_by_id(killmonster.enemy_id as usize).monster); - }, - _ => {} - } + GameMessage::RequestExp(request_exp) => { + handler::message::request_exp(id, request_exp, &self.client_location, &self.rooms) + }, + _ => { + let cmsg = msg.clone(); + Box::new(self.client_location.get_client_neighbors(id).unwrap().into_iter() + .map(move |client| { + (client.client, SendShipPacket::Message(cmsg.clone())) + })) }, - _ => {}, } - - let cmsg = msg.clone(); - Box::new(self.client_location.get_client_neighbors(id).unwrap().into_iter() - .map(move |client| { - (client.client, SendShipPacket::Message(cmsg.clone())) - })) } - /*fn generate_item_drop(&mut self, id: ClientId, monster: MonsterType) -> Option { - let room = self.rooms[self.client_location.get_area_by_user(id).index]; - let item_drop = room.drop_table.get_drop() - }*/ - fn direct_message(&mut self, id: ClientId, msg: &DirectMessage) -> Box + Send> { - let cmsg = msg.clone(); - let client = self.clients.get_mut(&id).unwrap(); - match &cmsg.msg { + let target = msg.flag; + match &msg.msg { GameMessage::GuildcardSend(guildcard_send) => { - let out_msg = DirectMessage{ - flag: cmsg.flag, - msg: GameMessage::GuildcardRecv(GuildcardRecv { - client: guildcard_send.client, - target: guildcard_send.target, - guildcard: client.user.id.0, - name: utf8_to_utf16_array!(client.character.name, 0x18), - team: [0; 0x10], // TODO: teams not yet implemented - desc: utf8_to_utf16_array!(client.character.guildcard.description, 0x58), - one: 1, - language: 0, // TODO: add language flag to character - section_id: client.character.section_id.into(), - class: client.character.char_class.into(), - }), - }; - let msg_flag = cmsg.flag as u8; - Box::new(self.client_location.get_all_clients_by_client(id).unwrap().into_iter() - .filter(move |client| client.local_client.id() == msg_flag) - .map(move |client| { - (client.client, SendShipPacket::DirectMessage(out_msg.clone())) - })) + handler::direct_message::guildcard_send(id, guildcard_send, target, &self.client_location, &self.clients) }, - /*GameMessage::RequestItem(req_item) => { - let item = self.generate_item_drop(id); - Box::new(vec![(id, SendShipPacket::Message(Message::new(GameMessage::ItemDrop(ItemDrop { - client: req_item.client, - target: req_item.target, - area: req_item.area, - variety: 0, - unknown: 0, - x: req_item.x, - z: req_item.z, - unknown2: 0, - item_bytes: item[0..12].try_into().unwrap(), - item_id: 0, - item_bytes2: item[12..16].try_into().unwrap(), - unknown3: 0, - }))))].into_iter()) - },*/ _ => { - let msg_flag = cmsg.flag as u8; + let cmsg = msg.clone(); Box::new(self.client_location.get_all_clients_by_client(id).unwrap().into_iter() - .filter(move |client| client.local_client.id() == msg_flag) + .filter(move |client| client.local_client.id() == target as u8) .map(move |client| { (client.client, SendShipPacket::DirectMessage(cmsg.clone())) })) }, } } - - fn player_chat(&mut self, id: ClientId, msg: &PlayerChat) -> Result + Send>, ShipError> { - let client = self.clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?; - let cmsg = PlayerChat::new(client.user.id.0, msg.message.clone()); - - Ok(Box::new(self.client_location.get_all_clients_by_client(id).unwrap().into_iter() - .map(move |client| { - (client.client, SendShipPacket::PlayerChat(cmsg.clone())) - }))) - } - - fn create_room(&mut self, id: ClientId, create_room: &CreateRoom) -> Box + Send> { - let area = self.client_location.get_area(id).unwrap(); - let area_client = self.client_location.get_local_client(id).unwrap(); - let lobby_neighbors = self.client_location.get_client_neighbors(id).unwrap(); - let room_id = self.client_location.create_new_room(id).unwrap(); - - let client = self.clients.get_mut(&id).unwrap();//.ok_or(ShipError::ClientNotFound(id)).unwrap(); - let mut room = room::RoomState::from_create_room(create_room, client.character.section_id).unwrap(); - room.bursting = true; - - let players = [PlayerHeader { - tag: 0x10000, - guildcard: client.user.id.0, - _unknown1: [0; 5], - client_id: 0, - name: libpso::utf8_to_utf16_array!(client.character.name, 16), - _unknown2: 2, - }, PlayerHeader::default(), PlayerHeader::default(), PlayerHeader::default()]; - - let join_room = JoinRoom { - flag: 1, - maps: room.maps.map_headers(), - players: players, - client: 0, - leader: 0, - one: 1, - difficulty: create_room.difficulty, - battle: create_room.battle, - event: 0, - section: 0, // TODO - challenge: create_room.challenge, - random_seed: 23, // TODO - episode: create_room.episode, - one2: 1, - single_player: create_room.single_player, - unknown: 0, - }; - self.rooms[room_id.0] = Some(room); - - let leader = self.client_location.get_area_leader(area); - let result = vec![(id, SendShipPacket::JoinRoom(join_room))].into_iter(); - match leader { - Ok(leader) => Box::new(result.chain(lobby_neighbors - .into_iter() - .map(move |c| { - (c.client, SendShipPacket::LeaveLobby(LeaveLobby::new(area_client.local_client.id(), leader.local_client.id()))) - }))), - Err(_) => Box::new(result) - } - } - - fn room_name_request(&mut self, id: ClientId) -> Box + Send> { - let area = self.client_location.get_area(id).unwrap(); - match area { - RoomLobby::Room(room) => Box::new(vec![(id, SendShipPacket::RoomNameResponse(RoomNameResponse {name: self.rooms[room.0].as_ref().unwrap().name.clone()}))].into_iter()), - RoomLobby::Lobby(_) => panic!() - } - } - - fn update_config(&mut self, id: ClientId, update_config: &UpdateConfig) -> Box + Send> { - let client = self.clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id)).unwrap(); - client.character.config.update(update_config); - self.entity_gateway.save_character(&client.character); - Box::new(None.into_iter()) - } - - fn request_infoboard(&mut self, id: ClientId, request_infoboard: &ViewInfoboardRequest) -> Box + Send> { - let clients = self.client_location.get_client_neighbors(id).unwrap(); - let r = clients.iter() - .filter_map(|c| { - self.clients.get(&c.client) - }) - .map(|client| { - InfoboardResponse { - name: libpso::utf8_to_utf16_array!(client.character.name, 16), - message: client.character.info_board.as_bytes(), - } - }).collect(); - Box::new(vec![(id, SendShipPacket::ViewInfoboardResponse(ViewInfoboardResponse {response: r}))].into_iter()) - } - - fn write_infoboard(&mut self, id: ClientId, new_infoboard: &WriteInfoboard) -> Box + Send> { - let client = self.clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id)).unwrap(); - client.character.info_board.update_infoboard(new_infoboard); - self.entity_gateway.save_character(&client.character); - Box::new(None.into_iter()) - } - - fn request_room_list(&mut self, id: ClientId) -> Box + Send> { - let active_room_list = self.rooms.iter() - .enumerate() - .filter_map(|(i, r)| { - r.as_ref().map(|room| { - RoomList { - menu_id: ROOM_MENU_ID, - item_id: i as u32, - difficulty: room.get_difficulty_for_room_list(), - players: self.client_location.get_clients_in_room(RoomId(i)).unwrap().len() as u8, - name: libpso::utf8_to_utf16_array!(room.name, 16), - episode: room.get_episode_for_room_list(), - flags: room.get_flags_for_room_list(), - } - }) - }); - let baseroom: RoomList = RoomList { - menu_id: ROOM_MENU_ID, - item_id: ROOM_MENU_ID, - difficulty: 0x00, - players: 0x00, - name: libpso::utf8_to_utf16_array!("Room list menu", 16), - episode: 0, - flags: 0, - }; - - Box::new(vec![(id, SendShipPacket::RoomListResponse(RoomListResponse { - baseroom, - rooms: active_room_list.collect() - }))].into_iter()) - } - - fn cool_62(&mut self, id: ClientId, cool_62: &Like62ButCooler) -> Box + Send> { - let target = cool_62.flag as u8; - let cool_62 = cool_62.clone(); - Box::new(self.client_location.get_client_neighbors(id).unwrap().into_iter() - .filter(move |client| client.local_client.id() == target) - .map(move |client| { - (client.client, SendShipPacket::Like62ButCooler(cool_62.clone())) - })) - } } impl ServerState for ShipServerState { @@ -684,17 +240,17 @@ impl ServerState for ShipServerState { -> Result + Send>, ShipError> { Ok(match pkt { RecvShipPacket::Login(login) => { - Box::new(self.validate_login(id, login)?.into_iter().map(move |pkt| (id, pkt))) + Box::new(handler::auth::validate_login(id, login, &mut self.entity_gateway, &mut self.clients, &mut self.item_database, &self.name)?.into_iter().map(move |pkt| (id, pkt))) }, RecvShipPacket::MenuSelect(menuselect) => { match menuselect.menu { - BLOCK_MENU_ID => Box::new(self.block_selected(id, menuselect)?.into_iter().map(move |pkt| (id, pkt))), - ROOM_MENU_ID => Box::new(self.join_room(id, menuselect)?.into_iter()), + BLOCK_MENU_ID => Box::new(handler::lobby::block_selected(id, menuselect, &mut self.clients, &self.level_table)?.into_iter().map(move |pkt| (id, pkt))), + ROOM_MENU_ID => handler::room::join_room(id, menuselect, &mut self.client_location, &mut self.clients, &self.level_table, &mut self.rooms)?, _ => unreachable!(), } }, RecvShipPacket::CharData(chardata) => { - Box::new(self.send_player_to_lobby(id, chardata)?.into_iter()) + Box::new(handler::lobby::send_player_to_lobby(id, chardata, &mut self.client_location, &self.clients, &self.level_table)?.into_iter()) }, RecvShipPacket::Message(msg) => { self.message(id, msg) @@ -702,40 +258,36 @@ impl ServerState for ShipServerState { RecvShipPacket::DirectMessage(msg) => { self.direct_message(id, msg) }, - RecvShipPacket::PlayerChat(msg) => { - Box::new(self.player_chat(id, msg)?.into_iter()) + Box::new(handler::communication::player_chat(id, msg, &self.client_location, &self.clients)?.into_iter()) }, RecvShipPacket::CreateRoom(create_room) => { - self.create_room(id, create_room) + handler::room::create_room(id, create_room, &mut self.client_location, &mut self.clients, &mut self.rooms)? }, RecvShipPacket::RoomNameRequest(_req) => { - self.room_name_request(id) + handler::room::room_name_request(id, &self.client_location, &self.rooms) }, RecvShipPacket::UpdateConfig(pkt) => { - self.update_config(id, pkt) + handler::settings::update_config(id, pkt, &mut self.clients, &mut self.entity_gateway) }, - RecvShipPacket::ViewInfoboardRequest(pkt) => { - self.request_infoboard(id, pkt) + handler::communication::request_infoboard(id, pkt, &self.client_location, &self.clients) }, - RecvShipPacket::WriteInfoboard(pkt) => { - self.write_infoboard(id, pkt) + handler::communication::write_infoboard(id, pkt, &mut self.clients, &mut self.entity_gateway) }, - RecvShipPacket::RoomListRequest(_req) => { - self.request_room_list(id) + handler::room::request_room_list(id, &self.client_location, &self.rooms) }, RecvShipPacket::Like62ButCooler(cool62) => { - self.cool_62(id, cool62) + handler::room::cool_62(id, cool62, &self.client_location) }, RecvShipPacket::ClientCharacterData(_) => { // TOOD: validate this in some way? Box::new(None.into_iter()) }, RecvShipPacket::DoneBursting(_) => { - self.done_bursting(id) + handler::room::done_bursting(id, &self.client_location, &mut self.rooms) } }) }