2020-04-21 23:15:11 -06:00
use libpso ::packet ::ship ::* ;
2020-05-24 15:59:48 -06:00
use libpso ::packet ::messages ::* ;
2020-04-21 23:15:11 -06:00
use crate ::common ::serverstate ::ClientId ;
2022-08-02 00:08:55 -06:00
use crate ::common ::leveltable ::LEVEL_TABLE ;
2020-05-02 22:08:37 -03:00
use crate ::ship ::ship ::{ SendShipPacket , ShipError , Rooms , Clients } ;
use crate ::ship ::location ::{ ClientLocation , RoomId , RoomLobby , ClientLocationError } ;
2020-04-24 20:38:56 -06:00
use crate ::ship ::packet ::builder ;
2020-04-21 23:15:11 -06:00
use crate ::ship ::room ;
2022-05-14 13:06:40 -06:00
use crate ::ship ::items ::state ::ItemState ;
2021-05-23 18:18:36 +00:00
use std ::convert ::{ TryFrom } ;
2022-09-18 21:01:32 -06:00
use futures ::StreamExt ;
pub async fn create_room ( id : ClientId ,
create_room : & CreateRoom ,
client_location : & mut ClientLocation ,
clients : & mut Clients ,
item_state : & mut ItemState ,
rooms : & mut Rooms )
-> Result < Box < dyn Iterator < Item = ( ClientId , SendShipPacket ) > + Send > , anyhow ::Error > {
2021-05-23 18:18:36 +00:00
let client = clients . get ( & id ) . ok_or ( ShipError ::ClientNotFound ( id ) ) ? ;
2022-08-02 00:08:55 -06:00
let level = LEVEL_TABLE . get_level_from_exp ( client . character . char_class , client . character . exp ) ;
2021-05-23 18:18:36 +00:00
match room ::Difficulty ::try_from ( create_room . difficulty ) ? {
room ::Difficulty ::Ultimate = > {
if level < 80 {
2021-06-22 23:23:22 +00:00
return Ok ( Box ::new ( vec! [ ( id , SendShipPacket ::SmallDialog ( SmallDialog ::new ( " You must be at least level 80 \n to create Ultimate rooms. " . into ( ) ) ) ) ] . into_iter ( ) ) )
2021-05-23 18:18:36 +00:00
}
} ,
room ::Difficulty ::VeryHard = > {
if level < 40 {
2021-06-22 23:23:22 +00:00
return Ok ( Box ::new ( vec! [ ( id , SendShipPacket ::SmallDialog ( SmallDialog ::new ( " You must be at least level 40 \n to create Very Hard rooms. " . into ( ) ) ) ) ] . into_iter ( ) ) )
2021-05-23 18:18:36 +00:00
}
} ,
room ::Difficulty ::Hard = > {
if level < 20 {
2021-06-22 23:23:22 +00:00
return Ok ( Box ::new ( vec! [ ( id , SendShipPacket ::SmallDialog ( SmallDialog ::new ( " You must be at least level 20 \n to create Hard rooms. " . into ( ) ) ) ) ] . into_iter ( ) ) )
2021-05-23 18:18:36 +00:00
}
} ,
2021-06-23 01:03:54 +00:00
room ::Difficulty ::Normal = > { } ,
2021-05-23 18:18:36 +00:00
} ;
2022-09-18 21:01:32 -06:00
let area = client_location . get_area ( id ) . await . unwrap ( ) ;
let area_client = client_location . get_local_client ( id ) . await . unwrap ( ) ;
let lobby_neighbors = client_location . get_client_neighbors ( id ) . await . unwrap ( ) ;
let room_id = client_location . create_new_room ( id ) . await . unwrap ( ) ;
2020-04-21 23:15:11 -06:00
let mut room = room ::RoomState ::from_create_room ( create_room , client . character . section_id ) . unwrap ( ) ;
room . bursting = true ;
2022-05-14 13:06:40 -06:00
item_state . add_character_to_room ( room_id , & client . character , area_client ) ;
2020-05-13 22:32:30 -06:00
2022-09-18 21:01:32 -06:00
let join_room = builder ::room ::join_room ( id , clients , client_location , room_id , & room ) . await ? ;
2020-04-21 23:15:11 -06:00
rooms [ room_id . 0 ] = Some ( room ) ;
2020-04-24 22:22:19 -06:00
let mut result : Box < dyn Iterator < Item = ( ClientId , SendShipPacket ) > + Send > = Box ::new (
vec! [ ( id , SendShipPacket ::JoinRoom ( join_room ) ) ] . into_iter ( )
) ;
2022-09-18 21:01:32 -06:00
if let Ok ( leader ) = client_location . get_area_leader ( area ) . await {
2020-04-24 22:22:19 -06:00
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 ( ) )
} ) ) ) ;
2020-04-21 23:15:11 -06:00
}
2020-04-24 22:22:19 -06:00
Ok ( result )
2020-04-21 23:15:11 -06:00
}
2022-09-18 21:01:32 -06:00
pub async fn room_name_request ( id : ClientId ,
client_location : & ClientLocation ,
rooms : & Rooms )
-> Box < dyn Iterator < Item = ( ClientId , SendShipPacket ) > + Send > {
let area = client_location . get_area ( id ) . await . unwrap ( ) ;
2020-04-21 23:15:11 -06:00
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! ( )
}
}
2022-09-18 21:01:32 -06:00
pub async fn join_room ( id : ClientId ,
pkt : & MenuSelect ,
client_location : & mut ClientLocation ,
clients : & mut Clients ,
item_state : & mut ItemState ,
rooms : & mut Rooms )
-> Result < Box < dyn Iterator < Item = ( ClientId , SendShipPacket ) > + Send > , ShipError > {
2021-05-23 18:18:36 +00:00
let client = clients . get ( & id ) . ok_or ( ShipError ::ClientNotFound ( id ) ) ? ;
2022-08-02 00:08:55 -06:00
let level = LEVEL_TABLE . get_level_from_exp ( client . character . char_class , client . character . exp ) ;
2022-07-07 00:00:04 +00:00
// let room = rooms.get(pkt.item as usize).ok_or(ShipError::InvalidRoom(pkt.item))?.as_ref().unwrap(); // clippy look what you made me do
if let Some ( room ) = rooms . get ( pkt . item as usize ) . ok_or ( ShipError ::InvalidRoom ( pkt . item ) ) ? {
match room . mode . difficulty ( ) {
room ::Difficulty ::Ultimate = > {
if level < 80 {
return Ok ( Box ::new ( vec! [ ( id , SendShipPacket ::SmallDialog ( SmallDialog ::new ( " You must be at least level 80 \n to join Ultimate rooms. " . into ( ) ) ) ) ] . into_iter ( ) ) )
}
} ,
room ::Difficulty ::VeryHard = > {
if level < 40 {
return Ok ( Box ::new ( vec! [ ( id , SendShipPacket ::SmallDialog ( SmallDialog ::new ( " You must be at least level 40 \n to join Very Hard rooms. " . into ( ) ) ) ) ] . into_iter ( ) ) )
}
} ,
room ::Difficulty ::Hard = > {
if level < 20 {
return Ok ( Box ::new ( vec! [ ( id , SendShipPacket ::SmallDialog ( SmallDialog ::new ( " You must be at least level 20 \n to join Hard rooms. " . into ( ) ) ) ) ] . into_iter ( ) ) )
}
} ,
_ = > { } ,
} ;
2022-09-18 21:01:32 -06:00
let original_area = client_location . get_area ( id ) . await . unwrap ( ) ;
let original_neighbors = client_location . get_client_neighbors ( id ) . await . unwrap ( ) ;
2022-07-07 00:00:04 +00:00
if room . bursting {
return Ok ( Box ::new ( vec! [ ( id , SendShipPacket ::SmallDialog ( SmallDialog ::new ( " player is bursting \n please wait " . into ( ) ) ) ) ] . into_iter ( ) ) )
}
let room_id = RoomId ( pkt . item as usize ) ;
2022-09-18 21:01:32 -06:00
let original_room_clients = client_location . get_clients_in_room ( room_id ) . await . map_err ( | err | -> ClientLocationError { err . into ( ) } ) ? ;
client_location . add_client_to_room ( id , room_id ) . await . unwrap ( ) ; // TODO: show room full error or whatever
2022-07-07 00:00:04 +00:00
let client = clients . get ( & id ) . ok_or ( ShipError ::ClientNotFound ( id ) ) ? ;
2022-09-18 21:01:32 -06:00
let area_client = client_location . get_local_client ( id ) . await . map_err ( | err | -> ClientLocationError { err . into ( ) } ) ? ;
2022-07-07 00:00:04 +00:00
2022-07-25 17:18:04 +00:00
item_state . add_character_to_room ( room_id , & client . character , area_client ) ;
2022-07-07 00:00:04 +00:00
2022-09-18 21:01:32 -06:00
let leader = client_location . get_room_leader ( room_id ) . await . map_err ( | err | -> ClientLocationError { err . into ( ) } ) ? ;
let join_room = builder ::room ::join_room ( id , clients , client_location , room_id , room ) . await ? ;
2022-08-02 00:08:55 -06:00
let add_to = builder ::room ::add_to_room ( id , client , & area_client , & leader , item_state , room_id ) ? ;
2022-07-07 00:00:04 +00:00
let room = rooms . get_mut ( room_id . 0 ) . unwrap ( ) . as_mut ( ) . unwrap ( ) ;
room . bursting = true ;
let mut result : Box < dyn Iterator < Item = ( ClientId , SendShipPacket ) > + Send > = Box ::new (
vec! [ ( id , SendShipPacket ::JoinRoom ( join_room ) ) ]
. into_iter ( )
. chain ( original_room_clients . into_iter ( )
. map ( move | c | ( c . client , SendShipPacket ::AddToRoom ( add_to . clone ( ) ) ) )
) ) ;
2022-09-18 21:01:32 -06:00
if let Ok ( leader ) = client_location . get_area_leader ( original_area ) . await {
2022-07-07 00:00:04 +00:00
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 )
} else {
Ok ( Box ::new ( vec! [ ( id , SendShipPacket ::SmallDialog ( SmallDialog ::new ( " Game is no longer active " . into ( ) ) ) ) ] . into_iter ( ) ) )
2020-04-21 23:15:11 -06:00
}
}
2022-09-18 21:01:32 -06:00
pub async fn done_bursting ( id : ClientId ,
client_location : & ClientLocation ,
rooms : & mut Rooms )
-> Box < dyn Iterator < Item = ( ClientId , SendShipPacket ) > + Send > {
let area = client_location . get_area ( id ) . await . unwrap ( ) ;
2021-02-20 22:29:40 +00:00
let mut rare_monster_list : Option < Vec < u16 > > = None ;
2020-04-21 23:15:11 -06:00
if let RoomLobby ::Room ( room_id ) = area {
2021-06-18 12:18:29 -06:00
if let Some ( room ) = rooms . get_mut ( room_id . 0 ) . unwrap ( ) . as_mut ( ) {
2020-05-24 18:42:37 -06:00
room . bursting = false ;
2021-02-20 22:29:40 +00:00
rare_monster_list = Some ( room . maps . get_rare_monster_list ( ) ) ;
2021-06-25 23:00:57 +00:00
} ;
2020-04-21 23:15:11 -06:00
}
2022-09-18 21:01:32 -06:00
let area_client = client_location . get_local_client ( id ) . await . unwrap ( ) ; // TODO: unwrap
2021-02-20 22:29:40 +00:00
let mut result : Box < dyn Iterator < Item = ( ClientId , SendShipPacket ) > + Send > = Box ::new (
2022-09-18 21:01:32 -06:00
client_location . get_client_neighbors ( id ) . await . unwrap ( ) . into_iter ( ) // TODO: unwrap
2021-12-29 15:46:22 -07:00
. flat_map ( move | client | {
2020-05-24 15:59:48 -06:00
vec! [
( client . client , SendShipPacket ::Message ( Message ::new ( GameMessage ::BurstDone ( BurstDone {
2020-05-24 18:42:37 -06:00
client : area_client . local_client . id ( ) ,
2020-05-24 15:59:48 -06:00
target : 0
} ) ) ) ) ,
]
2021-02-20 22:29:40 +00:00
} )
) ;
2021-07-18 18:40:10 +00:00
// TODO: check how often `done_bursting` is called. ie: make sure it's only used when joining a room and not each time a player warps in a pipe
2021-07-24 01:32:58 +00:00
if let Some ( rare_list ) = rare_monster_list {
let rare_monster_packet = SendShipPacket ::RareMonsterList ( builder ::room ::build_rare_monster_list ( rare_list ) ) ;
2021-07-18 18:40:10 +00:00
result = Box ::new ( result . chain ( vec! [ ( id , rare_monster_packet ) ] ) ) ; // TODO: make sure we arent clobbering `result` here
2021-02-20 22:29:40 +00:00
}
result
2020-05-24 15:59:48 -06:00
}
2022-09-18 21:01:32 -06:00
pub async fn request_room_list ( id : ClientId ,
client_location : & ClientLocation ,
rooms : & Rooms )
-> Box < dyn Iterator < Item = ( ClientId , SendShipPacket ) > + Send > {
let active_room_list = futures ::stream ::iter ( rooms . iter ( ) )
2020-04-21 23:15:11 -06:00
. enumerate ( )
2022-09-18 21:01:32 -06:00
. filter_map ( | ( i , r ) | async move {
r . as_ref ( ) . map ( | room | async move {
2020-04-21 23:15:11 -06:00
RoomList {
menu_id : ROOM_MENU_ID ,
item_id : i as u32 ,
difficulty : room . get_difficulty_for_room_list ( ) ,
2022-09-18 21:01:32 -06:00
players : client_location . get_clients_in_room ( RoomId ( i ) ) . await . unwrap ( ) . len ( ) as u8 ,
2020-04-21 23:15:11 -06:00
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 ,
2022-09-18 21:01:32 -06:00
rooms : futures ::future ::join_all ( active_room_list . collect ::< Vec < _ > > ( ) . await ) . await
2020-04-21 23:15:11 -06:00
} ) ) ] . into_iter ( ) )
}
2022-09-18 21:01:32 -06:00
pub async fn cool_62 ( id : ClientId ,
cool_62 : & Like62ButCooler ,
client_location : & ClientLocation )
-> Box < dyn Iterator < Item = ( ClientId , SendShipPacket ) > + Send > {
2020-04-21 23:15:11 -06:00
let target = cool_62 . flag as u8 ;
let cool_62 = cool_62 . clone ( ) ;
2022-09-18 21:01:32 -06:00
Box ::new ( client_location . get_client_neighbors ( id ) . await . unwrap ( ) . into_iter ( )
2020-04-21 23:15:11 -06:00
. filter ( move | client | client . local_client . id ( ) = = target )
. map ( move | client | {
( client . client , SendShipPacket ::Like62ButCooler ( cool_62 . clone ( ) ) )
} ) )
}