|
@ -3,12 +3,11 @@ use std::collections::{HashMap, BTreeMap, BTreeSet}; |
|
|
use std::fs::File;
|
|
|
use std::fs::File;
|
|
|
use std::io::{Read, Write, Cursor, Seek, SeekFrom};
|
|
|
use std::io::{Read, Write, Cursor, Seek, SeekFrom};
|
|
|
use std::path::PathBuf;
|
|
|
use std::path::PathBuf;
|
|
|
use std::convert::{TryInto, TryFrom};
|
|
|
|
|
|
|
|
|
use std::convert::TryInto;
|
|
|
use thiserror::Error;
|
|
|
use thiserror::Error;
|
|
|
use serde::{Serialize, Deserialize};
|
|
|
use serde::{Serialize, Deserialize};
|
|
|
use ages_prs::{LegacyPrsDecoder, LegacyPrsEncoder};
|
|
|
use ages_prs::{LegacyPrsDecoder, LegacyPrsEncoder};
|
|
|
use byteorder::{LittleEndian, ReadBytesExt};
|
|
|
use byteorder::{LittleEndian, ReadBytesExt};
|
|
|
use libpso::packet::ship::QuestChunk;
|
|
|
|
|
|
use libpso::util::array_to_utf16;
|
|
|
use libpso::util::array_to_utf16;
|
|
|
use crate::ship::map::{MapArea, MapAreaError, MapObject, MapEnemy, enemy_data_from_stream, objects_from_stream};
|
|
|
use crate::ship::map::{MapArea, MapAreaError, MapObject, MapEnemy, enemy_data_from_stream, objects_from_stream};
|
|
|
use crate::ship::room::Episode;
|
|
|
use crate::ship::room::Episode;
|
|
@ -42,7 +41,7 @@ struct QuestListConfig { |
|
|
|
|
|
|
|
|
#[derive(Error, Debug)]
|
|
|
#[derive(Error, Debug)]
|
|
|
#[error("")]
|
|
|
#[error("")]
|
|
|
enum ParseDatError {
|
|
|
|
|
|
|
|
|
pub enum ParseDatError {
|
|
|
IoError(#[from] std::io::Error),
|
|
|
IoError(#[from] std::io::Error),
|
|
|
MapError(#[from] MapAreaError),
|
|
|
MapError(#[from] MapAreaError),
|
|
|
UnknownDatHeader(u32),
|
|
|
UnknownDatHeader(u32),
|
|
@ -62,7 +61,7 @@ enum DatBlock { |
|
|
|
|
|
|
|
|
fn read_dat_section_header<T: Read + Seek>(cursor: &mut T, episode: &Episode) -> Result<DatBlock, ParseDatError> {
|
|
|
fn read_dat_section_header<T: Read + Seek>(cursor: &mut T, episode: &Episode) -> Result<DatBlock, ParseDatError> {
|
|
|
let header = cursor.read_u32::<LittleEndian>()?;
|
|
|
let header = cursor.read_u32::<LittleEndian>()?;
|
|
|
let offset = cursor.read_u32::<LittleEndian>()?;
|
|
|
|
|
|
|
|
|
let _offset = cursor.read_u32::<LittleEndian>()?;
|
|
|
let area = cursor.read_u32::<LittleEndian>()?;
|
|
|
let area = cursor.read_u32::<LittleEndian>()?;
|
|
|
let length = cursor.read_u32::<LittleEndian>()?;
|
|
|
let length = cursor.read_u32::<LittleEndian>()?;
|
|
|
|
|
|
|
|
@ -71,7 +70,7 @@ fn read_dat_section_header<T: Read + Seek>(cursor: &mut T, episode: &Episode) -> |
|
|
match header {
|
|
|
match header {
|
|
|
DAT_OBJECT_HEADER_ID => {
|
|
|
DAT_OBJECT_HEADER_ID => {
|
|
|
let mut obj_data = vec![0u8; length as usize];
|
|
|
let mut obj_data = vec![0u8; length as usize];
|
|
|
cursor.read(&mut obj_data);
|
|
|
|
|
|
|
|
|
cursor.read(&mut obj_data)?;
|
|
|
let mut obj_cursor = Cursor::new(obj_data);
|
|
|
let mut obj_cursor = Cursor::new(obj_data);
|
|
|
|
|
|
|
|
|
let objects = objects_from_stream(&mut obj_cursor, episode, &map_area);
|
|
|
let objects = objects_from_stream(&mut obj_cursor, episode, &map_area);
|
|
@ -79,7 +78,7 @@ fn read_dat_section_header<T: Read + Seek>(cursor: &mut T, episode: &Episode) -> |
|
|
},
|
|
|
},
|
|
|
DAT_ENEMY_HEADER_ID => {
|
|
|
DAT_ENEMY_HEADER_ID => {
|
|
|
let mut enemy_data = vec![0u8; length as usize];
|
|
|
let mut enemy_data = vec![0u8; length as usize];
|
|
|
cursor.read(&mut enemy_data);
|
|
|
|
|
|
|
|
|
cursor.read(&mut enemy_data)?;
|
|
|
let mut enemy_cursor = Cursor::new(enemy_data);
|
|
|
let mut enemy_cursor = Cursor::new(enemy_data);
|
|
|
|
|
|
|
|
|
let enemies = enemy_data_from_stream(&mut enemy_cursor, &map_area, episode);
|
|
|
let enemies = enemy_data_from_stream(&mut enemy_cursor, &map_area, episode);
|
|
@ -87,7 +86,7 @@ fn read_dat_section_header<T: Read + Seek>(cursor: &mut T, episode: &Episode) -> |
|
|
Ok(DatBlock::Enemy(enemies))
|
|
|
Ok(DatBlock::Enemy(enemies))
|
|
|
},
|
|
|
},
|
|
|
DAT_WAVE_HEADER_ID => {
|
|
|
DAT_WAVE_HEADER_ID => {
|
|
|
cursor.seek(SeekFrom::Current(length as i64));
|
|
|
|
|
|
|
|
|
cursor.seek(SeekFrom::Current(length as i64))?;
|
|
|
Ok(DatBlock::Wave)
|
|
|
Ok(DatBlock::Wave)
|
|
|
},
|
|
|
},
|
|
|
_ => Err(ParseDatError::UnknownDatHeader(header))
|
|
|
_ => Err(ParseDatError::UnknownDatHeader(header))
|
|
@ -134,11 +133,10 @@ fn parse_dat(dat: &[u8], episode: &Episode) -> Result<(Vec<Option<MapEnemy>>, Ve |
|
|
#[derive(Error, Debug)]
|
|
|
#[derive(Error, Debug)]
|
|
|
#[error("")]
|
|
|
#[error("")]
|
|
|
pub enum QuestLoadError {
|
|
|
pub enum QuestLoadError {
|
|
|
|
|
|
IoError(#[from] std::io::Error),
|
|
|
ParseDatError(#[from] ParseDatError),
|
|
|
ParseDatError(#[from] ParseDatError),
|
|
|
CouldNotReadMetadata,
|
|
|
CouldNotReadMetadata,
|
|
|
CouldNotLoadConfigFile,
|
|
|
CouldNotLoadConfigFile,
|
|
|
QuestFileNotFound(String),
|
|
|
|
|
|
CouldNotLoadFile(String),
|
|
|
|
|
|
}
|
|
|
}
|
|
|
|
|
|
|
|
|
#[derive(Debug)]
|
|
|
#[derive(Debug)]
|
|
@ -166,9 +164,9 @@ impl Quest { |
|
|
let (enemies, objects) = parse_dat(&dat, &episode)?;
|
|
|
let (enemies, objects) = parse_dat(&dat, &episode)?;
|
|
|
|
|
|
|
|
|
let mut prs_bin = LegacyPrsEncoder::new(Vec::new());
|
|
|
let mut prs_bin = LegacyPrsEncoder::new(Vec::new());
|
|
|
prs_bin.write(&bin);
|
|
|
|
|
|
|
|
|
prs_bin.write(&bin)?;
|
|
|
let mut prs_dat = LegacyPrsEncoder::new(Vec::new());
|
|
|
let mut prs_dat = LegacyPrsEncoder::new(Vec::new());
|
|
|
prs_dat.write(&dat);
|
|
|
|
|
|
|
|
|
prs_dat.write(&dat)?;
|
|
|
|
|
|
|
|
|
Ok(Quest {
|
|
|
Ok(Quest {
|
|
|
name: name,
|
|
|
name: name,
|
|
@ -190,7 +188,7 @@ pub type QuestList = BTreeMap<QuestCategory, Vec<Quest>>; |
|
|
pub fn load_quests(quest_path: PathBuf) -> Result<QuestList, QuestLoadError> {
|
|
|
pub fn load_quests(quest_path: PathBuf) -> Result<QuestList, QuestLoadError> {
|
|
|
let mut f = File::open(quest_path).map_err(|_| QuestLoadError::CouldNotLoadConfigFile)?;
|
|
|
let mut f = File::open(quest_path).map_err(|_| QuestLoadError::CouldNotLoadConfigFile)?;
|
|
|
let mut s = String::new();
|
|
|
let mut s = String::new();
|
|
|
f.read_to_string(&mut s);
|
|
|
|
|
|
|
|
|
f.read_to_string(&mut s)?;
|
|
|
|
|
|
|
|
|
let mut used_quest_ids = BTreeSet::new();
|
|
|
let mut used_quest_ids = BTreeSet::new();
|
|
|
let ql: BTreeMap<String, QuestListCategory> = toml::from_str(s.as_str()).map_err(|_| QuestLoadError::CouldNotLoadConfigFile)?;
|
|
|
let ql: BTreeMap<String, QuestListCategory> = toml::from_str(s.as_str()).map_err(|_| QuestLoadError::CouldNotLoadConfigFile)?;
|
|
|