Implement savefile writing
This commit is contained in:
parent
8003278dcd
commit
65656f2e09
@ -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<CompanionWithId>);
|
||||
|
||||
impl Companions {
|
||||
@ -49,11 +49,32 @@ impl BinRead for Companions {
|
||||
}
|
||||
}
|
||||
|
||||
impl BinWrite for Companions {
|
||||
type Args<'a> = ();
|
||||
|
||||
#[derive(Debug)]
|
||||
fn write_options<W: std::io::Write + std::io::Seek>(
|
||||
&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<CompanionWithSymbol>);
|
||||
|
||||
impl CompanionSymbols {
|
||||
const ENTRY_SIZE: i64 = 60;
|
||||
const SECTION_SIZE: i64 = 960;
|
||||
|
||||
pub fn iter(&self) -> std::slice::Iter<CompanionWithSymbol> {
|
||||
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<W: std::io::Write + std::io::Seek>(
|
||||
&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<u8>,
|
||||
|
||||
#[brw(assert((0..=21).contains(&symbol)))]
|
||||
#[br(assert((0..=21).contains(&symbol)))]
|
||||
pub symbol: u32,
|
||||
}
|
||||
|
@ -1,8 +1,8 @@
|
||||
use binrw::BinRead;
|
||||
use binrw::{BinRead, BinWrite};
|
||||
|
||||
|
||||
#[derive(Debug, BinRead)]
|
||||
pub struct Glyphs(#[brw(count = 6)] Vec<LevelGlyphs>);
|
||||
#[derive(Debug, Clone, BinRead, BinWrite)]
|
||||
pub struct Glyphs(#[br(count = 6)] Vec<LevelGlyphs>);
|
||||
|
||||
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<u8>,
|
||||
}
|
||||
|
||||
|
@ -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<u8>,
|
||||
|
||||
pub robe: u32,
|
||||
@ -60,57 +60,70 @@ pub struct Savefile {
|
||||
|
||||
pub scarf_length: u32,
|
||||
|
||||
#[brw(count = 4)]
|
||||
#[br(count = 4)]
|
||||
_unknown1: Vec<u8>,
|
||||
|
||||
#[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<u8>,
|
||||
|
||||
#[brw(parse_with = parse_last_played)]
|
||||
#[br(parse_with = parse_last_played)]
|
||||
#[bw(write_with = write_last_played)]
|
||||
pub last_played: DateTime<Utc>,
|
||||
|
||||
#[brw(count = 4)]
|
||||
#[br(count = 4)]
|
||||
_unknown3: Vec<u8>,
|
||||
|
||||
pub journey_count: u64,
|
||||
|
||||
pub glyphs: Glyphs,
|
||||
|
||||
#[brw(count = 2404)]
|
||||
#[br(count = 2404)]
|
||||
_unknown4: Vec<u8>,
|
||||
|
||||
pub companion_symbols: CompanionSymbols,
|
||||
|
||||
pub companions_met: u32,
|
||||
|
||||
#[brw(count = 1024)]
|
||||
#[br(count = 1024)]
|
||||
_unknown6: Vec<u8>,
|
||||
|
||||
pub total_companions_met: u32,
|
||||
|
||||
#[brw(count = 24)]
|
||||
#[br(count = 24)]
|
||||
_unknown7: Vec<u8>,
|
||||
|
||||
pub companions: Companions,
|
||||
|
||||
#[br(parse_with = until_eof)]
|
||||
_unknown8: Vec<u8>,
|
||||
}
|
||||
|
||||
impl Savefile {
|
||||
pub fn from_reader<R>(mut reader: R) -> std::io::Result<Self>
|
||||
pub fn from_reader<R>(mut reader: R) -> binrw::BinResult<Self>
|
||||
where
|
||||
R: Read + BinReaderExt,
|
||||
{
|
||||
// TODO: implement error type
|
||||
Ok(reader.read_le().unwrap())
|
||||
Ok(reader.read_le()?)
|
||||
}
|
||||
|
||||
pub fn write<W>(&self, mut writer: W) -> binrw::BinResult<()>
|
||||
where
|
||||
W: Write + BinWriterExt,
|
||||
{
|
||||
writer.write_le(self)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn current_companions<'a>(&'a self) -> impl Iterator<Item = &'a CompanionWithId> {
|
||||
@ -169,3 +182,13 @@ fn parse_last_played() -> binrw::BinResult<DateTime<Utc>> {
|
||||
|
||||
Ok(datetime)
|
||||
}
|
||||
|
||||
#[binrw::writer(writer, endian)]
|
||||
fn write_last_played(datetime: &DateTime<Utc>) -> binrw::BinResult<()> {
|
||||
let timestamp = datetime.timestamp_millis();
|
||||
let timestamp = (timestamp + 11_644_473_600_000) * 10_000;
|
||||
|
||||
writer.write_type(×tamp, endian)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -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,
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user