diff --git a/crates/save/src/companion.rs b/crates/save/src/companion.rs index 87d3c7b..cde4475 100644 --- a/crates/save/src/companion.rs +++ b/crates/save/src/companion.rs @@ -1,9 +1,9 @@ use std::io::SeekFrom; -use binrw::{BinRead, NullString}; +use binrw::{BinRead, BinWrite, BinWriterExt, NullString}; -#[derive(Debug)] +#[derive(Debug, Clone)] pub struct Companions(Vec); impl Companions { @@ -49,11 +49,32 @@ impl BinRead for Companions { } } +impl BinWrite for Companions { + type Args<'a> = (); -#[derive(Debug)] + fn write_options( + &self, + writer: &mut W, + endian: binrw::Endian, + _args: Self::Args<'_>, + ) -> binrw::BinResult<()> { + for companion in &self.0 { + writer.write_type(companion, endian)?; + writer.write_all(&[0x01, 0x00, 0x10, 0x01])?; + } + + Ok(()) + } +} + + +#[derive(Debug, Clone)] pub struct CompanionSymbols(Vec); impl CompanionSymbols { + const ENTRY_SIZE: i64 = 60; + const SECTION_SIZE: i64 = 960; + pub fn iter(&self) -> std::slice::Iter { self.0.iter() } @@ -80,27 +101,48 @@ impl BinRead for CompanionSymbols { let companion: CompanionWithSymbol = <_>::read_options(reader, endian, ())?; if companion.name.is_empty() { - reader.seek(SeekFrom::Current(-60))?; + reader.seek(SeekFrom::Current(-Self::ENTRY_SIZE))?; break; } companions.push(companion); } - let padding = 960 - (companions.len() * 60); - reader.seek(SeekFrom::Current(padding as i64))?; + let padding = Self::SECTION_SIZE - (companions.len() as i64 * Self::ENTRY_SIZE); + reader.seek(SeekFrom::Current(padding))?; Ok(Self(companions)) } } +impl BinWrite for CompanionSymbols { + type Args<'a> = (); -#[derive(Debug, BinRead)] + fn write_options( + &self, + writer: &mut W, + endian: binrw::Endian, + _args: Self::Args<'_>, + ) -> binrw::BinResult<()> { + for companion in &self.0 { + writer.write_type(companion, endian)?; + } + + let padding = Self::SECTION_SIZE - (self.0.len() as i64 * Self::ENTRY_SIZE); + writer.write_all(&vec![0u8; padding as usize])?; + + Ok(()) + } +} + + +#[derive(Debug, Clone, BinRead, BinWrite)] pub struct CompanionWithId { - #[brw(pad_size_to = 24, map = |raw: NullString| raw.to_string())] + #[br(pad_size_to = 24, map = |raw: NullString| raw.to_string())] + #[bw(pad_size_to = 24, map = |s| NullString::from(s.as_ref()))] pub name: String, - #[brw(assert(steam_id != 0))] + #[br(assert(steam_id != 0))] pub steam_id: u32, } @@ -117,14 +159,15 @@ impl CompanionWithId { } -#[derive(Debug, BinRead)] +#[derive(Debug, Clone, BinRead, BinWrite)] pub struct CompanionWithSymbol { - #[brw(pad_size_to = 52, map = |raw: NullString| raw.to_string())] + #[br(pad_size_to = 52, map = |raw: NullString| raw.to_string())] + #[bw(pad_size_to = 52, map = |s| NullString::from(s.as_ref()))] pub name: String, - #[brw(count = 4)] + #[br(count = 4)] _unknown1: Vec, - #[brw(assert((0..=21).contains(&symbol)))] + #[br(assert((0..=21).contains(&symbol)))] pub symbol: u32, } diff --git a/crates/save/src/glyphs.rs b/crates/save/src/glyphs.rs index 8e3e7fa..fc9e3e2 100644 --- a/crates/save/src/glyphs.rs +++ b/crates/save/src/glyphs.rs @@ -1,8 +1,8 @@ -use binrw::BinRead; +use binrw::{BinRead, BinWrite}; -#[derive(Debug, BinRead)] -pub struct Glyphs(#[brw(count = 6)] Vec); +#[derive(Debug, Clone, BinRead, BinWrite)] +pub struct Glyphs(#[br(count = 6)] Vec); impl Glyphs { const COUNT: [usize; 6] = [3, 3, 4, 3, 4, 4]; @@ -32,11 +32,11 @@ impl Glyphs { } -#[derive(Debug, BinRead)] +#[derive(Debug, Clone, BinRead, BinWrite)] pub struct LevelGlyphs { status_flags: u8, - #[brw(count = 343)] + #[br(count = 343)] _unused: Vec, } diff --git a/crates/save/src/lib.rs b/crates/save/src/lib.rs index 8b990eb..0b5b19e 100644 --- a/crates/save/src/lib.rs +++ b/crates/save/src/lib.rs @@ -5,9 +5,9 @@ mod test; use core::fmt; -use std::io::Read; +use std::io::{Read, Write}; -use binrw::{BinRead, BinReaderExt}; +use binrw::{until_eof, BinRead, BinReaderExt, BinWriterExt}; use chrono::{DateTime, NaiveDateTime, Utc}; use crate::companion::{CompanionSymbols, CompanionWithId, Companions}; @@ -31,7 +31,7 @@ pub const LEVEL_NAMES: [&str; 12] = [ ]; -#[derive(Debug, PartialEq, Eq)] +#[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum RobeColor { Red, White, @@ -47,11 +47,11 @@ impl fmt::Display for RobeColor { } -#[binrw::binread] -#[derive(Debug)] +#[binrw::binrw] +#[derive(Debug, Clone)] #[brw(little)] pub struct Savefile { - #[brw(count = 8)] + #[br(count = 8)] _unknown0: Vec, pub robe: u32, @@ -60,57 +60,70 @@ pub struct Savefile { pub scarf_length: u32, - #[brw(count = 4)] + #[br(count = 4)] _unknown1: Vec, - #[brw(assert(current_level <= 12))] + #[br(assert(current_level <= 12))] pub current_level: u64, pub total_collected_symbols: u32, - #[brw(assert(collected_symbols <= 21))] + #[br(assert(collected_symbols <= 21))] pub collected_symbols: u32, pub murals: Murals, - #[brw(count = 22)] + #[br(count = 22)] _unknown2: Vec, - #[brw(parse_with = parse_last_played)] + #[br(parse_with = parse_last_played)] + #[bw(write_with = write_last_played)] pub last_played: DateTime, - #[brw(count = 4)] + #[br(count = 4)] _unknown3: Vec, pub journey_count: u64, pub glyphs: Glyphs, - #[brw(count = 2404)] + #[br(count = 2404)] _unknown4: Vec, pub companion_symbols: CompanionSymbols, pub companions_met: u32, - #[brw(count = 1024)] + #[br(count = 1024)] _unknown6: Vec, pub total_companions_met: u32, - #[brw(count = 24)] + #[br(count = 24)] _unknown7: Vec, pub companions: Companions, + + #[br(parse_with = until_eof)] + _unknown8: Vec, } impl Savefile { - pub fn from_reader(mut reader: R) -> std::io::Result + pub fn from_reader(mut reader: R) -> binrw::BinResult where R: Read + BinReaderExt, { // TODO: implement error type - Ok(reader.read_le().unwrap()) + Ok(reader.read_le()?) + } + + pub fn write(&self, mut writer: W) -> binrw::BinResult<()> + where + W: Write + BinWriterExt, + { + writer.write_le(self)?; + + Ok(()) } pub fn current_companions<'a>(&'a self) -> impl Iterator { @@ -169,3 +182,13 @@ fn parse_last_played() -> binrw::BinResult> { Ok(datetime) } + +#[binrw::writer(writer, endian)] +fn write_last_played(datetime: &DateTime) -> binrw::BinResult<()> { + let timestamp = datetime.timestamp_millis(); + let timestamp = (timestamp + 11_644_473_600_000) * 10_000; + + writer.write_type(×tamp, endian)?; + + Ok(()) +} diff --git a/crates/save/src/murals.rs b/crates/save/src/murals.rs index a41cc8b..662708d 100644 --- a/crates/save/src/murals.rs +++ b/crates/save/src/murals.rs @@ -1,7 +1,7 @@ -use binrw::BinRead; +use binrw::{BinRead, BinWrite}; -#[derive(Debug, BinRead)] +#[derive(Debug, Clone, Copy, BinRead, BinWrite)] pub struct Murals { status_flags: u16, }