From f38e3357f46a31b691c28ccb1340a5ecd0f1463a Mon Sep 17 00:00:00 2001 From: jake Date: Tue, 21 Apr 2020 23:15:11 -0600 Subject: [PATCH] move room packet handlers to own file --- src/ship/packet/handler/mod.rs | 1 + src/ship/packet/handler/room.rs | 253 ++++++++++++++++++++++++++++++++ src/ship/ship.rs | 235 +---------------------------- 3 files changed, 262 insertions(+), 227 deletions(-) create mode 100644 src/ship/packet/handler/room.rs diff --git a/src/ship/packet/handler/mod.rs b/src/ship/packet/handler/mod.rs index 337c58f..df41e32 100644 --- a/src/ship/packet/handler/mod.rs +++ b/src/ship/packet/handler/mod.rs @@ -1,2 +1,3 @@ pub mod auth; pub mod lobby; +pub mod room; diff --git a/src/ship/packet/handler/room.rs b/src/ship/packet/handler/room.rs new file mode 100644 index 0000000..3553dda --- /dev/null +++ b/src/ship/packet/handler/room.rs @@ -0,0 +1,253 @@ +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}; +use crate::ship::character::{CharacterBytesBuilder, FullCharacterBytesBuilder}; +use crate::ship::location::{ClientLocation, LobbyId, RoomId, RoomLobby, MAX_ROOMS}; +use libpso::character::character; +use crate::ship::room; + +pub fn create_room(id: ClientId, + create_room: &CreateRoom, + client_location: &mut ClientLocation, + clients: &mut HashMap, + rooms: &mut Rooms) + -> Box + Send> { + 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 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, + }; + rooms[room_id.0] = Some(room); + + let leader = 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) + } +} + +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 HashMap, + level_table: &CharacterLevelTable, + rooms: &mut Rooms) + -> Result, 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(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("player is bursting\nplease wait".into())))]) + } + 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 all_clients = 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 = 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 = 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 = 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 = clients.get(&id).ok_or(ShipError::ClientNotFound(id))?; + let (level, stats) = 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 = rooms.get_mut(room_id.0).unwrap().as_mut().unwrap(); + room.bursting = true; + 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())); + Ok(result.chain(original_neighbors.into_iter() + .map(|c| (c.client, leave_lobby.clone()))).collect()) + } + else { + Ok(result.collect()) + } +} + +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/ship.rs b/src/ship/ship.rs index b13ec3a..dc47b89 100644 --- a/src/ship/ship.rs +++ b/src/ship/ship.rs @@ -27,6 +27,7 @@ use crate::ship::room; use crate::ship::packet::handler; pub const SHIP_PORT: u16 = 23423; +pub type Rooms = [Option; MAX_ROOMS]; #[derive(Debug)] pub enum ShipError { @@ -165,7 +166,7 @@ pub struct ShipServerState { client_location: ClientLocation, level_table: CharacterLevelTable, name: String, - rooms: [Option; MAX_ROOMS], + rooms: Rooms, item_database: items::ActiveItemDatabase, } @@ -182,7 +183,6 @@ impl ShipServerState { } } - 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; @@ -208,126 +208,9 @@ impl ShipServerState { ]) } - 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 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) => { @@ -419,65 +302,6 @@ impl ShipServerState { }))) } - 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); @@ -507,47 +331,6 @@ impl ShipServerState { 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 { @@ -578,7 +361,7 @@ impl ServerState for ShipServerState { 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()), + ROOM_MENU_ID => Box::new(handler::room::join_room(id, menuselect, &mut self.client_location, &mut self.clients, &self.level_table, &mut self.rooms)?.into_iter()), _ => unreachable!(), } }, @@ -596,10 +379,10 @@ impl ServerState for ShipServerState { Box::new(self.player_chat(id, msg)?.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) @@ -608,23 +391,21 @@ impl ServerState for ShipServerState { RecvShipPacket::ViewInfoboardRequest(pkt) => { self.request_infoboard(id, pkt) }, - RecvShipPacket::WriteInfoboard(pkt) => { self.write_infoboard(id, pkt) }, - 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) } }) }