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.

244 lines
9.9 KiB

4 years ago
4 years ago
1 year ago
1 year ago
1 year ago
4 years ago
4 years ago
1 year ago
4 years ago
4 years ago
1 year ago
4 years ago
4 years ago
1 year ago
4 years ago
1 year ago
4 years ago
1 year ago
4 years ago
4 years ago
4 years ago
1 year ago
1 year ago
1 year ago
4 years ago
1 year ago
1 year ago
4 years ago
4 years ago
4 years ago
4 years ago
1 year ago
4 years ago
1 year ago
1 year ago
4 years ago
4 years ago
4 years ago
4 years ago
  1. use std::io::{Cursor, Read, Seek, SeekFrom};
  2. use futures::stream::{FuturesOrdered, StreamExt};
  3. use libpso::packet::ship::*;
  4. use crate::common::serverstate::ClientId;
  5. use crate::ship::ship::{SendShipPacket, ShipError, Clients, ShipEvent};
  6. use crate::ship::room::Rooms;
  7. use crate::ship::map::enemy::RareMonsterAppearTable;
  8. use crate::ship::location::{ClientLocation};
  9. use crate::ship::packet::builder::quest;
  10. use libpso::util::array_to_utf8;
  11. enum QuestFileType {
  12. Bin,
  13. Dat
  14. }
  15. fn parse_filename(filename_bytes: &[u8; 16]) -> Result<(u16, u16, QuestFileType), anyhow::Error> {
  16. let filename = array_to_utf8(*filename_bytes).map_err(|_| ShipError::InvalidQuestFilename("NOT UTF8".to_string()))?;
  17. let (filename, suffix) = {
  18. let mut s = filename.splitn(2, '.');
  19. (s.next().ok_or_else(|| ShipError::InvalidQuestFilename(filename.to_owned()))?,
  20. s.next().ok_or_else(|| ShipError::InvalidQuestFilename(filename.to_owned()))?)
  21. };
  22. let datatype = match suffix {
  23. "bin" => QuestFileType::Bin,
  24. "dat" => QuestFileType::Dat,
  25. _ => Err(ShipError::InvalidQuestFilename(filename.to_owned()))?
  26. };
  27. let (category, quest) = {
  28. let mut s = filename.splitn(2, '-');
  29. (s.next().and_then(|k| k.parse().ok()).ok_or_else(|| ShipError::InvalidQuestFilename(filename.to_owned()))?,
  30. s.next().and_then(|k| k.parse().ok()).ok_or_else(|| ShipError::InvalidQuestFilename(filename.to_owned()))?)
  31. };
  32. Ok((category, quest, datatype))
  33. }
  34. pub async fn send_quest_category_list(id: ClientId,
  35. rql: RequestQuestList,
  36. client_location: &ClientLocation,
  37. rooms: &Rooms)
  38. -> Result<Vec<(ClientId, SendShipPacket)>, anyhow::Error> {
  39. let room_id = client_location.get_room(id).await?;
  40. let rql = rql.clone();
  41. rooms.with_mut(room_id, |room| Box::pin(async move {
  42. //let qcl = quest::quest_category_list(&room.quests[rql.flag.clamp(0, (room.quests.len() - 1) as u32) as usize]);
  43. room.quest_group = rql.flag.into();
  44. let qcl = quest::quest_category_list(room.quests());
  45. Ok(vec![(id, SendShipPacket::QuestCategoryList(qcl))])
  46. })).await?
  47. }
  48. pub async fn select_quest_category(id: ClientId,
  49. menuselect: MenuSelect,
  50. client_location: &ClientLocation,
  51. rooms: &Rooms)
  52. -> Result<Vec<(ClientId, SendShipPacket)>, anyhow::Error> {
  53. let room_id = client_location.get_room(id).await?;
  54. rooms.with(room_id, |room| Box::pin(async move {
  55. let (_, category_quests) = room.quests()
  56. .iter()
  57. .nth(menuselect.item as usize)
  58. .ok_or_else(|| ShipError::InvalidQuestCategory(menuselect.item as u16))?;
  59. let ql = quest::quest_list(menuselect.item, category_quests);
  60. Ok(vec![(id, SendShipPacket::QuestOptionList(ql))])
  61. })).await?
  62. }
  63. pub async fn quest_detail(id: ClientId,
  64. questdetailrequest: QuestDetailRequest,
  65. client_location: &ClientLocation,
  66. rooms: &Rooms)
  67. -> Result<Vec<(ClientId, SendShipPacket)>, anyhow::Error> {
  68. let room_id = client_location.get_room(id).await?;
  69. rooms.with(room_id, |room| Box::pin(async move {
  70. let (_, category_quests) = room.quests().iter()
  71. .nth(questdetailrequest.category as usize)
  72. .ok_or_else(|| ShipError::InvalidQuestCategory(questdetailrequest.category))?;
  73. let quest = category_quests.iter()
  74. .find(|q| {
  75. q.id == questdetailrequest.quest
  76. }).ok_or_else(|| ShipError::InvalidQuest(questdetailrequest.quest))?;
  77. let qd = quest::quest_detail(quest);
  78. Ok(vec![(id, SendShipPacket::QuestDetail(qd))])
  79. })).await?
  80. }
  81. pub async fn player_chose_quest(id: ClientId,
  82. questmenuselect: QuestMenuSelect,
  83. clients: &Clients,
  84. client_location: &ClientLocation,
  85. rooms: &Rooms,
  86. event: ShipEvent)
  87. -> Result<Vec<(ClientId, SendShipPacket)>, anyhow::Error> {
  88. let room_id = client_location.get_room(id).await?;
  89. let client_location = client_location.clone();
  90. let questmenuselect = questmenuselect.clone();
  91. rooms.with_mut(room_id, |room| {
  92. let clients = clients.clone();
  93. Box::pin(async move {
  94. let quest = room.quests().iter()
  95. .nth(questmenuselect.category as usize)
  96. .ok_or_else(|| ShipError::InvalidQuestCategory(questmenuselect.category))?
  97. .1
  98. .iter()
  99. .find(|q| {
  100. q.id == questmenuselect.quest
  101. })
  102. .ok_or_else(|| ShipError::InvalidQuest(questmenuselect.quest))?
  103. .clone();
  104. let rare_monster_table = RareMonsterAppearTable::new(room.mode.episode());
  105. room.maps.set_quest_data(quest.enemies.clone(), quest.objects.clone(), &rare_monster_table, event);
  106. room.map_areas = quest.map_areas.clone();
  107. let bin = quest::quest_header(&questmenuselect, &quest.bin_blob, "bin");
  108. let dat = quest::quest_header(&questmenuselect, &quest.dat_blob, "dat");
  109. let area_clients = client_location.get_all_clients_by_client(id).await?;
  110. for client in &area_clients {
  111. clients.with_mut(client.client, |client| Box::pin(async move {
  112. client.done_loading_quest = false;
  113. })).await?;
  114. }
  115. Ok(area_clients
  116. .into_iter()
  117. .flat_map(move |c| {
  118. vec![(c.client, SendShipPacket::QuestHeader(bin.clone())), (c.client, SendShipPacket::QuestHeader(dat.clone()))]
  119. })
  120. .collect())
  121. })}).await?
  122. }
  123. pub async fn quest_file_request(id: ClientId,
  124. quest_file_request: QuestFileRequest,
  125. client_location: &ClientLocation,
  126. rooms: &mut Rooms)
  127. -> Result<Vec<(ClientId, SendShipPacket)>, anyhow::Error>
  128. {
  129. let room_id = client_location.get_room(id).await?;
  130. let quest_file_request = quest_file_request.clone();
  131. rooms.with(room_id, |room| Box::pin(async move {
  132. let (category_id, quest_id, datatype) = parse_filename(&quest_file_request.filename)?;
  133. let (_, category_quests) = room.quests().iter()
  134. .nth(category_id as usize)
  135. .ok_or_else(|| ShipError::InvalidQuestCategory(category_id))?;
  136. let quest = category_quests.iter()
  137. .find(|q| {
  138. q.id == quest_id
  139. }).ok_or_else(|| ShipError::InvalidQuest(quest_id))?;
  140. let blob = match datatype {
  141. QuestFileType::Bin => &quest.bin_blob,
  142. QuestFileType::Dat => &quest.dat_blob,
  143. };
  144. let mut blob_cursor = Cursor::new(&**blob);
  145. let mut subblob = [0u8; 0x400];
  146. let blob_length = blob_cursor.read(&mut subblob)?;
  147. let qc = quest::quest_chunk(0, quest_file_request.filename, subblob, blob_length);
  148. Ok(vec![(id, SendShipPacket::QuestChunk(qc))])
  149. })).await?
  150. }
  151. pub async fn quest_chunk_ack(id: ClientId,
  152. quest_chunk_ack: QuestChunkAck,
  153. client_location: &ClientLocation,
  154. rooms: &Rooms)
  155. -> Result<Vec<(ClientId, SendShipPacket)>, anyhow::Error> {
  156. let room_id = client_location.get_room(id).await?;
  157. let quest_chunk_ack = quest_chunk_ack.clone();
  158. rooms.with(room_id, |room| Box::pin(async move {
  159. let (category_id, quest_id, datatype) = parse_filename(&quest_chunk_ack.filename)?;
  160. let (_, category_quests) = room.quests().iter()
  161. .nth(category_id as usize)
  162. .ok_or_else(|| ShipError::InvalidQuestCategory(category_id))?;
  163. let quest = category_quests.iter()
  164. .find(|q| {
  165. q.id == quest_id
  166. }).ok_or_else(|| ShipError::InvalidQuest(quest_id))?;
  167. let blob = match datatype {
  168. QuestFileType::Bin => &quest.bin_blob,
  169. QuestFileType::Dat => &quest.dat_blob,
  170. };
  171. let mut blob_cursor = Cursor::new(&**blob);
  172. blob_cursor.seek(SeekFrom::Start((quest_chunk_ack.chunk_num as u64 + 1) * 0x400))?;
  173. let mut subblob = [0u8; 0x400];
  174. let blob_length = blob_cursor.read(&mut subblob)?;
  175. if blob_length == 0 {
  176. return Ok(Vec::new());
  177. }
  178. let qc = quest::quest_chunk(quest_chunk_ack.chunk_num + 1, quest_chunk_ack.filename, subblob, blob_length);
  179. Ok(vec![(id, SendShipPacket::QuestChunk(qc))])
  180. })).await?
  181. }
  182. pub async fn done_loading_quest(id: ClientId,
  183. clients: &Clients,
  184. client_location: &ClientLocation)
  185. -> Result<Vec<(ClientId, SendShipPacket)>, anyhow::Error> {
  186. clients.with_mut(id, |client| Box::pin(async move {
  187. client.done_loading_quest = true;
  188. })).await?;
  189. let area_clients = client_location.get_all_clients_by_client(id).await?;
  190. let all_loaded = area_clients.iter()
  191. .map(|client|
  192. clients.with(client.client, |client| Box::pin(async move {
  193. client.done_loading_quest
  194. }))
  195. )
  196. .collect::<FuturesOrdered<_>>()
  197. .all(|c| async move {
  198. c.unwrap_or(false)
  199. }).await;
  200. if all_loaded {
  201. Ok(area_clients
  202. .iter()
  203. .map(|c| {
  204. (c.client, SendShipPacket::DoneLoadingQuest(DoneLoadingQuest {}))
  205. })
  206. .collect())
  207. }
  208. else {
  209. Ok(Vec::new())
  210. }
  211. }