Implement savefile writing
This commit is contained in:
parent
8003278dcd
commit
65656f2e09
@ -1,9 +1,9 @@
|
|||||||
use std::io::SeekFrom;
|
use std::io::SeekFrom;
|
||||||
|
|
||||||
use binrw::{BinRead, NullString};
|
use binrw::{BinRead, BinWrite, BinWriterExt, NullString};
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct Companions(Vec<CompanionWithId>);
|
pub struct Companions(Vec<CompanionWithId>);
|
||||||
|
|
||||||
impl Companions {
|
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>);
|
pub struct CompanionSymbols(Vec<CompanionWithSymbol>);
|
||||||
|
|
||||||
impl CompanionSymbols {
|
impl CompanionSymbols {
|
||||||
|
const ENTRY_SIZE: i64 = 60;
|
||||||
|
const SECTION_SIZE: i64 = 960;
|
||||||
|
|
||||||
pub fn iter(&self) -> std::slice::Iter<CompanionWithSymbol> {
|
pub fn iter(&self) -> std::slice::Iter<CompanionWithSymbol> {
|
||||||
self.0.iter()
|
self.0.iter()
|
||||||
}
|
}
|
||||||
@ -80,27 +101,48 @@ impl BinRead for CompanionSymbols {
|
|||||||
let companion: CompanionWithSymbol = <_>::read_options(reader, endian, ())?;
|
let companion: CompanionWithSymbol = <_>::read_options(reader, endian, ())?;
|
||||||
|
|
||||||
if companion.name.is_empty() {
|
if companion.name.is_empty() {
|
||||||
reader.seek(SeekFrom::Current(-60))?;
|
reader.seek(SeekFrom::Current(-Self::ENTRY_SIZE))?;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
companions.push(companion);
|
companions.push(companion);
|
||||||
}
|
}
|
||||||
|
|
||||||
let padding = 960 - (companions.len() * 60);
|
let padding = Self::SECTION_SIZE - (companions.len() as i64 * Self::ENTRY_SIZE);
|
||||||
reader.seek(SeekFrom::Current(padding as i64))?;
|
reader.seek(SeekFrom::Current(padding))?;
|
||||||
|
|
||||||
Ok(Self(companions))
|
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 {
|
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,
|
pub name: String,
|
||||||
|
|
||||||
#[brw(assert(steam_id != 0))]
|
#[br(assert(steam_id != 0))]
|
||||||
pub steam_id: u32,
|
pub steam_id: u32,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,14 +159,15 @@ impl CompanionWithId {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, BinRead)]
|
#[derive(Debug, Clone, BinRead, BinWrite)]
|
||||||
pub struct CompanionWithSymbol {
|
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,
|
pub name: String,
|
||||||
|
|
||||||
#[brw(count = 4)]
|
#[br(count = 4)]
|
||||||
_unknown1: Vec<u8>,
|
_unknown1: Vec<u8>,
|
||||||
|
|
||||||
#[brw(assert((0..=21).contains(&symbol)))]
|
#[br(assert((0..=21).contains(&symbol)))]
|
||||||
pub symbol: u32,
|
pub symbol: u32,
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
use binrw::BinRead;
|
use binrw::{BinRead, BinWrite};
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, BinRead)]
|
#[derive(Debug, Clone, BinRead, BinWrite)]
|
||||||
pub struct Glyphs(#[brw(count = 6)] Vec<LevelGlyphs>);
|
pub struct Glyphs(#[br(count = 6)] Vec<LevelGlyphs>);
|
||||||
|
|
||||||
impl Glyphs {
|
impl Glyphs {
|
||||||
const COUNT: [usize; 6] = [3, 3, 4, 3, 4, 4];
|
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 {
|
pub struct LevelGlyphs {
|
||||||
status_flags: u8,
|
status_flags: u8,
|
||||||
|
|
||||||
#[brw(count = 343)]
|
#[br(count = 343)]
|
||||||
_unused: Vec<u8>,
|
_unused: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,9 +5,9 @@ mod test;
|
|||||||
|
|
||||||
|
|
||||||
use core::fmt;
|
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 chrono::{DateTime, NaiveDateTime, Utc};
|
||||||
|
|
||||||
use crate::companion::{CompanionSymbols, CompanionWithId, Companions};
|
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 {
|
pub enum RobeColor {
|
||||||
Red,
|
Red,
|
||||||
White,
|
White,
|
||||||
@ -47,11 +47,11 @@ impl fmt::Display for RobeColor {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[binrw::binread]
|
#[binrw::binrw]
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
#[brw(little)]
|
#[brw(little)]
|
||||||
pub struct Savefile {
|
pub struct Savefile {
|
||||||
#[brw(count = 8)]
|
#[br(count = 8)]
|
||||||
_unknown0: Vec<u8>,
|
_unknown0: Vec<u8>,
|
||||||
|
|
||||||
pub robe: u32,
|
pub robe: u32,
|
||||||
@ -60,57 +60,70 @@ pub struct Savefile {
|
|||||||
|
|
||||||
pub scarf_length: u32,
|
pub scarf_length: u32,
|
||||||
|
|
||||||
#[brw(count = 4)]
|
#[br(count = 4)]
|
||||||
_unknown1: Vec<u8>,
|
_unknown1: Vec<u8>,
|
||||||
|
|
||||||
#[brw(assert(current_level <= 12))]
|
#[br(assert(current_level <= 12))]
|
||||||
pub current_level: u64,
|
pub current_level: u64,
|
||||||
|
|
||||||
pub total_collected_symbols: u32,
|
pub total_collected_symbols: u32,
|
||||||
|
|
||||||
#[brw(assert(collected_symbols <= 21))]
|
#[br(assert(collected_symbols <= 21))]
|
||||||
pub collected_symbols: u32,
|
pub collected_symbols: u32,
|
||||||
|
|
||||||
pub murals: Murals,
|
pub murals: Murals,
|
||||||
|
|
||||||
#[brw(count = 22)]
|
#[br(count = 22)]
|
||||||
_unknown2: Vec<u8>,
|
_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>,
|
pub last_played: DateTime<Utc>,
|
||||||
|
|
||||||
#[brw(count = 4)]
|
#[br(count = 4)]
|
||||||
_unknown3: Vec<u8>,
|
_unknown3: Vec<u8>,
|
||||||
|
|
||||||
pub journey_count: u64,
|
pub journey_count: u64,
|
||||||
|
|
||||||
pub glyphs: Glyphs,
|
pub glyphs: Glyphs,
|
||||||
|
|
||||||
#[brw(count = 2404)]
|
#[br(count = 2404)]
|
||||||
_unknown4: Vec<u8>,
|
_unknown4: Vec<u8>,
|
||||||
|
|
||||||
pub companion_symbols: CompanionSymbols,
|
pub companion_symbols: CompanionSymbols,
|
||||||
|
|
||||||
pub companions_met: u32,
|
pub companions_met: u32,
|
||||||
|
|
||||||
#[brw(count = 1024)]
|
#[br(count = 1024)]
|
||||||
_unknown6: Vec<u8>,
|
_unknown6: Vec<u8>,
|
||||||
|
|
||||||
pub total_companions_met: u32,
|
pub total_companions_met: u32,
|
||||||
|
|
||||||
#[brw(count = 24)]
|
#[br(count = 24)]
|
||||||
_unknown7: Vec<u8>,
|
_unknown7: Vec<u8>,
|
||||||
|
|
||||||
pub companions: Companions,
|
pub companions: Companions,
|
||||||
|
|
||||||
|
#[br(parse_with = until_eof)]
|
||||||
|
_unknown8: Vec<u8>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Savefile {
|
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
|
where
|
||||||
R: Read + BinReaderExt,
|
R: Read + BinReaderExt,
|
||||||
{
|
{
|
||||||
// TODO: implement error type
|
// 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> {
|
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)
|
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 {
|
pub struct Murals {
|
||||||
status_flags: u16,
|
status_flags: u16,
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user