use super::decoder::{Decoder, DecoderCtx}; use super::entitylist::{EntityEncoding, EntityList}; use super::fstring::FString; use super::raw::Raw; use super::sgd::SGD; use super::ssg::SSG; use super::stream::ReadStream; use super::tag::Tag; use anyhow::anyhow; use anyhow::Result; use byteorder::{LittleEndian, WriteBytesExt}; use deflate::deflate_bytes_zlib; use inflate::inflate_bytes_zlib; use std::io::Cursor; use std::path::Path; pub struct World { pub tag: Tag, pub uncompressed_size: u32, pub data: Raw, pub mission: FString, pub sgd: SGD, pub ssg: SSG, pub ents: EntityList, } impl World { const WORLD_TAG_LEN: usize = 11; const WORLD_HDR_LEN: usize = 0x13; pub fn test(&self) -> Result<()> { let entfile_start: usize = 0x1038; let raw1 = Raw { offset: 0, size: self.ents.get_enc_size(), mem: self.data.mem[entfile_start..entfile_start + self.ents.get_enc_size()].to_vec(), }; raw1.dump(Path::new("entfile1.bin"))?; let raw2 = self.ents.encode(EntityEncoding::World)?; raw2.dump(Path::new("entfile2.bin"))?; Ok(()) } } impl Decoder for World { fn decode(raw: &Raw, offset: usize, size: usize) -> Result { let mut enc = ReadStream::new(raw, offset); let tag: Tag = enc.read(Self::WORLD_TAG_LEN)?; let uncompressed_size = enc.read_u32()?; enc.skip(4); let data = { let inflated = inflate_bytes_zlib(enc.as_bytes(size)?).map_err(|e| anyhow!(e))?; Raw { offset, size, mem: inflated, } }; let mut rd = ReadStream::new(&data, 0); let mission: FString = rd.read(0)?; let sgd: SGD = rd.read(0)?; let ssg: SSG = rd.read(0)?; let ents: EntityList = rd.read_opt(0, EntityEncoding::World)?; Ok(World { tag, uncompressed_size, data, mission, sgd, ssg, ents, }) } fn encode(&self) -> Result { let mut hdr = [0u8; 8]; { let mut wdr = Cursor::new(&mut hdr[..]); let _ = wdr.write_u32::(self.uncompressed_size); let _ = wdr.write_u32::(self.uncompressed_size); } let data = deflate_bytes_zlib(&self.data.mem); Ok(Raw::join( self.data.offset, self.data.size, &mut [ self.tag.encode()?, Raw { offset: Self::WORLD_TAG_LEN, size: 8, mem: hdr.to_vec(), }, Raw { offset: Self::WORLD_HDR_LEN, size: data.len(), mem: data, }, ], )) } fn get_enc_size(&self) -> usize { Self::WORLD_HDR_LEN + self.data.mem.len() } }