You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

301 lines
13 KiB

1 year ago
4 years ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
1 year ago
4 years ago
1 year ago
  1. use std::convert::{TryFrom, Into};
  2. use futures::stream::StreamExt;
  3. use async_std::sync::Arc;
  4. use libpso::packet::ship::*;
  5. use libpso::packet::messages::*;
  6. use crate::common::serverstate::ClientId;
  7. use crate::common::leveltable::LEVEL_TABLE;
  8. use crate::entity::gateway::EntityGateway;
  9. use crate::entity::character::SectionID;
  10. use crate::entity::room::{NewRoomEntity, RoomEntityMode, RoomNote};
  11. use crate::ship::drops::DropTable;
  12. use crate::ship::ship::{SendShipPacket, Clients, ShipEvent};
  13. use crate::ship::room::{Rooms, Episode, Difficulty, RoomState, RoomMode};
  14. use crate::ship::map::Maps;
  15. use crate::ship::location::{ClientLocation, RoomId, RoomLobby, GetAreaError};
  16. use crate::ship::packet::builder;
  17. use crate::ship::items::state::ItemState;
  18. #[allow(clippy::too_many_arguments)]
  19. pub async fn create_room<EG>(id: ClientId,
  20. create_room: CreateRoom,
  21. entity_gateway: &mut EG,
  22. client_location: &mut ClientLocation,
  23. clients: &Clients,
  24. item_state: &mut ItemState,
  25. rooms: &Rooms,
  26. map_builder: Arc<Box<dyn Fn(RoomMode, ShipEvent) -> Maps + Send + Sync>>,
  27. drop_table_builder: Arc<Box<dyn Fn(Episode, Difficulty, SectionID) -> DropTable + Send + Sync>>,
  28. event: ShipEvent)
  29. -> Result<Vec<(ClientId, SendShipPacket)>, anyhow::Error>
  30. where
  31. EG: EntityGateway + Clone + 'static,
  32. {
  33. let level = clients.with(id, |client| Box::pin(async move {
  34. LEVEL_TABLE.get_level_from_exp(client.character.char_class, client.character.exp)
  35. })).await?;
  36. let difficulty = Difficulty::try_from(create_room.difficulty)?;
  37. match difficulty {
  38. Difficulty::Ultimate if level < 80 => {
  39. return Ok(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("You must be at least level 80 \nto create Ultimate rooms.".into())))])
  40. },
  41. Difficulty::VeryHard if level < 40 => {
  42. return Ok(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("You must be at least level 40 \nto create Very Hard rooms.".into())))])
  43. },
  44. Difficulty::Hard if level < 20 => {
  45. return Ok(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("You must be at least level 20 \nto create Hard rooms.".into())))])
  46. },
  47. _ => {},
  48. };
  49. let area = client_location.get_area(id).await?;
  50. let old_area_client = client_location.get_local_client(id).await?;
  51. let lobby_neighbors = client_location.get_client_neighbors(id).await?;
  52. let room_id = client_location.create_new_room(id).await?;
  53. let new_area_client = client_location.get_local_client(id).await?;
  54. let name = String::from_utf16_lossy(&create_room.name).trim_matches(char::from(0)).to_string();
  55. let mode = match (create_room.battle, create_room.challenge, create_room.single_player) {
  56. (1, 0, 0) => RoomEntityMode::Battle,
  57. (0, 1, 0) => RoomEntityMode::Challenge,
  58. (0, 0, 1) => RoomEntityMode::Single,
  59. _ => RoomEntityMode::Multi,
  60. };
  61. let episode = create_room.episode.try_into()?;
  62. let difficulty = create_room.difficulty.try_into()?;
  63. let room = clients.with(id, |client| {
  64. let mut item_state = item_state.clone();
  65. let mut entity_gateway = entity_gateway.clone();
  66. Box::pin(async move {
  67. item_state.add_character_to_room(room_id, &client.character, new_area_client).await;
  68. let room_entity = entity_gateway.create_room(NewRoomEntity {
  69. name: name.clone(),
  70. section_id: client.character.section_id,
  71. mode,
  72. episode,
  73. difficulty,
  74. }).await?;
  75. entity_gateway.add_room_note(room_entity.id, RoomNote::Create {
  76. character_id: client.character.id,
  77. }).await?;
  78. let mut room = RoomState::new(room_entity.id, mode, episode, difficulty,
  79. client.character.section_id, name, create_room.password, event,
  80. map_builder, drop_table_builder)?;
  81. room.bursting = true;
  82. Ok::<_, anyhow::Error>(room)
  83. })}).await??;
  84. let join_room = builder::room::join_room(id, clients, client_location, room_id, &room, event).await?;
  85. rooms.add(room_id, room).await?;
  86. let mut result = vec![(id, SendShipPacket::JoinRoom(join_room))];
  87. if let Ok(leader) = client_location.get_area_leader(area).await {
  88. let leave_lobby = SendShipPacket::LeaveLobby(LeaveLobby::new(old_area_client.local_client.id(), leader.local_client.id()));
  89. result.extend(lobby_neighbors
  90. .into_iter()
  91. .map(move |c| {
  92. (c.client, leave_lobby.clone())
  93. }));
  94. }
  95. Ok(result)
  96. }
  97. pub async fn room_name_request(id: ClientId,
  98. client_location: &ClientLocation,
  99. rooms: &Rooms)
  100. -> Result<Vec<(ClientId, SendShipPacket)>, anyhow::Error> {
  101. let area = client_location.get_area(id).await?;
  102. match area {
  103. RoomLobby::Room(room) => {
  104. rooms.with(room, |room| Box::pin(async move {
  105. vec![(id, SendShipPacket::RoomNameResponse(RoomNameResponse {
  106. name: room.name.clone()
  107. }))]
  108. })).await
  109. },
  110. RoomLobby::Lobby(_) => Err(GetAreaError::NotInRoom.into())
  111. }
  112. }
  113. #[allow(clippy::too_many_arguments)]
  114. pub async fn join_room<EG>(id: ClientId,
  115. pkt: MenuSelect,
  116. entity_gateway: &mut EG,
  117. client_location: &mut ClientLocation,
  118. clients: &Clients,
  119. item_state: &mut ItemState,
  120. rooms: &Rooms,
  121. event: ShipEvent)
  122. -> Result<Vec<(ClientId, SendShipPacket)>, anyhow::Error>
  123. where
  124. EG: EntityGateway + Clone + 'static,
  125. {
  126. let room_id = RoomId(pkt.item as usize);
  127. if !rooms.exists(room_id).await {
  128. return Ok(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("This room no longer exists!".into())))])
  129. }
  130. let level = clients.with(id, |client| Box::pin(async move {
  131. LEVEL_TABLE.get_level_from_exp(client.character.char_class, client.character.exp)
  132. })).await?;
  133. let (difficulty, bursting, room_entity_id) = rooms.with(room_id, |room| Box::pin(async move {
  134. (room.mode.difficulty(), room.bursting, room.room_id)
  135. })).await?;
  136. match difficulty {
  137. Difficulty::Ultimate if level < 80 => {
  138. return Ok(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("You must be at least level 80 \nto join Ultimate rooms.".into())))])
  139. },
  140. Difficulty::VeryHard if level < 40 => {
  141. return Ok(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("You must be at least level 40 \nto join Very Hard rooms.".into())))])
  142. },
  143. Difficulty::Hard if level < 20 => {
  144. return Ok(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("You must be at least level 20 \nto join Hard rooms.".into())))])
  145. },
  146. _ => {},
  147. }
  148. if bursting {
  149. return Ok(vec![(id, SendShipPacket::SmallDialog(SmallDialog::new("player is bursting\nplease wait".into())))])
  150. }
  151. let original_area = client_location.get_area(id).await?;
  152. let original_neighbors = client_location.get_client_neighbors(id).await?;
  153. let original_room_clients = client_location.get_clients_in_room(room_id).await?;
  154. client_location.add_client_to_room(id, room_id).await?;
  155. let area_client = client_location.get_local_client(id).await?;
  156. let room_leader = client_location.get_room_leader(room_id).await?;
  157. clients.with(id, |client| {
  158. let mut item_state = item_state.clone();
  159. let mut entity_gateway = entity_gateway.clone();
  160. Box::pin(async move {
  161. entity_gateway.add_room_note(room_entity_id, RoomNote::PlayerJoin {
  162. character_id: client.character.id,
  163. }).await?;
  164. item_state.add_character_to_room(room_id, &client.character, area_client).await;
  165. Ok::<_, anyhow::Error>(())
  166. })}).await??;
  167. let join_room = rooms.with(room_id, |room| {
  168. let clients = clients.clone();
  169. let client_location = client_location.clone();
  170. Box::pin(async move {
  171. builder::room::join_room(id, &clients, &client_location, room_id, room, event).await
  172. })}).await??;
  173. let add_to = clients.with(id, |client| {
  174. let item_state = item_state.clone();
  175. Box::pin(async move {
  176. builder::room::add_to_room(id, client, &area_client, &room_leader, &item_state, event).await
  177. })}).await??;
  178. rooms.with_mut(room_id, |room| Box::pin(async move {
  179. room.bursting = true;
  180. })).await?;
  181. Ok(vec![(id, SendShipPacket::JoinRoom(join_room))]
  182. .into_iter()
  183. .chain(original_room_clients.into_iter()
  184. .map(move |c| (c.client, SendShipPacket::AddToRoom(add_to.clone()))))
  185. .chain(futures::stream::iter(original_neighbors.into_iter())
  186. .filter_map(|c| {
  187. let client_location = client_location.clone();
  188. async move {
  189. client_location.get_area_leader(original_area).await.ok().map(|leader| {
  190. let leave_lobby = SendShipPacket::LeaveLobby(LeaveLobby::new(area_client.local_client.id(), leader.local_client.id()));
  191. (c.client, leave_lobby)
  192. })
  193. }
  194. })
  195. .collect::<Vec<_>>()
  196. .await
  197. )
  198. .collect())
  199. }
  200. pub async fn done_bursting(id: ClientId,
  201. client_location: &ClientLocation,
  202. rooms: &Rooms)
  203. -> Result<Vec<(ClientId, SendShipPacket)>, anyhow::Error> {
  204. let room_id = client_location.get_room(id).await?;
  205. let rare_monster_list = rooms.with_mut(room_id, |room| Box::pin(async move {
  206. room.bursting = false;
  207. room.maps.get_rare_monster_list()
  208. })).await?;
  209. let area_client = client_location.get_local_client(id).await?;
  210. Ok(client_location.get_client_neighbors(id).await?.into_iter()
  211. .map(move |client| {
  212. (client.client, SendShipPacket::Message(Message::new(GameMessage::BurstDone(BurstDone {
  213. client: area_client.local_client.id(),
  214. target: 0
  215. }))))
  216. })
  217. .chain(std::iter::once_with(move || {
  218. (id, SendShipPacket::RareMonsterList(builder::room::build_rare_monster_list(rare_monster_list)))
  219. }))
  220. .collect())
  221. }
  222. pub async fn request_room_list(id: ClientId,
  223. client_location: &ClientLocation,
  224. rooms: &Rooms)
  225. -> Vec<(ClientId, SendShipPacket)> {
  226. let active_room_list = rooms.stream()
  227. .enumerate()
  228. .filter_map(|(i, r)| async move {
  229. r.as_ref().map(|room| {
  230. let difficulty = room.get_difficulty_for_room_list();
  231. let name = libpso::utf8_to_utf16_array!(room.name, 16);
  232. let episode = room.get_episode_for_room_list();
  233. let flags = room.get_flags_for_room_list();
  234. async move {
  235. RoomList {
  236. menu_id: ROOM_MENU_ID,
  237. item_id: i as u32,
  238. difficulty,
  239. players: client_location.get_clients_in_room(RoomId(i)).await.unwrap().len() as u8,
  240. name,
  241. episode,
  242. flags,
  243. }
  244. }})
  245. });
  246. let baseroom: RoomList = RoomList {
  247. menu_id: ROOM_MENU_ID,
  248. item_id: ROOM_MENU_ID,
  249. difficulty: 0x00,
  250. players: 0x00,
  251. name: libpso::utf8_to_utf16_array!("Room list menu", 16),
  252. episode: 0,
  253. flags: 0,
  254. };
  255. vec![(id, SendShipPacket::RoomListResponse(RoomListResponse {
  256. baseroom,
  257. rooms: futures::future::join_all(active_room_list.collect::<Vec<_>>().await).await
  258. }))]
  259. }
  260. pub async fn cool_62(id: ClientId,
  261. cool_62: Like62ButCooler,
  262. client_location: &ClientLocation)
  263. -> Result<Vec<(ClientId, SendShipPacket)>, anyhow::Error> {
  264. let target = cool_62.flag as u8;
  265. let cool_62 = cool_62.clone();
  266. Ok(client_location
  267. .get_client_neighbors(id)
  268. .await?
  269. .into_iter()
  270. .filter(move |client| client.local_client.id() == target)
  271. .map(move |client| {
  272. (client.client, SendShipPacket::Like62ButCooler(cool_62.clone()))
  273. })
  274. .collect())
  275. }