diff --git a/src/ship/location.rs b/src/ship/location.rs index 04b78fa..666b797 100644 --- a/src/ship/location.rs +++ b/src/ship/location.rs @@ -292,4 +292,14 @@ impl ClientLocation { .map(|lobby| lobby.write().unwrap().remove(id)) .any(|k| k); } + + pub fn get_client_count_in_room(&self, room_id: RoomId) -> u8 { + self.rooms[room_id.0].as_ref() + .unwrap() + .read() + .unwrap() + .clients() + .filter(|k| k.is_some()) + .count() as u8 + } } diff --git a/src/ship/room.rs b/src/ship/room.rs index 825aec6..08e49ad 100644 --- a/src/ship/room.rs +++ b/src/ship/room.rs @@ -76,7 +76,7 @@ impl Into for Difficulty { } } -#[derive(Debug)] +#[derive(Debug, Copy, Clone)] pub enum RoomMode { Single { episode: Episode, @@ -97,7 +97,7 @@ pub enum RoomMode { impl RoomMode { - fn difficulty(&self) -> Difficulty { + pub fn difficulty(&self) -> Difficulty { match self { RoomMode::Single {difficulty, ..} => *difficulty, RoomMode::Multi {difficulty, ..} => *difficulty, @@ -106,7 +106,7 @@ impl RoomMode { } } - fn episode(&self) -> Episode { + pub fn episode(&self) -> Episode { match self { RoomMode::Single {episode, ..} => *episode, RoomMode::Multi {episode, ..} => *episode, @@ -119,9 +119,9 @@ impl RoomMode { #[derive(Debug)] pub struct RoomState { - mode: RoomMode, + pub mode: RoomMode, pub name: String, - password: [u16; 16], + pub password: [u16; 16], //pub maps: [u32; 0x20], pub maps: Maps, // drop_table @@ -136,6 +136,36 @@ impl RoomState { } }*/ + pub fn get_flags_for_room_list(&self) -> u8 { + let mut flags = 0u8; + + match self.mode { + RoomMode::Single {..} => {flags += 0x04} + RoomMode::Battle {..} => {flags += 0x10}, + RoomMode::Challenge {..} => {flags += 0x20}, + _ => {flags += 0x40}, + }; + + if self.password[0] > 0 { + flags += 0x02; + } + flags + } + + pub fn get_episode_for_room_list(&self) -> u8 { + let episode: u8 = self.mode.episode().into(); + + match self.mode { + RoomMode::Single {..} => episode + 0x10, + _ => episode + 0x40, + } + } + + pub fn get_difficulty_for_room_list(&self) -> u8 { + let difficulty: u8 = self.mode.difficulty().into(); + difficulty + 0x22 + } + pub fn from_create_room(create_room: &libpso::packet::ship::CreateRoom) -> Result { if [create_room.battle, create_room.challenge, create_room.single_player].iter().sum::() > 1 { return Err(RoomCreationError::InvalidMode) @@ -165,13 +195,12 @@ impl RoomState { } }; - let ep = room_mode.episode(); Ok(RoomState { mode: room_mode, name: String::from_utf16_lossy(&create_room.name).trim_matches(char::from(0)).into(), password: create_room.password, //maps: [0; 0x20], - maps: Maps::new(ep), + maps: Maps::new(room_mode.episode()), }) } diff --git a/src/ship/ship.rs b/src/ship/ship.rs index ced4ba0..89c73fb 100644 --- a/src/ship/ship.rs +++ b/src/ship/ship.rs @@ -9,6 +9,7 @@ use libpso::packet::messages::*; use libpso::{PacketParseError, PSOPacket}; use libpso::crypto::bb::PSOBBCipher; use libpso::character::character; +use libpso::packet::ship::{ROOM_MENU_ID}; use crate::common::cipherkeys::{ELSEWHERE_PRIVATE_KEY, ELSEWHERE_PARRAY}; use crate::common::serverstate::{SendServerPacket, RecvServerPacket, ServerState, OnConnect, ClientId}; @@ -46,6 +47,7 @@ pub enum RecvShipPacket { UpdateConfig(UpdateConfig), ViewInfoboardRequest(ViewInfoboardRequest), WriteInfoboard(WriteInfoboard), + RoomListRequest(RoomListRequest), } impl RecvServerPacket for RecvShipPacket { @@ -62,6 +64,7 @@ impl RecvServerPacket for RecvShipPacket { 0x7ED => Ok(RecvShipPacket::UpdateConfig(UpdateConfig::from_bytes(data)?)), 0xD8 => Ok(RecvShipPacket::ViewInfoboardRequest(ViewInfoboardRequest::from_bytes(data)?)), 0xD9 => Ok(RecvShipPacket::WriteInfoboard(WriteInfoboard::from_bytes(data)?)), + 0x08 => Ok(RecvShipPacket::RoomListRequest(RoomListRequest::from_bytes(data)?)), _ => Err(PacketParseError::WrongPacketForServerType(u16::from_le_bytes([data[2], data[3]]), data.to_vec())) } } @@ -86,6 +89,7 @@ pub enum SendShipPacket { LeaveRoom(LeaveRoom), RoomNameResponse(RoomNameResponse), ViewInfoboardResponse(ViewInfoboardResponse), + RoomListResponse(RoomListResponse), } impl SendServerPacket for SendShipPacket { @@ -108,11 +112,11 @@ impl SendServerPacket for SendShipPacket { SendShipPacket::LeaveRoom(pkt) => pkt.as_bytes(), SendShipPacket::RoomNameResponse(pkt) => pkt.as_bytes(), SendShipPacket::ViewInfoboardResponse(pkt) => pkt.as_bytes(), + SendShipPacket::RoomListResponse(pkt) => pkt.as_bytes(), } } } - struct ClientState { user: UserAccount, settings: UserSettings, @@ -137,12 +141,6 @@ impl ClientState { } } - - - - - - pub struct ShipServerState { entity_gateway: EG, clients: HashMap, @@ -439,8 +437,39 @@ impl ShipServerState { self.entity_gateway.set_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_client_count_in_room(RoomId(i)), // TODO + 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()) + } +} impl ServerState for ShipServerState { type SendPacket = SendShipPacket; @@ -503,6 +532,10 @@ impl ServerState for ShipServerState { RecvShipPacket::WriteInfoboard(pkt) => { self.write_infoboard(id, pkt) }, + + RecvShipPacket::RoomListRequest(_req) => { + self.request_room_list(id) + }, }) }