201 lines
9.4 KiB
Rust
Raw Normal View History

2020-05-24 15:59:48 -06:00
use std::io::{Cursor, Read, Seek, SeekFrom};
use libpso::packet::ship::*;
use crate::common::serverstate::ClientId;
use crate::ship::ship::{SendShipPacket, ShipError, Clients, Rooms};
use crate::ship::location::{ClientLocation, ClientLocationError};
use crate::ship::packet::builder::quest;
use libpso::util::array_to_utf8;
// TOOD: enum
2020-05-24 23:03:53 -06:00
enum QuestFileType {
Bin,
Dat
}
2020-05-24 15:59:48 -06:00
2020-05-24 23:03:53 -06:00
fn parse_filename(filename_bytes: &[u8; 16]) -> Result<(u16, u16, QuestFileType), ShipError> {
2020-05-24 15:59:48 -06:00
let filename = array_to_utf8(*filename_bytes).map_err(|_| ShipError::InvalidQuestFilename("NOT UTF8".to_string()))?;
let (filename, suffix) = {
let mut s = filename.splitn(2, '.');
2021-06-18 12:18:29 -06:00
(s.next().ok_or_else(|| ShipError::InvalidQuestFilename(filename.to_owned()))?,
s.next().ok_or_else(|| ShipError::InvalidQuestFilename(filename.to_owned()))?)
2020-05-24 15:59:48 -06:00
};
let datatype = match suffix {
2020-05-24 23:03:53 -06:00
"bin" => QuestFileType::Bin,
"dat" => QuestFileType::Dat,
2020-05-24 15:59:48 -06:00
_ => return Err(ShipError::InvalidQuestFilename(filename.to_owned()))
};
let (category, quest) = {
let mut s = filename.splitn(2, '-');
2021-06-18 12:18:29 -06:00
(s.next().and_then(|k| k.parse().ok()).ok_or_else(|| ShipError::InvalidQuestFilename(filename.to_owned()))?,
s.next().and_then(|k| k.parse().ok()).ok_or_else(|| ShipError::InvalidQuestFilename(filename.to_owned()))?)
2020-05-24 15:59:48 -06:00
};
Ok((category, quest, datatype))
}
2022-09-18 21:01:32 -06:00
pub async fn send_quest_category_list(id: ClientId, rql: &RequestQuestList, client_location: &ClientLocation, rooms: &mut Rooms) -> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, ShipError> {
let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?;
let room = rooms.get_mut(room_id.0)
.ok_or(ShipError::InvalidRoom(room_id.0 as u32))?.as_mut()
.ok_or(ShipError::InvalidRoom(room_id.0 as u32))?;
2022-02-07 03:01:29 +00:00
let qcl = quest::quest_category_list(&room.quests[rql.flag.clamp(0, (room.quests.len() - 1) as u32) as usize]);
room.set_quest_group(rql.flag as usize);
2020-05-24 15:59:48 -06:00
Ok(Box::new(vec![(id, SendShipPacket::QuestCategoryList(qcl))].into_iter()))
}
2022-09-18 21:01:32 -06:00
pub async fn select_quest_category(id: ClientId, menuselect: &MenuSelect, client_location: &ClientLocation, rooms: &mut Rooms) -> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, ShipError> {
let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?;
let room = rooms.get_mut(room_id.0)
.ok_or(ShipError::InvalidRoom(room_id.0 as u32))?.as_mut()
.ok_or(ShipError::InvalidRoom(room_id.0 as u32))?;
2022-02-07 03:01:29 +00:00
let (_, category_quests) = room.quests[room.quest_group.value()].iter()
2020-05-24 15:59:48 -06:00
.nth(menuselect.item as usize)
.ok_or(ShipError::InvalidQuestCategory(menuselect.item))?;
let ql = quest::quest_list(menuselect.item, category_quests);
for q in ql.quests.clone() {
println!("name: {:?} quest_id: {}", q.name, q.quest_id);
}
2020-05-24 15:59:48 -06:00
Ok(Box::new(vec![(id, SendShipPacket::QuestOptionList(ql))].into_iter()))
}
2022-09-18 21:01:32 -06:00
pub async fn quest_detail(id: ClientId, questdetailrequest: &QuestDetailRequest, client_location: &ClientLocation, rooms: &mut Rooms) -> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, ShipError> {
let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?;
let room = rooms.get_mut(room_id.0)
.ok_or(ShipError::InvalidRoom(room_id.0 as u32))?.as_mut()
.ok_or(ShipError::InvalidRoom(room_id.0 as u32))?;
2022-02-07 03:01:29 +00:00
let (_, category_quests) = room.quests[room.quest_group.value()].iter()
2020-05-24 15:59:48 -06:00
.nth(questdetailrequest.category as usize)
.ok_or(ShipError::InvalidQuestCategory(questdetailrequest.category as u32))?;
let quest = category_quests.iter()
.find(|q| {
q.id == questdetailrequest.quest as u16
}).ok_or(ShipError::InvalidQuest(questdetailrequest.quest as u32))?;
2021-06-18 12:18:29 -06:00
let qd = quest::quest_detail(quest);
2020-05-24 15:59:48 -06:00
Ok(Box::new(vec![(id, SendShipPacket::QuestDetail(qd))].into_iter()))
}
2022-09-18 21:01:32 -06:00
pub async fn player_chose_quest(id: ClientId, questmenuselect: &QuestMenuSelect, clients: &mut Clients, client_location: &ClientLocation, rooms: &mut Rooms)
2020-05-24 15:59:48 -06:00
-> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, ShipError> {
2022-09-18 21:01:32 -06:00
let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?;
let room = rooms.get_mut(room_id.0)
.ok_or(ShipError::InvalidRoom(room_id.0 as u32))?.as_mut()
.ok_or(ShipError::InvalidRoom(room_id.0 as u32))?;
2022-02-07 03:01:29 +00:00
let (_, category_quests) = room.quests[room.quest_group.value()].iter()
2020-05-24 15:59:48 -06:00
.nth(questmenuselect.category as usize)
.ok_or(ShipError::InvalidQuestCategory(questmenuselect.category as u32))?;
let quest = category_quests.iter()
.find(|q| {
q.id == questmenuselect.quest as u16
}).ok_or(ShipError::InvalidQuest(questmenuselect.quest as u32))?;
room.maps.set_quest_data(quest.enemies.clone(), quest.objects.clone(), &room.rare_monster_table);
room.map_areas = quest.map_areas.clone();
2020-05-24 15:59:48 -06:00
2020-05-24 23:03:53 -06:00
let bin = quest::quest_header(questmenuselect, &quest.bin_blob, "bin");
let dat = quest::quest_header(questmenuselect, &quest.dat_blob, "dat");
2020-05-24 15:59:48 -06:00
2022-09-18 21:01:32 -06:00
let area_clients = client_location.get_all_clients_by_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?;
2020-05-24 15:59:48 -06:00
area_clients.iter().for_each(|c| {
2021-06-18 12:18:29 -06:00
if let Some(client) = clients.get_mut(&c.client) {
2020-05-24 15:59:48 -06:00
client.done_loading_quest = false;
2021-06-18 12:18:29 -06:00
}
2020-05-24 15:59:48 -06:00
});
Ok(Box::new(area_clients.into_iter().flat_map(move |c| {
2020-05-24 15:59:48 -06:00
vec![(c.client, SendShipPacket::QuestHeader(bin.clone())), (c.client, SendShipPacket::QuestHeader(dat.clone()))]
})))
2020-05-24 15:59:48 -06:00
}
2022-09-18 21:01:32 -06:00
pub async fn quest_file_request(id: ClientId, quest_file_request: &QuestFileRequest, client_location: &ClientLocation, rooms: &mut Rooms) -> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, ShipError> {
let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?;
let room = rooms.get_mut(room_id.0)
.ok_or(ShipError::InvalidRoom(room_id.0 as u32))?.as_mut()
.ok_or(ShipError::InvalidRoom(room_id.0 as u32))?;
2020-05-24 15:59:48 -06:00
let (category_id, quest_id, datatype) = parse_filename(&quest_file_request.filename)?;
2022-02-07 03:01:29 +00:00
let (_, category_quests) = room.quests[room.quest_group.value()].iter()
2020-05-24 15:59:48 -06:00
.nth(category_id as usize)
.ok_or(ShipError::InvalidQuestCategory(category_id as u32))?;
let quest = category_quests.iter()
.find(|q| {
q.id == quest_id as u16
}).ok_or(ShipError::InvalidQuest(quest_id as u32))?;
let blob = match datatype {
2020-05-24 23:03:53 -06:00
QuestFileType::Bin => &quest.bin_blob,
QuestFileType::Dat => &quest.dat_blob,
2020-05-24 15:59:48 -06:00
};
let mut blob_cursor = Cursor::new(blob);
let mut subblob = [0u8; 0x400];
let blob_length = blob_cursor.read(&mut subblob)?;
2020-05-24 23:03:53 -06:00
let qc = quest::quest_chunk(0, quest_file_request.filename, subblob, blob_length);
2020-05-24 15:59:48 -06:00
Ok(Box::new(vec![(id, SendShipPacket::QuestChunk(qc))].into_iter()))
}
2022-09-18 21:01:32 -06:00
pub async fn quest_chunk_ack(id: ClientId, quest_chunk_ack: &QuestChunkAck, client_location: &ClientLocation, rooms: &mut Rooms) -> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, ShipError> {
let room_id = client_location.get_room(id).await.map_err(|err| -> ClientLocationError { err.into() })?;
let room = rooms.get_mut(room_id.0)
.ok_or(ShipError::InvalidRoom(room_id.0 as u32))?.as_mut()
.ok_or(ShipError::InvalidRoom(room_id.0 as u32))?;
2020-05-24 15:59:48 -06:00
let (category_id, quest_id, datatype) = parse_filename(&quest_chunk_ack.filename)?;
2022-02-07 03:01:29 +00:00
let (_, category_quests) = room.quests[room.quest_group.value()].iter()
2020-05-24 15:59:48 -06:00
.nth(category_id as usize)
.ok_or(ShipError::InvalidQuestCategory(category_id as u32))?;
let quest = category_quests.iter()
.find(|q| {
q.id == quest_id
}).ok_or(ShipError::InvalidQuest(quest_id as u32))?;
let blob = match datatype {
2020-05-24 23:03:53 -06:00
QuestFileType::Bin => &quest.bin_blob,
QuestFileType::Dat => &quest.dat_blob,
2020-05-24 15:59:48 -06:00
};
let mut blob_cursor = Cursor::new(blob);
2020-05-25 10:03:25 -06:00
blob_cursor.seek(SeekFrom::Start((quest_chunk_ack.chunk_num as u64 + 1) * 0x400))?;
2020-05-24 15:59:48 -06:00
let mut subblob = [0u8; 0x400];
let blob_length = blob_cursor.read(&mut subblob)?;
if blob_length == 0 {
return Ok(Box::new(None.into_iter()));
}
2020-05-24 23:03:53 -06:00
let qc = quest::quest_chunk(quest_chunk_ack.chunk_num + 1, quest_chunk_ack.filename, subblob, blob_length);
2020-05-24 15:59:48 -06:00
Ok(Box::new(vec![(id, SendShipPacket::QuestChunk(qc))].into_iter()))
}
2022-09-18 21:01:32 -06:00
pub async fn done_loading_quest(id: ClientId, clients: &mut Clients, client_location: &ClientLocation)
-> Result<Box<dyn Iterator<Item = (ClientId, SendShipPacket)> + Send>, ShipError> {
2020-05-24 15:59:48 -06:00
let client = clients.get_mut(&id).ok_or(ShipError::ClientNotFound(id))?;
client.done_loading_quest = true;
2022-09-18 21:01:32 -06:00
let area_clients = client_location.get_all_clients_by_client(id).await.map_err(|err| -> ClientLocationError { err.into() })?;
2020-05-24 15:59:48 -06:00
let all_loaded = area_clients.iter().all(|c| {
clients.get(&c.client)
.map(|client| {
client.done_loading_quest
})
.unwrap_or(false)
});
if all_loaded {
Ok(Box::new(area_clients.into_iter().map(|c| {
(c.client, SendShipPacket::DoneLoadingQuest(DoneLoadingQuest {}))
})))
}
else {
Ok(Box::new(None.into_iter()))
}
}